diff --git a/404.html b/404.html index faed31c..aad0230 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ -404 Page not found |

Not found

Oops! This page doesn't exist. Try going back to our home page.

\ No newline at end of file +404 Page not found |

Not found

Oops! This page doesn't exist. Try going back to the home page.

\ No newline at end of file diff --git a/categories/index.html b/categories/index.html index ae31d3f..1014120 100644 --- a/categories/index.html +++ b/categories/index.html @@ -1 +1 @@ -Categories |

Categories

\ No newline at end of file +Categories |

Categories

\ No newline at end of file diff --git a/categories/index.xml b/categories/index.xml index 5c64594..5b64699 100644 --- a/categories/index.xml +++ b/categories/index.xml @@ -1 +1 @@ -– Categorieshttps://onshape-public.github.io/categories/Recent content in Categories onHugo -- gohugo.ioen-us \ No newline at end of file +Categories onhttps://onshape-public.github.io/categories/Recent content in Categories onHugoen-us \ No newline at end of file diff --git a/css/prism.css b/css/prism.css index f55c4c6..716b70d 100644 --- a/css/prism.css +++ b/css/prism.css @@ -1,208 +1,4 @@ -/* PrismJS 1.21.0 +/* PrismJS 1.28.0 https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+go+java+markdown+python+scss+sql+toml+yaml&plugins=toolbar+copy-to-clipboard */ -/** - * prism.js default theme for JavaScript, CSS and HTML - * Based on dabblet (http://dabblet.com) - * @author Lea Verou - */ - -code[class*="language-"], -pre[class*="language-"] { - color: black; - background: none; - text-shadow: 0 1px white; - font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - font-size: 1em; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - word-wrap: normal; - line-height: 1.5; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, -code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { - text-shadow: none; - background: #b3d4fc; -} - -pre[class*="language-"]::selection, pre[class*="language-"] ::selection, -code[class*="language-"]::selection, code[class*="language-"] ::selection { - text-shadow: none; - background: #b3d4fc; -} - -@media print { - code[class*="language-"], - pre[class*="language-"] { - text-shadow: none; - } -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: .5em 0; - overflow: auto; -} - -:not(pre) > code[class*="language-"], -pre[class*="language-"] { - background: #f5f2f0; -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: .1em; - border-radius: .3em; - white-space: normal; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: slategray; -} - -.token.punctuation { - color: #999; -} - -.token.namespace { - opacity: .7; -} - -.token.property, -.token.tag, -.token.boolean, -.token.number, -.token.constant, -.token.symbol, -.token.deleted { - color: #905; -} - -.token.selector, -.token.attr-name, -.token.string, -.token.char, -.token.builtin, -.token.inserted { - color: #690; -} - -.token.operator, -.token.entity, -.token.url, -.language-css .token.string, -.style .token.string { - color: #9a6e3a; - /* This background color was intended by the author of this theme. */ - background: hsla(0, 0%, 100%, .5); -} - -.token.atrule, -.token.attr-value, -.token.keyword { - color: #07a; -} - -.token.function, -.token.class-name { - color: #DD4A68; -} - -.token.regex, -.token.important, -.token.variable { - color: #e90; -} - -.token.important, -.token.bold { - font-weight: bold; -} -.token.italic { - font-style: italic; -} - -.token.entity { - cursor: help; -} - -div.code-toolbar { - position: relative; -} - -div.code-toolbar > .toolbar { - position: absolute; - top: .3em; - right: .2em; - transition: opacity 0.3s ease-in-out; - opacity: 0; -} - -div.code-toolbar:hover > .toolbar { - opacity: 1; -} - -/* Separate line b/c rules are thrown out if selector is invalid. - IE11 and old Edge versions don't support :focus-within. */ -div.code-toolbar:focus-within > .toolbar { - opacity: 1; -} - -div.code-toolbar > .toolbar .toolbar-item { - display: inline-block; -} - -div.code-toolbar > .toolbar a { - cursor: pointer; -} - -div.code-toolbar > .toolbar button { - background: none; - border: 0; - color: inherit; - font: inherit; - line-height: normal; - overflow: visible; - padding: 0; - -webkit-user-select: none; /* for button */ - -moz-user-select: none; - -ms-user-select: none; -} - -div.code-toolbar > .toolbar a, -div.code-toolbar > .toolbar button, -div.code-toolbar > .toolbar span { - color: #bbb; - font-size: .8em; - padding: 0 .5em; - background: #f5f2f0; - background: rgba(224, 224, 224, 0.2); - box-shadow: 0 2px 0 0 rgba(0,0,0,0.2); - border-radius: .5em; -} - -div.code-toolbar > .toolbar a:hover, -div.code-toolbar > .toolbar a:focus, -div.code-toolbar > .toolbar button:hover, -div.code-toolbar > .toolbar button:focus, -div.code-toolbar > .toolbar span:hover, -div.code-toolbar > .toolbar span:focus { - color: inherit; - text-decoration: none; -} - +code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help} +div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none} diff --git a/css/shortcodes.css b/css/shortcodes.css deleted file mode 100644 index 0aa1c0f..0000000 --- a/css/shortcodes.css +++ /dev/null @@ -1,2 +0,0 @@ -@import "shortcodes/tabbed-pane.css"; -@import "shortcodes/cards-pane.css"; diff --git a/css/shortcodes/cards-pane.css b/css/shortcodes/cards-pane.css deleted file mode 100644 index 34c8545..0000000 --- a/css/shortcodes/cards-pane.css +++ /dev/null @@ -1,21 +0,0 @@ -.card-deck { - max-width: 83%; -} - -.card { - max-width: 80%; -} - -.card-body.code { - background-color: #f8f9fa; - padding: 0 0 0 1ex; -} - -.card-body pre { - margin: 0; - padding: 0 1rem 1rem 1rem; -} - -.card .highlight { - border: none; -} diff --git a/css/shortcodes/tabbed-pane.css b/css/shortcodes/tabbed-pane.css deleted file mode 100644 index 3016398..0000000 --- a/css/shortcodes/tabbed-pane.css +++ /dev/null @@ -1,18 +0,0 @@ -.td-content .highlight { - margin: 0rem 0 2rem 0; -} - -.tab-content .highlight { - border: none; -} - -.tab-content { - margin: 0rem; - max-width: 80%; -} - -.tab-content pre { - border-left: 1px solid rgba(0, 0, 0, 0.125); - border-right: 1px solid rgba(0, 0, 0, 0.125); - border-bottom: 1px solid rgba(0, 0, 0, 0.125); -} diff --git a/css/swagger-ui.css b/css/swagger-ui.css deleted file mode 100644 index c61e5a8..0000000 --- a/css/swagger-ui.css +++ /dev/null @@ -1,4 +0,0 @@ -.swagger-ui{ - /*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */font-family:sans-serif;color:#3b4151}.swagger-ui html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}.swagger-ui body{margin:0}.swagger-ui article,.swagger-ui aside,.swagger-ui footer,.swagger-ui header,.swagger-ui nav,.swagger-ui section{display:block}.swagger-ui h1{font-size:2em;margin:.67em 0}.swagger-ui figcaption,.swagger-ui figure,.swagger-ui main{display:block}.swagger-ui figure{margin:1em 40px}.swagger-ui hr{box-sizing:content-box;height:0;overflow:visible}.swagger-ui pre{font-family:monospace,monospace;font-size:1em}.swagger-ui a{background-color:transparent;-webkit-text-decoration-skip:objects}.swagger-ui abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.swagger-ui b,.swagger-ui strong{font-weight:inherit;font-weight:bolder}.swagger-ui code,.swagger-ui kbd,.swagger-ui samp{font-family:monospace,monospace;font-size:1em}.swagger-ui dfn{font-style:italic}.swagger-ui mark{background-color:#ff0;color:#000}.swagger-ui small{font-size:80%}.swagger-ui sub,.swagger-ui sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.swagger-ui sub{bottom:-.25em}.swagger-ui sup{top:-.5em}.swagger-ui audio,.swagger-ui video{display:inline-block}.swagger-ui audio:not([controls]){display:none;height:0}.swagger-ui img{border-style:none}.swagger-ui svg:not(:root){overflow:hidden}.swagger-ui button,.swagger-ui input,.swagger-ui optgroup,.swagger-ui select,.swagger-ui textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}.swagger-ui button,.swagger-ui input{overflow:visible}.swagger-ui button,.swagger-ui select{text-transform:none}.swagger-ui [type=reset],.swagger-ui [type=submit],.swagger-ui button,.swagger-ui html [type=button]{-webkit-appearance:button}.swagger-ui [type=button]::-moz-focus-inner,.swagger-ui [type=reset]::-moz-focus-inner,.swagger-ui [type=submit]::-moz-focus-inner,.swagger-ui button::-moz-focus-inner{border-style:none;padding:0}.swagger-ui [type=button]:-moz-focusring,.swagger-ui [type=reset]:-moz-focusring,.swagger-ui [type=submit]:-moz-focusring,.swagger-ui button:-moz-focusring{outline:1px dotted ButtonText}.swagger-ui fieldset{padding:.35em .75em .625em}.swagger-ui legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}.swagger-ui progress{display:inline-block;vertical-align:baseline}.swagger-ui textarea{overflow:auto}.swagger-ui [type=checkbox],.swagger-ui [type=radio]{box-sizing:border-box;padding:0}.swagger-ui [type=number]::-webkit-inner-spin-button,.swagger-ui [type=number]::-webkit-outer-spin-button{height:auto}.swagger-ui [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.swagger-ui [type=search]::-webkit-search-cancel-button,.swagger-ui [type=search]::-webkit-search-decoration{-webkit-appearance:none}.swagger-ui ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.swagger-ui details,.swagger-ui menu{display:block}.swagger-ui summary{display:list-item}.swagger-ui canvas{display:inline-block}.swagger-ui template{display:none}.swagger-ui [hidden]{display:none}.swagger-ui .debug *{outline:1px solid gold}.swagger-ui .debug-white *{outline:1px solid #fff}.swagger-ui .debug-black *{outline:1px solid #000}.swagger-ui .debug-grid{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) repeat 0 0}.swagger-ui .debug-grid-16{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) repeat 0 0}.swagger-ui .debug-grid-8-solid{background:#fff url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) repeat 0 0}.swagger-ui .debug-grid-16-solid{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) repeat 0 0}.swagger-ui .border-box,.swagger-ui a,.swagger-ui article,.swagger-ui body,.swagger-ui code,.swagger-ui dd,.swagger-ui div,.swagger-ui dl,.swagger-ui dt,.swagger-ui fieldset,.swagger-ui footer,.swagger-ui form,.swagger-ui h1,.swagger-ui h2,.swagger-ui h3,.swagger-ui h4,.swagger-ui h5,.swagger-ui h6,.swagger-ui header,.swagger-ui html,.swagger-ui input[type=email],.swagger-ui input[type=number],.swagger-ui input[type=password],.swagger-ui input[type=tel],.swagger-ui input[type=text],.swagger-ui input[type=url],.swagger-ui legend,.swagger-ui li,.swagger-ui main,.swagger-ui ol,.swagger-ui p,.swagger-ui pre,.swagger-ui section,.swagger-ui table,.swagger-ui td,.swagger-ui textarea,.swagger-ui th,.swagger-ui tr,.swagger-ui ul{box-sizing:border-box}.swagger-ui .aspect-ratio{height:0;position:relative}.swagger-ui .aspect-ratio--16x9{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1{padding-bottom:100%}.swagger-ui .aspect-ratio--object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}@media screen and (min-width:30em){.swagger-ui .aspect-ratio-ns{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-ns{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-ns{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-ns{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-ns{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-ns{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-ns{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-ns{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-ns{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-ns{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-ns{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-ns{padding-bottom:100%}.swagger-ui .aspect-ratio--object-ns{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .aspect-ratio-m{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-m{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-m{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-m{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-m{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-m{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-m{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-m{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-m{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-m{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-m{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-m{padding-bottom:100%}.swagger-ui .aspect-ratio--object-m{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}@media screen and (min-width:60em){.swagger-ui .aspect-ratio-l{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-l{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-l{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-l{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-l{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-l{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-l{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-l{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-l{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-l{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-l{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-l{padding-bottom:100%}.swagger-ui .aspect-ratio--object-l{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}}.swagger-ui img{max-width:100%}.swagger-ui .cover{background-size:cover!important}.swagger-ui .contain{background-size:contain!important}@media screen and (min-width:30em){.swagger-ui .cover-ns{background-size:cover!important}.swagger-ui .contain-ns{background-size:contain!important}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .cover-m{background-size:cover!important}.swagger-ui .contain-m{background-size:contain!important}}@media screen and (min-width:60em){.swagger-ui .cover-l{background-size:cover!important}.swagger-ui .contain-l{background-size:contain!important}}.swagger-ui .bg-center{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left{background-repeat:no-repeat;background-position:0}@media screen and (min-width:30em){.swagger-ui .bg-center-ns{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-ns{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-ns{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-ns{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-ns{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .bg-center-m{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-m{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-m{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-m{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-m{background-repeat:no-repeat;background-position:0}}@media screen and (min-width:60em){.swagger-ui .bg-center-l{background-repeat:no-repeat;background-position:50%}.swagger-ui .bg-top-l{background-repeat:no-repeat;background-position:top}.swagger-ui .bg-right-l{background-repeat:no-repeat;background-position:100%}.swagger-ui .bg-bottom-l{background-repeat:no-repeat;background-position:bottom}.swagger-ui .bg-left-l{background-repeat:no-repeat;background-position:0}}.swagger-ui .outline{outline:1px solid}.swagger-ui .outline-transparent{outline:1px solid transparent}.swagger-ui .outline-0{outline:0}@media screen and (min-width:30em){.swagger-ui .outline-ns{outline:1px solid}.swagger-ui .outline-transparent-ns{outline:1px solid transparent}.swagger-ui .outline-0-ns{outline:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .outline-m{outline:1px solid}.swagger-ui .outline-transparent-m{outline:1px solid transparent}.swagger-ui .outline-0-m{outline:0}}@media screen and (min-width:60em){.swagger-ui .outline-l{outline:1px solid}.swagger-ui .outline-transparent-l{outline:1px solid transparent}.swagger-ui .outline-0-l{outline:0}}.swagger-ui .ba{border-style:solid;border-width:1px}.swagger-ui .bt{border-top-style:solid;border-top-width:1px}.swagger-ui .br{border-right-style:solid;border-right-width:1px}.swagger-ui .bb{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl{border-left-style:solid;border-left-width:1px}.swagger-ui .bn{border-style:none;border-width:0}@media screen and (min-width:30em){.swagger-ui .ba-ns{border-style:solid;border-width:1px}.swagger-ui .bt-ns{border-top-style:solid;border-top-width:1px}.swagger-ui .br-ns{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-ns{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-ns{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-ns{border-style:none;border-width:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ba-m{border-style:solid;border-width:1px}.swagger-ui .bt-m{border-top-style:solid;border-top-width:1px}.swagger-ui .br-m{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-m{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-m{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-m{border-style:none;border-width:0}}@media screen and (min-width:60em){.swagger-ui .ba-l{border-style:solid;border-width:1px}.swagger-ui .bt-l{border-top-style:solid;border-top-width:1px}.swagger-ui .br-l{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-l{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-l{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-l{border-style:none;border-width:0}}.swagger-ui .b--black{border-color:#000}.swagger-ui .b--near-black{border-color:#111}.swagger-ui .b--dark-gray{border-color:#333}.swagger-ui .b--mid-gray{border-color:#555}.swagger-ui .b--gray{border-color:#777}.swagger-ui .b--silver{border-color:#999}.swagger-ui .b--light-silver{border-color:#aaa}.swagger-ui .b--moon-gray{border-color:#ccc}.swagger-ui .b--light-gray{border-color:#eee}.swagger-ui .b--near-white{border-color:#f4f4f4}.swagger-ui .b--white{border-color:#fff}.swagger-ui .b--white-90{border-color:hsla(0,0%,100%,.9)}.swagger-ui .b--white-80{border-color:hsla(0,0%,100%,.8)}.swagger-ui .b--white-70{border-color:hsla(0,0%,100%,.7)}.swagger-ui .b--white-60{border-color:hsla(0,0%,100%,.6)}.swagger-ui .b--white-50{border-color:hsla(0,0%,100%,.5)}.swagger-ui .b--white-40{border-color:hsla(0,0%,100%,.4)}.swagger-ui .b--white-30{border-color:hsla(0,0%,100%,.3)}.swagger-ui .b--white-20{border-color:hsla(0,0%,100%,.2)}.swagger-ui .b--white-10{border-color:hsla(0,0%,100%,.1)}.swagger-ui .b--white-05{border-color:hsla(0,0%,100%,.05)}.swagger-ui .b--white-025{border-color:hsla(0,0%,100%,.025)}.swagger-ui .b--white-0125{border-color:hsla(0,0%,100%,.0125)}.swagger-ui .b--black-90{border-color:rgba(0,0,0,.9)}.swagger-ui .b--black-80{border-color:rgba(0,0,0,.8)}.swagger-ui .b--black-70{border-color:rgba(0,0,0,.7)}.swagger-ui .b--black-60{border-color:rgba(0,0,0,.6)}.swagger-ui .b--black-50{border-color:rgba(0,0,0,.5)}.swagger-ui .b--black-40{border-color:rgba(0,0,0,.4)}.swagger-ui .b--black-30{border-color:rgba(0,0,0,.3)}.swagger-ui .b--black-20{border-color:rgba(0,0,0,.2)}.swagger-ui .b--black-10{border-color:rgba(0,0,0,.1)}.swagger-ui .b--black-05{border-color:rgba(0,0,0,.05)}.swagger-ui .b--black-025{border-color:rgba(0,0,0,.025)}.swagger-ui .b--black-0125{border-color:rgba(0,0,0,.0125)}.swagger-ui .b--dark-red{border-color:#e7040f}.swagger-ui .b--red{border-color:#ff4136}.swagger-ui .b--light-red{border-color:#ff725c}.swagger-ui .b--orange{border-color:#ff6300}.swagger-ui .b--gold{border-color:#ffb700}.swagger-ui .b--yellow{border-color:gold}.swagger-ui .b--light-yellow{border-color:#fbf1a9}.swagger-ui .b--purple{border-color:#5e2ca5}.swagger-ui .b--light-purple{border-color:#a463f2}.swagger-ui .b--dark-pink{border-color:#d5008f}.swagger-ui .b--hot-pink{border-color:#ff41b4}.swagger-ui .b--pink{border-color:#ff80cc}.swagger-ui .b--light-pink{border-color:#ffa3d7}.swagger-ui .b--dark-green{border-color:#137752}.swagger-ui .b--green{border-color:#19a974}.swagger-ui .b--light-green{border-color:#9eebcf}.swagger-ui .b--navy{border-color:#001b44}.swagger-ui .b--dark-blue{border-color:#00449e}.swagger-ui .b--blue{border-color:#357edd}.swagger-ui .b--light-blue{border-color:#96ccff}.swagger-ui .b--lightest-blue{border-color:#cdecff}.swagger-ui .b--washed-blue{border-color:#f6fffe}.swagger-ui .b--washed-green{border-color:#e8fdf5}.swagger-ui .b--washed-yellow{border-color:#fffceb}.swagger-ui .b--washed-red{border-color:#ffdfdf}.swagger-ui .b--transparent{border-color:transparent}.swagger-ui .b--inherit{border-color:inherit}.swagger-ui .br0{border-radius:0}.swagger-ui .br1{border-radius:.125rem}.swagger-ui .br2{border-radius:.25rem}.swagger-ui .br3{border-radius:.5rem}.swagger-ui .br4{border-radius:1rem}.swagger-ui .br-100{border-radius:100%}.swagger-ui .br-pill{border-radius:9999px}.swagger-ui .br--bottom{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left{border-top-right-radius:0;border-bottom-right-radius:0}@media screen and (min-width:30em){.swagger-ui .br0-ns{border-radius:0}.swagger-ui .br1-ns{border-radius:.125rem}.swagger-ui .br2-ns{border-radius:.25rem}.swagger-ui .br3-ns{border-radius:.5rem}.swagger-ui .br4-ns{border-radius:1rem}.swagger-ui .br-100-ns{border-radius:100%}.swagger-ui .br-pill-ns{border-radius:9999px}.swagger-ui .br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-ns{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-ns{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-ns{border-top-right-radius:0;border-bottom-right-radius:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .br0-m{border-radius:0}.swagger-ui .br1-m{border-radius:.125rem}.swagger-ui .br2-m{border-radius:.25rem}.swagger-ui .br3-m{border-radius:.5rem}.swagger-ui .br4-m{border-radius:1rem}.swagger-ui .br-100-m{border-radius:100%}.swagger-ui .br-pill-m{border-radius:9999px}.swagger-ui .br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-m{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-m{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-m{border-top-right-radius:0;border-bottom-right-radius:0}}@media screen and (min-width:60em){.swagger-ui .br0-l{border-radius:0}.swagger-ui .br1-l{border-radius:.125rem}.swagger-ui .br2-l{border-radius:.25rem}.swagger-ui .br3-l{border-radius:.5rem}.swagger-ui .br4-l{border-radius:1rem}.swagger-ui .br-100-l{border-radius:100%}.swagger-ui .br-pill-l{border-radius:9999px}.swagger-ui .br--bottom-l{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-l{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-l{border-top-left-radius:0;border-bottom-left-radius:0}.swagger-ui .br--left-l{border-top-right-radius:0;border-bottom-right-radius:0}}.swagger-ui .b--dotted{border-style:dotted}.swagger-ui .b--dashed{border-style:dashed}.swagger-ui .b--solid{border-style:solid}.swagger-ui .b--none{border-style:none}@media screen and (min-width:30em){.swagger-ui .b--dotted-ns{border-style:dotted}.swagger-ui .b--dashed-ns{border-style:dashed}.swagger-ui .b--solid-ns{border-style:solid}.swagger-ui .b--none-ns{border-style:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .b--dotted-m{border-style:dotted}.swagger-ui .b--dashed-m{border-style:dashed}.swagger-ui .b--solid-m{border-style:solid}.swagger-ui .b--none-m{border-style:none}}@media screen and (min-width:60em){.swagger-ui .b--dotted-l{border-style:dotted}.swagger-ui .b--dashed-l{border-style:dashed}.swagger-ui .b--solid-l{border-style:solid}.swagger-ui .b--none-l{border-style:none}}.swagger-ui .bw0{border-width:0}.swagger-ui .bw1{border-width:.125rem}.swagger-ui .bw2{border-width:.25rem}.swagger-ui .bw3{border-width:.5rem}.swagger-ui .bw4{border-width:1rem}.swagger-ui .bw5{border-width:2rem}.swagger-ui .bt-0{border-top-width:0}.swagger-ui .br-0{border-right-width:0}.swagger-ui .bb-0{border-bottom-width:0}.swagger-ui .bl-0{border-left-width:0}@media screen and (min-width:30em){.swagger-ui .bw0-ns{border-width:0}.swagger-ui .bw1-ns{border-width:.125rem}.swagger-ui .bw2-ns{border-width:.25rem}.swagger-ui .bw3-ns{border-width:.5rem}.swagger-ui .bw4-ns{border-width:1rem}.swagger-ui .bw5-ns{border-width:2rem}.swagger-ui .bt-0-ns{border-top-width:0}.swagger-ui .br-0-ns{border-right-width:0}.swagger-ui .bb-0-ns{border-bottom-width:0}.swagger-ui .bl-0-ns{border-left-width:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .bw0-m{border-width:0}.swagger-ui .bw1-m{border-width:.125rem}.swagger-ui .bw2-m{border-width:.25rem}.swagger-ui .bw3-m{border-width:.5rem}.swagger-ui .bw4-m{border-width:1rem}.swagger-ui .bw5-m{border-width:2rem}.swagger-ui .bt-0-m{border-top-width:0}.swagger-ui .br-0-m{border-right-width:0}.swagger-ui .bb-0-m{border-bottom-width:0}.swagger-ui .bl-0-m{border-left-width:0}}@media screen and (min-width:60em){.swagger-ui .bw0-l{border-width:0}.swagger-ui .bw1-l{border-width:.125rem}.swagger-ui .bw2-l{border-width:.25rem}.swagger-ui .bw3-l{border-width:.5rem}.swagger-ui .bw4-l{border-width:1rem}.swagger-ui .bw5-l{border-width:2rem}.swagger-ui .bt-0-l{border-top-width:0}.swagger-ui .br-0-l{border-right-width:0}.swagger-ui .bb-0-l{border-bottom-width:0}.swagger-ui .bl-0-l{border-left-width:0}}.swagger-ui .shadow-1{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}@media screen and (min-width:30em){.swagger-ui .shadow-1-ns{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-ns{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-ns{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-ns{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-ns{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .shadow-1-m{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-m{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-m{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-m{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-m{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}@media screen and (min-width:60em){.swagger-ui .shadow-1-l{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-2-l{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-3-l{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.swagger-ui .shadow-4-l{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.swagger-ui .shadow-5-l{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}}.swagger-ui .pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.swagger-ui .top-0{top:0}.swagger-ui .right-0{right:0}.swagger-ui .bottom-0{bottom:0}.swagger-ui .left-0{left:0}.swagger-ui .top-1{top:1rem}.swagger-ui .right-1{right:1rem}.swagger-ui .bottom-1{bottom:1rem}.swagger-ui .left-1{left:1rem}.swagger-ui .top-2{top:2rem}.swagger-ui .right-2{right:2rem}.swagger-ui .bottom-2{bottom:2rem}.swagger-ui .left-2{left:2rem}.swagger-ui .top--1{top:-1rem}.swagger-ui .right--1{right:-1rem}.swagger-ui .bottom--1{bottom:-1rem}.swagger-ui .left--1{left:-1rem}.swagger-ui .top--2{top:-2rem}.swagger-ui .right--2{right:-2rem}.swagger-ui .bottom--2{bottom:-2rem}.swagger-ui .left--2{left:-2rem}.swagger-ui .absolute--fill{top:0;right:0;bottom:0;left:0}@media screen and (min-width:30em){.swagger-ui .top-0-ns{top:0}.swagger-ui .left-0-ns{left:0}.swagger-ui .right-0-ns{right:0}.swagger-ui .bottom-0-ns{bottom:0}.swagger-ui .top-1-ns{top:1rem}.swagger-ui .left-1-ns{left:1rem}.swagger-ui .right-1-ns{right:1rem}.swagger-ui .bottom-1-ns{bottom:1rem}.swagger-ui .top-2-ns{top:2rem}.swagger-ui .left-2-ns{left:2rem}.swagger-ui .right-2-ns{right:2rem}.swagger-ui .bottom-2-ns{bottom:2rem}.swagger-ui .top--1-ns{top:-1rem}.swagger-ui .right--1-ns{right:-1rem}.swagger-ui .bottom--1-ns{bottom:-1rem}.swagger-ui .left--1-ns{left:-1rem}.swagger-ui .top--2-ns{top:-2rem}.swagger-ui .right--2-ns{right:-2rem}.swagger-ui .bottom--2-ns{bottom:-2rem}.swagger-ui .left--2-ns{left:-2rem}.swagger-ui .absolute--fill-ns{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .top-0-m{top:0}.swagger-ui .left-0-m{left:0}.swagger-ui .right-0-m{right:0}.swagger-ui .bottom-0-m{bottom:0}.swagger-ui .top-1-m{top:1rem}.swagger-ui .left-1-m{left:1rem}.swagger-ui .right-1-m{right:1rem}.swagger-ui .bottom-1-m{bottom:1rem}.swagger-ui .top-2-m{top:2rem}.swagger-ui .left-2-m{left:2rem}.swagger-ui .right-2-m{right:2rem}.swagger-ui .bottom-2-m{bottom:2rem}.swagger-ui .top--1-m{top:-1rem}.swagger-ui .right--1-m{right:-1rem}.swagger-ui .bottom--1-m{bottom:-1rem}.swagger-ui .left--1-m{left:-1rem}.swagger-ui .top--2-m{top:-2rem}.swagger-ui .right--2-m{right:-2rem}.swagger-ui .bottom--2-m{bottom:-2rem}.swagger-ui .left--2-m{left:-2rem}.swagger-ui .absolute--fill-m{top:0;right:0;bottom:0;left:0}}@media screen and (min-width:60em){.swagger-ui .top-0-l{top:0}.swagger-ui .left-0-l{left:0}.swagger-ui .right-0-l{right:0}.swagger-ui .bottom-0-l{bottom:0}.swagger-ui .top-1-l{top:1rem}.swagger-ui .left-1-l{left:1rem}.swagger-ui .right-1-l{right:1rem}.swagger-ui .bottom-1-l{bottom:1rem}.swagger-ui .top-2-l{top:2rem}.swagger-ui .left-2-l{left:2rem}.swagger-ui .right-2-l{right:2rem}.swagger-ui .bottom-2-l{bottom:2rem}.swagger-ui .top--1-l{top:-1rem}.swagger-ui .right--1-l{right:-1rem}.swagger-ui .bottom--1-l{bottom:-1rem}.swagger-ui .left--1-l{left:-1rem}.swagger-ui .top--2-l{top:-2rem}.swagger-ui .right--2-l{right:-2rem}.swagger-ui .bottom--2-l{bottom:-2rem}.swagger-ui .left--2-l{left:-2rem}.swagger-ui .absolute--fill-l{top:0;right:0;bottom:0;left:0}}.swagger-ui .cf:after,.swagger-ui .cf:before{content:" ";display:table}.swagger-ui .cf:after{clear:both}.swagger-ui .cf{*zoom:1}.swagger-ui .cl{clear:left}.swagger-ui .cr{clear:right}.swagger-ui .cb{clear:both}.swagger-ui .cn{clear:none}@media screen and (min-width:30em){.swagger-ui .cl-ns{clear:left}.swagger-ui .cr-ns{clear:right}.swagger-ui .cb-ns{clear:both}.swagger-ui .cn-ns{clear:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .cl-m{clear:left}.swagger-ui .cr-m{clear:right}.swagger-ui .cb-m{clear:both}.swagger-ui .cn-m{clear:none}}@media screen and (min-width:60em){.swagger-ui .cl-l{clear:left}.swagger-ui .cr-l{clear:right}.swagger-ui .cb-l{clear:both}.swagger-ui .cn-l{clear:none}}.swagger-ui .flex{display:flex}.swagger-ui .inline-flex{display:inline-flex}.swagger-ui .flex-auto{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none{flex:none}.swagger-ui .flex-column{flex-direction:column}.swagger-ui .flex-row{flex-direction:row}.swagger-ui .flex-wrap{flex-wrap:wrap}.swagger-ui .flex-nowrap{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse{flex-direction:column-reverse}.swagger-ui .flex-row-reverse{flex-direction:row-reverse}.swagger-ui .items-start{align-items:flex-start}.swagger-ui .items-end{align-items:flex-end}.swagger-ui .items-center{align-items:center}.swagger-ui .items-baseline{align-items:baseline}.swagger-ui .items-stretch{align-items:stretch}.swagger-ui .self-start{align-self:flex-start}.swagger-ui .self-end{align-self:flex-end}.swagger-ui .self-center{align-self:center}.swagger-ui .self-baseline{align-self:baseline}.swagger-ui .self-stretch{align-self:stretch}.swagger-ui .justify-start{justify-content:flex-start}.swagger-ui .justify-end{justify-content:flex-end}.swagger-ui .justify-center{justify-content:center}.swagger-ui .justify-between{justify-content:space-between}.swagger-ui .justify-around{justify-content:space-around}.swagger-ui .content-start{align-content:flex-start}.swagger-ui .content-end{align-content:flex-end}.swagger-ui .content-center{align-content:center}.swagger-ui .content-between{align-content:space-between}.swagger-ui .content-around{align-content:space-around}.swagger-ui .content-stretch{align-content:stretch}.swagger-ui .order-0{order:0}.swagger-ui .order-1{order:1}.swagger-ui .order-2{order:2}.swagger-ui .order-3{order:3}.swagger-ui .order-4{order:4}.swagger-ui .order-5{order:5}.swagger-ui .order-6{order:6}.swagger-ui .order-7{order:7}.swagger-ui .order-8{order:8}.swagger-ui .order-last{order:99999}.swagger-ui .flex-grow-0{flex-grow:0}.swagger-ui .flex-grow-1{flex-grow:1}.swagger-ui .flex-shrink-0{flex-shrink:0}.swagger-ui .flex-shrink-1{flex-shrink:1}@media screen and (min-width:30em){.swagger-ui .flex-ns{display:flex}.swagger-ui .inline-flex-ns{display:inline-flex}.swagger-ui .flex-auto-ns{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-ns{flex:none}.swagger-ui .flex-column-ns{flex-direction:column}.swagger-ui .flex-row-ns{flex-direction:row}.swagger-ui .flex-wrap-ns{flex-wrap:wrap}.swagger-ui .flex-nowrap-ns{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-ns{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-ns{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-ns{flex-direction:row-reverse}.swagger-ui .items-start-ns{align-items:flex-start}.swagger-ui .items-end-ns{align-items:flex-end}.swagger-ui .items-center-ns{align-items:center}.swagger-ui .items-baseline-ns{align-items:baseline}.swagger-ui .items-stretch-ns{align-items:stretch}.swagger-ui .self-start-ns{align-self:flex-start}.swagger-ui .self-end-ns{align-self:flex-end}.swagger-ui .self-center-ns{align-self:center}.swagger-ui .self-baseline-ns{align-self:baseline}.swagger-ui .self-stretch-ns{align-self:stretch}.swagger-ui .justify-start-ns{justify-content:flex-start}.swagger-ui .justify-end-ns{justify-content:flex-end}.swagger-ui .justify-center-ns{justify-content:center}.swagger-ui .justify-between-ns{justify-content:space-between}.swagger-ui .justify-around-ns{justify-content:space-around}.swagger-ui .content-start-ns{align-content:flex-start}.swagger-ui .content-end-ns{align-content:flex-end}.swagger-ui .content-center-ns{align-content:center}.swagger-ui .content-between-ns{align-content:space-between}.swagger-ui .content-around-ns{align-content:space-around}.swagger-ui .content-stretch-ns{align-content:stretch}.swagger-ui .order-0-ns{order:0}.swagger-ui .order-1-ns{order:1}.swagger-ui .order-2-ns{order:2}.swagger-ui .order-3-ns{order:3}.swagger-ui .order-4-ns{order:4}.swagger-ui .order-5-ns{order:5}.swagger-ui .order-6-ns{order:6}.swagger-ui .order-7-ns{order:7}.swagger-ui .order-8-ns{order:8}.swagger-ui .order-last-ns{order:99999}.swagger-ui .flex-grow-0-ns{flex-grow:0}.swagger-ui .flex-grow-1-ns{flex-grow:1}.swagger-ui .flex-shrink-0-ns{flex-shrink:0}.swagger-ui .flex-shrink-1-ns{flex-shrink:1}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .flex-m{display:flex}.swagger-ui .inline-flex-m{display:inline-flex}.swagger-ui .flex-auto-m{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-m{flex:none}.swagger-ui .flex-column-m{flex-direction:column}.swagger-ui .flex-row-m{flex-direction:row}.swagger-ui .flex-wrap-m{flex-wrap:wrap}.swagger-ui .flex-nowrap-m{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-m{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-m{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-m{flex-direction:row-reverse}.swagger-ui .items-start-m{align-items:flex-start}.swagger-ui .items-end-m{align-items:flex-end}.swagger-ui .items-center-m{align-items:center}.swagger-ui .items-baseline-m{align-items:baseline}.swagger-ui .items-stretch-m{align-items:stretch}.swagger-ui .self-start-m{align-self:flex-start}.swagger-ui .self-end-m{align-self:flex-end}.swagger-ui .self-center-m{align-self:center}.swagger-ui .self-baseline-m{align-self:baseline}.swagger-ui .self-stretch-m{align-self:stretch}.swagger-ui .justify-start-m{justify-content:flex-start}.swagger-ui .justify-end-m{justify-content:flex-end}.swagger-ui .justify-center-m{justify-content:center}.swagger-ui .justify-between-m{justify-content:space-between}.swagger-ui .justify-around-m{justify-content:space-around}.swagger-ui .content-start-m{align-content:flex-start}.swagger-ui .content-end-m{align-content:flex-end}.swagger-ui .content-center-m{align-content:center}.swagger-ui .content-between-m{align-content:space-between}.swagger-ui .content-around-m{align-content:space-around}.swagger-ui .content-stretch-m{align-content:stretch}.swagger-ui .order-0-m{order:0}.swagger-ui .order-1-m{order:1}.swagger-ui .order-2-m{order:2}.swagger-ui .order-3-m{order:3}.swagger-ui .order-4-m{order:4}.swagger-ui .order-5-m{order:5}.swagger-ui .order-6-m{order:6}.swagger-ui .order-7-m{order:7}.swagger-ui .order-8-m{order:8}.swagger-ui .order-last-m{order:99999}.swagger-ui .flex-grow-0-m{flex-grow:0}.swagger-ui .flex-grow-1-m{flex-grow:1}.swagger-ui .flex-shrink-0-m{flex-shrink:0}.swagger-ui .flex-shrink-1-m{flex-shrink:1}}@media screen and (min-width:60em){.swagger-ui .flex-l{display:flex}.swagger-ui .inline-flex-l{display:inline-flex}.swagger-ui .flex-auto-l{flex:1 1 auto;min-width:0;min-height:0}.swagger-ui .flex-none-l{flex:none}.swagger-ui .flex-column-l{flex-direction:column}.swagger-ui .flex-row-l{flex-direction:row}.swagger-ui .flex-wrap-l{flex-wrap:wrap}.swagger-ui .flex-nowrap-l{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-l{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-l{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-l{flex-direction:row-reverse}.swagger-ui .items-start-l{align-items:flex-start}.swagger-ui .items-end-l{align-items:flex-end}.swagger-ui .items-center-l{align-items:center}.swagger-ui .items-baseline-l{align-items:baseline}.swagger-ui .items-stretch-l{align-items:stretch}.swagger-ui .self-start-l{align-self:flex-start}.swagger-ui .self-end-l{align-self:flex-end}.swagger-ui .self-center-l{align-self:center}.swagger-ui .self-baseline-l{align-self:baseline}.swagger-ui .self-stretch-l{align-self:stretch}.swagger-ui .justify-start-l{justify-content:flex-start}.swagger-ui .justify-end-l{justify-content:flex-end}.swagger-ui .justify-center-l{justify-content:center}.swagger-ui .justify-between-l{justify-content:space-between}.swagger-ui .justify-around-l{justify-content:space-around}.swagger-ui .content-start-l{align-content:flex-start}.swagger-ui .content-end-l{align-content:flex-end}.swagger-ui .content-center-l{align-content:center}.swagger-ui .content-between-l{align-content:space-between}.swagger-ui .content-around-l{align-content:space-around}.swagger-ui .content-stretch-l{align-content:stretch}.swagger-ui .order-0-l{order:0}.swagger-ui .order-1-l{order:1}.swagger-ui .order-2-l{order:2}.swagger-ui .order-3-l{order:3}.swagger-ui .order-4-l{order:4}.swagger-ui .order-5-l{order:5}.swagger-ui .order-6-l{order:6}.swagger-ui .order-7-l{order:7}.swagger-ui .order-8-l{order:8}.swagger-ui .order-last-l{order:99999}.swagger-ui .flex-grow-0-l{flex-grow:0}.swagger-ui .flex-grow-1-l{flex-grow:1}.swagger-ui .flex-shrink-0-l{flex-shrink:0}.swagger-ui .flex-shrink-1-l{flex-shrink:1}}.swagger-ui .dn{display:none}.swagger-ui .di{display:inline}.swagger-ui .db{display:block}.swagger-ui .dib{display:inline-block}.swagger-ui .dit{display:inline-table}.swagger-ui .dt{display:table}.swagger-ui .dtc{display:table-cell}.swagger-ui .dt-row{display:table-row}.swagger-ui .dt-row-group{display:table-row-group}.swagger-ui .dt-column{display:table-column}.swagger-ui .dt-column-group{display:table-column-group}.swagger-ui .dt--fixed{table-layout:fixed;width:100%}@media screen and (min-width:30em){.swagger-ui .dn-ns{display:none}.swagger-ui .di-ns{display:inline}.swagger-ui .db-ns{display:block}.swagger-ui .dib-ns{display:inline-block}.swagger-ui .dit-ns{display:inline-table}.swagger-ui .dt-ns{display:table}.swagger-ui .dtc-ns{display:table-cell}.swagger-ui .dt-row-ns{display:table-row}.swagger-ui .dt-row-group-ns{display:table-row-group}.swagger-ui .dt-column-ns{display:table-column}.swagger-ui .dt-column-group-ns{display:table-column-group}.swagger-ui .dt--fixed-ns{table-layout:fixed;width:100%}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .dn-m{display:none}.swagger-ui .di-m{display:inline}.swagger-ui .db-m{display:block}.swagger-ui .dib-m{display:inline-block}.swagger-ui .dit-m{display:inline-table}.swagger-ui .dt-m{display:table}.swagger-ui .dtc-m{display:table-cell}.swagger-ui .dt-row-m{display:table-row}.swagger-ui .dt-row-group-m{display:table-row-group}.swagger-ui .dt-column-m{display:table-column}.swagger-ui .dt-column-group-m{display:table-column-group}.swagger-ui .dt--fixed-m{table-layout:fixed;width:100%}}@media screen and (min-width:60em){.swagger-ui .dn-l{display:none}.swagger-ui .di-l{display:inline}.swagger-ui .db-l{display:block}.swagger-ui .dib-l{display:inline-block}.swagger-ui .dit-l{display:inline-table}.swagger-ui .dt-l{display:table}.swagger-ui .dtc-l{display:table-cell}.swagger-ui .dt-row-l{display:table-row}.swagger-ui .dt-row-group-l{display:table-row-group}.swagger-ui .dt-column-l{display:table-column}.swagger-ui .dt-column-group-l{display:table-column-group}.swagger-ui .dt--fixed-l{table-layout:fixed;width:100%}}.swagger-ui .fl{float:left;_display:inline}.swagger-ui .fr{float:right;_display:inline}.swagger-ui .fn{float:none}@media screen and (min-width:30em){.swagger-ui .fl-ns{float:left;_display:inline}.swagger-ui .fr-ns{float:right;_display:inline}.swagger-ui .fn-ns{float:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .fl-m{float:left;_display:inline}.swagger-ui .fr-m{float:right;_display:inline}.swagger-ui .fn-m{float:none}}@media screen and (min-width:60em){.swagger-ui .fl-l{float:left;_display:inline}.swagger-ui .fr-l{float:right;_display:inline}.swagger-ui .fn-l{float:none}}.swagger-ui .sans-serif{font-family:-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica,helvetica neue,ubuntu,roboto,noto,segoe ui,arial,sans-serif}.swagger-ui .serif{font-family:georgia,serif}.swagger-ui .system-sans-serif{font-family:sans-serif}.swagger-ui .system-serif{font-family:serif}.swagger-ui .code,.swagger-ui code{font-family:Consolas,monaco,monospace}.swagger-ui .courier{font-family:Courier Next,courier,monospace}.swagger-ui .helvetica{font-family:helvetica neue,helvetica,sans-serif}.swagger-ui .avenir{font-family:avenir next,avenir,sans-serif}.swagger-ui .athelas{font-family:athelas,georgia,serif}.swagger-ui .georgia{font-family:georgia,serif}.swagger-ui .times{font-family:times,serif}.swagger-ui .bodoni{font-family:Bodoni MT,serif}.swagger-ui .calisto{font-family:Calisto MT,serif}.swagger-ui .garamond{font-family:garamond,serif}.swagger-ui .baskerville{font-family:baskerville,serif}.swagger-ui .i{font-style:italic}.swagger-ui .fs-normal{font-style:normal}@media screen and (min-width:30em){.swagger-ui .i-ns{font-style:italic}.swagger-ui .fs-normal-ns{font-style:normal}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .i-m{font-style:italic}.swagger-ui .fs-normal-m{font-style:normal}}@media screen and (min-width:60em){.swagger-ui .i-l{font-style:italic}.swagger-ui .fs-normal-l{font-style:normal}}.swagger-ui .normal{font-weight:400}.swagger-ui .b{font-weight:700}.swagger-ui .fw1{font-weight:100}.swagger-ui .fw2{font-weight:200}.swagger-ui .fw3{font-weight:300}.swagger-ui .fw4{font-weight:400}.swagger-ui .fw5{font-weight:500}.swagger-ui .fw6{font-weight:600}.swagger-ui .fw7{font-weight:700}.swagger-ui .fw8{font-weight:800}.swagger-ui .fw9{font-weight:900}@media screen and (min-width:30em){.swagger-ui .normal-ns{font-weight:400}.swagger-ui .b-ns{font-weight:700}.swagger-ui .fw1-ns{font-weight:100}.swagger-ui .fw2-ns{font-weight:200}.swagger-ui .fw3-ns{font-weight:300}.swagger-ui .fw4-ns{font-weight:400}.swagger-ui .fw5-ns{font-weight:500}.swagger-ui .fw6-ns{font-weight:600}.swagger-ui .fw7-ns{font-weight:700}.swagger-ui .fw8-ns{font-weight:800}.swagger-ui .fw9-ns{font-weight:900}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .normal-m{font-weight:400}.swagger-ui .b-m{font-weight:700}.swagger-ui .fw1-m{font-weight:100}.swagger-ui .fw2-m{font-weight:200}.swagger-ui .fw3-m{font-weight:300}.swagger-ui .fw4-m{font-weight:400}.swagger-ui .fw5-m{font-weight:500}.swagger-ui .fw6-m{font-weight:600}.swagger-ui .fw7-m{font-weight:700}.swagger-ui .fw8-m{font-weight:800}.swagger-ui .fw9-m{font-weight:900}}@media screen and (min-width:60em){.swagger-ui .normal-l{font-weight:400}.swagger-ui .b-l{font-weight:700}.swagger-ui .fw1-l{font-weight:100}.swagger-ui .fw2-l{font-weight:200}.swagger-ui .fw3-l{font-weight:300}.swagger-ui .fw4-l{font-weight:400}.swagger-ui .fw5-l{font-weight:500}.swagger-ui .fw6-l{font-weight:600}.swagger-ui .fw7-l{font-weight:700}.swagger-ui .fw8-l{font-weight:800}.swagger-ui .fw9-l{font-weight:900}}.swagger-ui .input-reset{-webkit-appearance:none;-moz-appearance:none}.swagger-ui .button-reset::-moz-focus-inner,.swagger-ui .input-reset::-moz-focus-inner{border:0;padding:0}.swagger-ui .h1{height:1rem}.swagger-ui .h2{height:2rem}.swagger-ui .h3{height:4rem}.swagger-ui .h4{height:8rem}.swagger-ui .h5{height:16rem}.swagger-ui .h-25{height:25%}.swagger-ui .h-50{height:50%}.swagger-ui .h-75{height:75%}.swagger-ui .h-100{height:100%}.swagger-ui .min-h-100{min-height:100%}.swagger-ui .vh-25{height:25vh}.swagger-ui .vh-50{height:50vh}.swagger-ui .vh-75{height:75vh}.swagger-ui .vh-100{height:100vh}.swagger-ui .min-vh-100{min-height:100vh}.swagger-ui .h-auto{height:auto}.swagger-ui .h-inherit{height:inherit}@media screen and (min-width:30em){.swagger-ui .h1-ns{height:1rem}.swagger-ui .h2-ns{height:2rem}.swagger-ui .h3-ns{height:4rem}.swagger-ui .h4-ns{height:8rem}.swagger-ui .h5-ns{height:16rem}.swagger-ui .h-25-ns{height:25%}.swagger-ui .h-50-ns{height:50%}.swagger-ui .h-75-ns{height:75%}.swagger-ui .h-100-ns{height:100%}.swagger-ui .min-h-100-ns{min-height:100%}.swagger-ui .vh-25-ns{height:25vh}.swagger-ui .vh-50-ns{height:50vh}.swagger-ui .vh-75-ns{height:75vh}.swagger-ui .vh-100-ns{height:100vh}.swagger-ui .min-vh-100-ns{min-height:100vh}.swagger-ui .h-auto-ns{height:auto}.swagger-ui .h-inherit-ns{height:inherit}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .h1-m{height:1rem}.swagger-ui .h2-m{height:2rem}.swagger-ui .h3-m{height:4rem}.swagger-ui .h4-m{height:8rem}.swagger-ui .h5-m{height:16rem}.swagger-ui .h-25-m{height:25%}.swagger-ui .h-50-m{height:50%}.swagger-ui .h-75-m{height:75%}.swagger-ui .h-100-m{height:100%}.swagger-ui .min-h-100-m{min-height:100%}.swagger-ui .vh-25-m{height:25vh}.swagger-ui .vh-50-m{height:50vh}.swagger-ui .vh-75-m{height:75vh}.swagger-ui .vh-100-m{height:100vh}.swagger-ui .min-vh-100-m{min-height:100vh}.swagger-ui .h-auto-m{height:auto}.swagger-ui .h-inherit-m{height:inherit}}@media screen and (min-width:60em){.swagger-ui .h1-l{height:1rem}.swagger-ui .h2-l{height:2rem}.swagger-ui .h3-l{height:4rem}.swagger-ui .h4-l{height:8rem}.swagger-ui .h5-l{height:16rem}.swagger-ui .h-25-l{height:25%}.swagger-ui .h-50-l{height:50%}.swagger-ui .h-75-l{height:75%}.swagger-ui .h-100-l{height:100%}.swagger-ui .min-h-100-l{min-height:100%}.swagger-ui .vh-25-l{height:25vh}.swagger-ui .vh-50-l{height:50vh}.swagger-ui .vh-75-l{height:75vh}.swagger-ui .vh-100-l{height:100vh}.swagger-ui .min-vh-100-l{min-height:100vh}.swagger-ui .h-auto-l{height:auto}.swagger-ui .h-inherit-l{height:inherit}}.swagger-ui .tracked{letter-spacing:.1em}.swagger-ui .tracked-tight{letter-spacing:-.05em}.swagger-ui .tracked-mega{letter-spacing:.25em}@media screen and (min-width:30em){.swagger-ui .tracked-ns{letter-spacing:.1em}.swagger-ui .tracked-tight-ns{letter-spacing:-.05em}.swagger-ui .tracked-mega-ns{letter-spacing:.25em}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .tracked-m{letter-spacing:.1em}.swagger-ui .tracked-tight-m{letter-spacing:-.05em}.swagger-ui .tracked-mega-m{letter-spacing:.25em}}@media screen and (min-width:60em){.swagger-ui .tracked-l{letter-spacing:.1em}.swagger-ui .tracked-tight-l{letter-spacing:-.05em}.swagger-ui .tracked-mega-l{letter-spacing:.25em}}.swagger-ui .lh-solid{line-height:1}.swagger-ui .lh-title{line-height:1.25}.swagger-ui .lh-copy{line-height:1.5}@media screen and (min-width:30em){.swagger-ui .lh-solid-ns{line-height:1}.swagger-ui .lh-title-ns{line-height:1.25}.swagger-ui .lh-copy-ns{line-height:1.5}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .lh-solid-m{line-height:1}.swagger-ui .lh-title-m{line-height:1.25}.swagger-ui .lh-copy-m{line-height:1.5}}@media screen and (min-width:60em){.swagger-ui .lh-solid-l{line-height:1}.swagger-ui .lh-title-l{line-height:1.25}.swagger-ui .lh-copy-l{line-height:1.5}}.swagger-ui .link{text-decoration:none}.swagger-ui .link,.swagger-ui .link:link,.swagger-ui .link:visited{transition:color .15s ease-in}.swagger-ui .link:hover{transition:color .15s ease-in}.swagger-ui .link:active{transition:color .15s ease-in}.swagger-ui .link:focus{transition:color .15s ease-in;outline:1px dotted currentColor}.swagger-ui .list{list-style-type:none}.swagger-ui .mw-100{max-width:100%}.swagger-ui .mw1{max-width:1rem}.swagger-ui .mw2{max-width:2rem}.swagger-ui .mw3{max-width:4rem}.swagger-ui .mw4{max-width:8rem}.swagger-ui .mw5{max-width:16rem}.swagger-ui .mw6{max-width:32rem}.swagger-ui .mw7{max-width:48rem}.swagger-ui .mw8{max-width:64rem}.swagger-ui .mw9{max-width:96rem}.swagger-ui .mw-none{max-width:none}@media screen and (min-width:30em){.swagger-ui .mw-100-ns{max-width:100%}.swagger-ui .mw1-ns{max-width:1rem}.swagger-ui .mw2-ns{max-width:2rem}.swagger-ui .mw3-ns{max-width:4rem}.swagger-ui .mw4-ns{max-width:8rem}.swagger-ui .mw5-ns{max-width:16rem}.swagger-ui .mw6-ns{max-width:32rem}.swagger-ui .mw7-ns{max-width:48rem}.swagger-ui .mw8-ns{max-width:64rem}.swagger-ui .mw9-ns{max-width:96rem}.swagger-ui .mw-none-ns{max-width:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .mw-100-m{max-width:100%}.swagger-ui .mw1-m{max-width:1rem}.swagger-ui .mw2-m{max-width:2rem}.swagger-ui .mw3-m{max-width:4rem}.swagger-ui .mw4-m{max-width:8rem}.swagger-ui .mw5-m{max-width:16rem}.swagger-ui .mw6-m{max-width:32rem}.swagger-ui .mw7-m{max-width:48rem}.swagger-ui .mw8-m{max-width:64rem}.swagger-ui .mw9-m{max-width:96rem}.swagger-ui .mw-none-m{max-width:none}}@media screen and (min-width:60em){.swagger-ui .mw-100-l{max-width:100%}.swagger-ui .mw1-l{max-width:1rem}.swagger-ui .mw2-l{max-width:2rem}.swagger-ui .mw3-l{max-width:4rem}.swagger-ui .mw4-l{max-width:8rem}.swagger-ui .mw5-l{max-width:16rem}.swagger-ui .mw6-l{max-width:32rem}.swagger-ui .mw7-l{max-width:48rem}.swagger-ui .mw8-l{max-width:64rem}.swagger-ui .mw9-l{max-width:96rem}.swagger-ui .mw-none-l{max-width:none}}.swagger-ui .w1{width:1rem}.swagger-ui .w2{width:2rem}.swagger-ui .w3{width:4rem}.swagger-ui .w4{width:8rem}.swagger-ui .w5{width:16rem}.swagger-ui .w-10{width:10%}.swagger-ui .w-20{width:20%}.swagger-ui .w-25{width:25%}.swagger-ui .w-30{width:30%}.swagger-ui .w-33{width:33%}.swagger-ui .w-34{width:34%}.swagger-ui .w-40{width:40%}.swagger-ui .w-50{width:50%}.swagger-ui .w-60{width:60%}.swagger-ui .w-70{width:70%}.swagger-ui .w-75{width:75%}.swagger-ui .w-80{width:80%}.swagger-ui .w-90{width:90%}.swagger-ui .w-100{width:100%}.swagger-ui .w-third{width:33.33333%}.swagger-ui .w-two-thirds{width:66.66667%}.swagger-ui .w-auto{width:auto}@media screen and (min-width:30em){.swagger-ui .w1-ns{width:1rem}.swagger-ui .w2-ns{width:2rem}.swagger-ui .w3-ns{width:4rem}.swagger-ui .w4-ns{width:8rem}.swagger-ui .w5-ns{width:16rem}.swagger-ui .w-10-ns{width:10%}.swagger-ui .w-20-ns{width:20%}.swagger-ui .w-25-ns{width:25%}.swagger-ui .w-30-ns{width:30%}.swagger-ui .w-33-ns{width:33%}.swagger-ui .w-34-ns{width:34%}.swagger-ui .w-40-ns{width:40%}.swagger-ui .w-50-ns{width:50%}.swagger-ui .w-60-ns{width:60%}.swagger-ui .w-70-ns{width:70%}.swagger-ui .w-75-ns{width:75%}.swagger-ui .w-80-ns{width:80%}.swagger-ui .w-90-ns{width:90%}.swagger-ui .w-100-ns{width:100%}.swagger-ui .w-third-ns{width:33.33333%}.swagger-ui .w-two-thirds-ns{width:66.66667%}.swagger-ui .w-auto-ns{width:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .w1-m{width:1rem}.swagger-ui .w2-m{width:2rem}.swagger-ui .w3-m{width:4rem}.swagger-ui .w4-m{width:8rem}.swagger-ui .w5-m{width:16rem}.swagger-ui .w-10-m{width:10%}.swagger-ui .w-20-m{width:20%}.swagger-ui .w-25-m{width:25%}.swagger-ui .w-30-m{width:30%}.swagger-ui .w-33-m{width:33%}.swagger-ui .w-34-m{width:34%}.swagger-ui .w-40-m{width:40%}.swagger-ui .w-50-m{width:50%}.swagger-ui .w-60-m{width:60%}.swagger-ui .w-70-m{width:70%}.swagger-ui .w-75-m{width:75%}.swagger-ui .w-80-m{width:80%}.swagger-ui .w-90-m{width:90%}.swagger-ui .w-100-m{width:100%}.swagger-ui .w-third-m{width:33.33333%}.swagger-ui .w-two-thirds-m{width:66.66667%}.swagger-ui .w-auto-m{width:auto}}@media screen and (min-width:60em){.swagger-ui .w1-l{width:1rem}.swagger-ui .w2-l{width:2rem}.swagger-ui .w3-l{width:4rem}.swagger-ui .w4-l{width:8rem}.swagger-ui .w5-l{width:16rem}.swagger-ui .w-10-l{width:10%}.swagger-ui .w-20-l{width:20%}.swagger-ui .w-25-l{width:25%}.swagger-ui .w-30-l{width:30%}.swagger-ui .w-33-l{width:33%}.swagger-ui .w-34-l{width:34%}.swagger-ui .w-40-l{width:40%}.swagger-ui .w-50-l{width:50%}.swagger-ui .w-60-l{width:60%}.swagger-ui .w-70-l{width:70%}.swagger-ui .w-75-l{width:75%}.swagger-ui .w-80-l{width:80%}.swagger-ui .w-90-l{width:90%}.swagger-ui .w-100-l{width:100%}.swagger-ui .w-third-l{width:33.33333%}.swagger-ui .w-two-thirds-l{width:66.66667%}.swagger-ui .w-auto-l{width:auto}}.swagger-ui .overflow-visible{overflow:visible}.swagger-ui .overflow-hidden{overflow:hidden}.swagger-ui .overflow-scroll{overflow:scroll}.swagger-ui .overflow-auto{overflow:auto}.swagger-ui .overflow-x-visible{overflow-x:visible}.swagger-ui .overflow-x-hidden{overflow-x:hidden}.swagger-ui .overflow-x-scroll{overflow-x:scroll}.swagger-ui .overflow-x-auto{overflow-x:auto}.swagger-ui .overflow-y-visible{overflow-y:visible}.swagger-ui .overflow-y-hidden{overflow-y:hidden}.swagger-ui .overflow-y-scroll{overflow-y:scroll}.swagger-ui .overflow-y-auto{overflow-y:auto}@media screen and (min-width:30em){.swagger-ui .overflow-visible-ns{overflow:visible}.swagger-ui .overflow-hidden-ns{overflow:hidden}.swagger-ui .overflow-scroll-ns{overflow:scroll}.swagger-ui .overflow-auto-ns{overflow:auto}.swagger-ui .overflow-x-visible-ns{overflow-x:visible}.swagger-ui .overflow-x-hidden-ns{overflow-x:hidden}.swagger-ui .overflow-x-scroll-ns{overflow-x:scroll}.swagger-ui .overflow-x-auto-ns{overflow-x:auto}.swagger-ui .overflow-y-visible-ns{overflow-y:visible}.swagger-ui .overflow-y-hidden-ns{overflow-y:hidden}.swagger-ui .overflow-y-scroll-ns{overflow-y:scroll}.swagger-ui .overflow-y-auto-ns{overflow-y:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .overflow-visible-m{overflow:visible}.swagger-ui .overflow-hidden-m{overflow:hidden}.swagger-ui .overflow-scroll-m{overflow:scroll}.swagger-ui .overflow-auto-m{overflow:auto}.swagger-ui .overflow-x-visible-m{overflow-x:visible}.swagger-ui .overflow-x-hidden-m{overflow-x:hidden}.swagger-ui .overflow-x-scroll-m{overflow-x:scroll}.swagger-ui .overflow-x-auto-m{overflow-x:auto}.swagger-ui .overflow-y-visible-m{overflow-y:visible}.swagger-ui .overflow-y-hidden-m{overflow-y:hidden}.swagger-ui .overflow-y-scroll-m{overflow-y:scroll}.swagger-ui .overflow-y-auto-m{overflow-y:auto}}@media screen and (min-width:60em){.swagger-ui .overflow-visible-l{overflow:visible}.swagger-ui .overflow-hidden-l{overflow:hidden}.swagger-ui .overflow-scroll-l{overflow:scroll}.swagger-ui .overflow-auto-l{overflow:auto}.swagger-ui .overflow-x-visible-l{overflow-x:visible}.swagger-ui .overflow-x-hidden-l{overflow-x:hidden}.swagger-ui .overflow-x-scroll-l{overflow-x:scroll}.swagger-ui .overflow-x-auto-l{overflow-x:auto}.swagger-ui .overflow-y-visible-l{overflow-y:visible}.swagger-ui .overflow-y-hidden-l{overflow-y:hidden}.swagger-ui .overflow-y-scroll-l{overflow-y:scroll}.swagger-ui .overflow-y-auto-l{overflow-y:auto}}.swagger-ui .static{position:static}.swagger-ui .relative{position:relative}.swagger-ui .absolute{position:absolute}.swagger-ui .fixed{position:fixed}@media screen and (min-width:30em){.swagger-ui .static-ns{position:static}.swagger-ui .relative-ns{position:relative}.swagger-ui .absolute-ns{position:absolute}.swagger-ui .fixed-ns{position:fixed}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .static-m{position:static}.swagger-ui .relative-m{position:relative}.swagger-ui .absolute-m{position:absolute}.swagger-ui .fixed-m{position:fixed}}@media screen and (min-width:60em){.swagger-ui .static-l{position:static}.swagger-ui .relative-l{position:relative}.swagger-ui .absolute-l{position:absolute}.swagger-ui .fixed-l{position:fixed}}.swagger-ui .o-100{opacity:1}.swagger-ui .o-90{opacity:.9}.swagger-ui .o-80{opacity:.8}.swagger-ui .o-70{opacity:.7}.swagger-ui .o-60{opacity:.6}.swagger-ui .o-50{opacity:.5}.swagger-ui .o-40{opacity:.4}.swagger-ui .o-30{opacity:.3}.swagger-ui .o-20{opacity:.2}.swagger-ui .o-10{opacity:.1}.swagger-ui .o-05{opacity:.05}.swagger-ui .o-025{opacity:.025}.swagger-ui .o-0{opacity:0}.swagger-ui .rotate-45{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315{-webkit-transform:rotate(315deg);transform:rotate(315deg)}@media screen and (min-width:30em){.swagger-ui .rotate-45-ns{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-ns{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-ns{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-ns{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-ns{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-ns{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-ns{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .rotate-45-m{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-m{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-m{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-m{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-m{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-m{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-m{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}@media screen and (min-width:60em){.swagger-ui .rotate-45-l{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.swagger-ui .rotate-90-l{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.swagger-ui .rotate-135-l{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.swagger-ui .rotate-180-l{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.swagger-ui .rotate-225-l{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.swagger-ui .rotate-270-l{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.swagger-ui .rotate-315-l{-webkit-transform:rotate(315deg);transform:rotate(315deg)}}.swagger-ui .black-90{color:rgba(0,0,0,.9)}.swagger-ui .black-80{color:rgba(0,0,0,.8)}.swagger-ui .black-70{color:rgba(0,0,0,.7)}.swagger-ui .black-60{color:rgba(0,0,0,.6)}.swagger-ui .black-50{color:rgba(0,0,0,.5)}.swagger-ui .black-40{color:rgba(0,0,0,.4)}.swagger-ui .black-30{color:rgba(0,0,0,.3)}.swagger-ui .black-20{color:rgba(0,0,0,.2)}.swagger-ui .black-10{color:rgba(0,0,0,.1)}.swagger-ui .black-05{color:rgba(0,0,0,.05)}.swagger-ui .white-90{color:hsla(0,0%,100%,.9)}.swagger-ui .white-80{color:hsla(0,0%,100%,.8)}.swagger-ui .white-70{color:hsla(0,0%,100%,.7)}.swagger-ui .white-60{color:hsla(0,0%,100%,.6)}.swagger-ui .white-50{color:hsla(0,0%,100%,.5)}.swagger-ui .white-40{color:hsla(0,0%,100%,.4)}.swagger-ui .white-30{color:hsla(0,0%,100%,.3)}.swagger-ui .white-20{color:hsla(0,0%,100%,.2)}.swagger-ui .white-10{color:hsla(0,0%,100%,.1)}.swagger-ui .black{color:#000}.swagger-ui .near-black{color:#111}.swagger-ui .dark-gray{color:#333}.swagger-ui .mid-gray{color:#555}.swagger-ui .gray{color:#777}.swagger-ui .silver{color:#999}.swagger-ui .light-silver{color:#aaa}.swagger-ui .moon-gray{color:#ccc}.swagger-ui .light-gray{color:#eee}.swagger-ui .near-white{color:#f4f4f4}.swagger-ui .white{color:#fff}.swagger-ui .dark-red{color:#e7040f}.swagger-ui .red{color:#ff4136}.swagger-ui .light-red{color:#ff725c}.swagger-ui .orange{color:#ff6300}.swagger-ui .gold{color:#ffb700}.swagger-ui .yellow{color:gold}.swagger-ui .light-yellow{color:#fbf1a9}.swagger-ui .purple{color:#5e2ca5}.swagger-ui .light-purple{color:#a463f2}.swagger-ui .dark-pink{color:#d5008f}.swagger-ui .hot-pink{color:#ff41b4}.swagger-ui .pink{color:#ff80cc}.swagger-ui .light-pink{color:#ffa3d7}.swagger-ui .dark-green{color:#137752}.swagger-ui .green{color:#19a974}.swagger-ui .light-green{color:#9eebcf}.swagger-ui .navy{color:#001b44}.swagger-ui .dark-blue{color:#00449e}.swagger-ui .blue{color:#357edd}.swagger-ui .light-blue{color:#96ccff}.swagger-ui .lightest-blue{color:#cdecff}.swagger-ui .washed-blue{color:#f6fffe}.swagger-ui .washed-green{color:#e8fdf5}.swagger-ui .washed-yellow{color:#fffceb}.swagger-ui .washed-red{color:#ffdfdf}.swagger-ui .color-inherit{color:inherit}.swagger-ui .bg-black-90{background-color:rgba(0,0,0,.9)}.swagger-ui .bg-black-80{background-color:rgba(0,0,0,.8)}.swagger-ui .bg-black-70{background-color:rgba(0,0,0,.7)}.swagger-ui .bg-black-60{background-color:rgba(0,0,0,.6)}.swagger-ui .bg-black-50{background-color:rgba(0,0,0,.5)}.swagger-ui .bg-black-40{background-color:rgba(0,0,0,.4)}.swagger-ui .bg-black-30{background-color:rgba(0,0,0,.3)}.swagger-ui .bg-black-20{background-color:rgba(0,0,0,.2)}.swagger-ui .bg-black-10{background-color:rgba(0,0,0,.1)}.swagger-ui .bg-black-05{background-color:rgba(0,0,0,.05)}.swagger-ui .bg-white-90{background-color:hsla(0,0%,100%,.9)}.swagger-ui .bg-white-80{background-color:hsla(0,0%,100%,.8)}.swagger-ui .bg-white-70{background-color:hsla(0,0%,100%,.7)}.swagger-ui .bg-white-60{background-color:hsla(0,0%,100%,.6)}.swagger-ui .bg-white-50{background-color:hsla(0,0%,100%,.5)}.swagger-ui .bg-white-40{background-color:hsla(0,0%,100%,.4)}.swagger-ui .bg-white-30{background-color:hsla(0,0%,100%,.3)}.swagger-ui .bg-white-20{background-color:hsla(0,0%,100%,.2)}.swagger-ui .bg-white-10{background-color:hsla(0,0%,100%,.1)}.swagger-ui .bg-black{background-color:#000}.swagger-ui .bg-near-black{background-color:#111}.swagger-ui .bg-dark-gray{background-color:#333}.swagger-ui .bg-mid-gray{background-color:#555}.swagger-ui .bg-gray{background-color:#777}.swagger-ui .bg-silver{background-color:#999}.swagger-ui .bg-light-silver{background-color:#aaa}.swagger-ui .bg-moon-gray{background-color:#ccc}.swagger-ui .bg-light-gray{background-color:#eee}.swagger-ui .bg-near-white{background-color:#f4f4f4}.swagger-ui .bg-white{background-color:#fff}.swagger-ui .bg-transparent{background-color:transparent}.swagger-ui .bg-dark-red{background-color:#e7040f}.swagger-ui .bg-red{background-color:#ff4136}.swagger-ui .bg-light-red{background-color:#ff725c}.swagger-ui .bg-orange{background-color:#ff6300}.swagger-ui .bg-gold{background-color:#ffb700}.swagger-ui .bg-yellow{background-color:gold}.swagger-ui .bg-light-yellow{background-color:#fbf1a9}.swagger-ui .bg-purple{background-color:#5e2ca5}.swagger-ui .bg-light-purple{background-color:#a463f2}.swagger-ui .bg-dark-pink{background-color:#d5008f}.swagger-ui .bg-hot-pink{background-color:#ff41b4}.swagger-ui .bg-pink{background-color:#ff80cc}.swagger-ui .bg-light-pink{background-color:#ffa3d7}.swagger-ui .bg-dark-green{background-color:#137752}.swagger-ui .bg-green{background-color:#19a974}.swagger-ui .bg-light-green{background-color:#9eebcf}.swagger-ui .bg-navy{background-color:#001b44}.swagger-ui .bg-dark-blue{background-color:#00449e}.swagger-ui .bg-blue{background-color:#357edd}.swagger-ui .bg-light-blue{background-color:#96ccff}.swagger-ui .bg-lightest-blue{background-color:#cdecff}.swagger-ui .bg-washed-blue{background-color:#f6fffe}.swagger-ui .bg-washed-green{background-color:#e8fdf5}.swagger-ui .bg-washed-yellow{background-color:#fffceb}.swagger-ui .bg-washed-red{background-color:#ffdfdf}.swagger-ui .bg-inherit{background-color:inherit}.swagger-ui .hover-black:focus,.swagger-ui .hover-black:hover{color:#000}.swagger-ui .hover-near-black:focus,.swagger-ui .hover-near-black:hover{color:#111}.swagger-ui .hover-dark-gray:focus,.swagger-ui .hover-dark-gray:hover{color:#333}.swagger-ui .hover-mid-gray:focus,.swagger-ui .hover-mid-gray:hover{color:#555}.swagger-ui .hover-gray:focus,.swagger-ui .hover-gray:hover{color:#777}.swagger-ui .hover-silver:focus,.swagger-ui .hover-silver:hover{color:#999}.swagger-ui .hover-light-silver:focus,.swagger-ui .hover-light-silver:hover{color:#aaa}.swagger-ui .hover-moon-gray:focus,.swagger-ui .hover-moon-gray:hover{color:#ccc}.swagger-ui .hover-light-gray:focus,.swagger-ui .hover-light-gray:hover{color:#eee}.swagger-ui .hover-near-white:focus,.swagger-ui .hover-near-white:hover{color:#f4f4f4}.swagger-ui .hover-white:focus,.swagger-ui .hover-white:hover{color:#fff}.swagger-ui .hover-black-90:focus,.swagger-ui .hover-black-90:hover{color:rgba(0,0,0,.9)}.swagger-ui .hover-black-80:focus,.swagger-ui .hover-black-80:hover{color:rgba(0,0,0,.8)}.swagger-ui .hover-black-70:focus,.swagger-ui .hover-black-70:hover{color:rgba(0,0,0,.7)}.swagger-ui .hover-black-60:focus,.swagger-ui .hover-black-60:hover{color:rgba(0,0,0,.6)}.swagger-ui .hover-black-50:focus,.swagger-ui .hover-black-50:hover{color:rgba(0,0,0,.5)}.swagger-ui .hover-black-40:focus,.swagger-ui .hover-black-40:hover{color:rgba(0,0,0,.4)}.swagger-ui .hover-black-30:focus,.swagger-ui .hover-black-30:hover{color:rgba(0,0,0,.3)}.swagger-ui .hover-black-20:focus,.swagger-ui .hover-black-20:hover{color:rgba(0,0,0,.2)}.swagger-ui .hover-black-10:focus,.swagger-ui .hover-black-10:hover{color:rgba(0,0,0,.1)}.swagger-ui .hover-white-90:focus,.swagger-ui .hover-white-90:hover{color:hsla(0,0%,100%,.9)}.swagger-ui .hover-white-80:focus,.swagger-ui .hover-white-80:hover{color:hsla(0,0%,100%,.8)}.swagger-ui .hover-white-70:focus,.swagger-ui .hover-white-70:hover{color:hsla(0,0%,100%,.7)}.swagger-ui .hover-white-60:focus,.swagger-ui .hover-white-60:hover{color:hsla(0,0%,100%,.6)}.swagger-ui .hover-white-50:focus,.swagger-ui .hover-white-50:hover{color:hsla(0,0%,100%,.5)}.swagger-ui .hover-white-40:focus,.swagger-ui .hover-white-40:hover{color:hsla(0,0%,100%,.4)}.swagger-ui .hover-white-30:focus,.swagger-ui .hover-white-30:hover{color:hsla(0,0%,100%,.3)}.swagger-ui .hover-white-20:focus,.swagger-ui .hover-white-20:hover{color:hsla(0,0%,100%,.2)}.swagger-ui .hover-white-10:focus,.swagger-ui .hover-white-10:hover{color:hsla(0,0%,100%,.1)}.swagger-ui .hover-inherit:focus,.swagger-ui .hover-inherit:hover{color:inherit}.swagger-ui .hover-bg-black:focus,.swagger-ui .hover-bg-black:hover{background-color:#000}.swagger-ui .hover-bg-near-black:focus,.swagger-ui .hover-bg-near-black:hover{background-color:#111}.swagger-ui .hover-bg-dark-gray:focus,.swagger-ui .hover-bg-dark-gray:hover{background-color:#333}.swagger-ui .hover-bg-mid-gray:focus,.swagger-ui .hover-bg-mid-gray:hover{background-color:#555}.swagger-ui .hover-bg-gray:focus,.swagger-ui .hover-bg-gray:hover{background-color:#777}.swagger-ui .hover-bg-silver:focus,.swagger-ui .hover-bg-silver:hover{background-color:#999}.swagger-ui .hover-bg-light-silver:focus,.swagger-ui .hover-bg-light-silver:hover{background-color:#aaa}.swagger-ui .hover-bg-moon-gray:focus,.swagger-ui .hover-bg-moon-gray:hover{background-color:#ccc}.swagger-ui .hover-bg-light-gray:focus,.swagger-ui .hover-bg-light-gray:hover{background-color:#eee}.swagger-ui .hover-bg-near-white:focus,.swagger-ui .hover-bg-near-white:hover{background-color:#f4f4f4}.swagger-ui .hover-bg-white:focus,.swagger-ui .hover-bg-white:hover{background-color:#fff}.swagger-ui .hover-bg-transparent:focus,.swagger-ui .hover-bg-transparent:hover{background-color:transparent}.swagger-ui .hover-bg-black-90:focus,.swagger-ui .hover-bg-black-90:hover{background-color:rgba(0,0,0,.9)}.swagger-ui .hover-bg-black-80:focus,.swagger-ui .hover-bg-black-80:hover{background-color:rgba(0,0,0,.8)}.swagger-ui .hover-bg-black-70:focus,.swagger-ui .hover-bg-black-70:hover{background-color:rgba(0,0,0,.7)}.swagger-ui .hover-bg-black-60:focus,.swagger-ui .hover-bg-black-60:hover{background-color:rgba(0,0,0,.6)}.swagger-ui .hover-bg-black-50:focus,.swagger-ui .hover-bg-black-50:hover{background-color:rgba(0,0,0,.5)}.swagger-ui .hover-bg-black-40:focus,.swagger-ui .hover-bg-black-40:hover{background-color:rgba(0,0,0,.4)}.swagger-ui .hover-bg-black-30:focus,.swagger-ui .hover-bg-black-30:hover{background-color:rgba(0,0,0,.3)}.swagger-ui .hover-bg-black-20:focus,.swagger-ui .hover-bg-black-20:hover{background-color:rgba(0,0,0,.2)}.swagger-ui .hover-bg-black-10:focus,.swagger-ui .hover-bg-black-10:hover{background-color:rgba(0,0,0,.1)}.swagger-ui .hover-bg-white-90:focus,.swagger-ui .hover-bg-white-90:hover{background-color:hsla(0,0%,100%,.9)}.swagger-ui .hover-bg-white-80:focus,.swagger-ui .hover-bg-white-80:hover{background-color:hsla(0,0%,100%,.8)}.swagger-ui .hover-bg-white-70:focus,.swagger-ui .hover-bg-white-70:hover{background-color:hsla(0,0%,100%,.7)}.swagger-ui .hover-bg-white-60:focus,.swagger-ui .hover-bg-white-60:hover{background-color:hsla(0,0%,100%,.6)}.swagger-ui .hover-bg-white-50:focus,.swagger-ui .hover-bg-white-50:hover{background-color:hsla(0,0%,100%,.5)}.swagger-ui .hover-bg-white-40:focus,.swagger-ui .hover-bg-white-40:hover{background-color:hsla(0,0%,100%,.4)}.swagger-ui .hover-bg-white-30:focus,.swagger-ui .hover-bg-white-30:hover{background-color:hsla(0,0%,100%,.3)}.swagger-ui .hover-bg-white-20:focus,.swagger-ui .hover-bg-white-20:hover{background-color:hsla(0,0%,100%,.2)}.swagger-ui .hover-bg-white-10:focus,.swagger-ui .hover-bg-white-10:hover{background-color:hsla(0,0%,100%,.1)}.swagger-ui .hover-dark-red:focus,.swagger-ui .hover-dark-red:hover{color:#e7040f}.swagger-ui .hover-red:focus,.swagger-ui .hover-red:hover{color:#ff4136}.swagger-ui .hover-light-red:focus,.swagger-ui .hover-light-red:hover{color:#ff725c}.swagger-ui .hover-orange:focus,.swagger-ui .hover-orange:hover{color:#ff6300}.swagger-ui .hover-gold:focus,.swagger-ui .hover-gold:hover{color:#ffb700}.swagger-ui .hover-yellow:focus,.swagger-ui .hover-yellow:hover{color:gold}.swagger-ui .hover-light-yellow:focus,.swagger-ui .hover-light-yellow:hover{color:#fbf1a9}.swagger-ui .hover-purple:focus,.swagger-ui .hover-purple:hover{color:#5e2ca5}.swagger-ui .hover-light-purple:focus,.swagger-ui .hover-light-purple:hover{color:#a463f2}.swagger-ui .hover-dark-pink:focus,.swagger-ui .hover-dark-pink:hover{color:#d5008f}.swagger-ui .hover-hot-pink:focus,.swagger-ui .hover-hot-pink:hover{color:#ff41b4}.swagger-ui .hover-pink:focus,.swagger-ui .hover-pink:hover{color:#ff80cc}.swagger-ui .hover-light-pink:focus,.swagger-ui .hover-light-pink:hover{color:#ffa3d7}.swagger-ui .hover-dark-green:focus,.swagger-ui .hover-dark-green:hover{color:#137752}.swagger-ui .hover-green:focus,.swagger-ui .hover-green:hover{color:#19a974}.swagger-ui .hover-light-green:focus,.swagger-ui .hover-light-green:hover{color:#9eebcf}.swagger-ui .hover-navy:focus,.swagger-ui .hover-navy:hover{color:#001b44}.swagger-ui .hover-dark-blue:focus,.swagger-ui .hover-dark-blue:hover{color:#00449e}.swagger-ui .hover-blue:focus,.swagger-ui .hover-blue:hover{color:#357edd}.swagger-ui .hover-light-blue:focus,.swagger-ui .hover-light-blue:hover{color:#96ccff}.swagger-ui .hover-lightest-blue:focus,.swagger-ui .hover-lightest-blue:hover{color:#cdecff}.swagger-ui .hover-washed-blue:focus,.swagger-ui .hover-washed-blue:hover{color:#f6fffe}.swagger-ui .hover-washed-green:focus,.swagger-ui .hover-washed-green:hover{color:#e8fdf5}.swagger-ui .hover-washed-yellow:focus,.swagger-ui .hover-washed-yellow:hover{color:#fffceb}.swagger-ui .hover-washed-red:focus,.swagger-ui .hover-washed-red:hover{color:#ffdfdf}.swagger-ui .hover-bg-dark-red:focus,.swagger-ui .hover-bg-dark-red:hover{background-color:#e7040f}.swagger-ui .hover-bg-red:focus,.swagger-ui .hover-bg-red:hover{background-color:#ff4136}.swagger-ui .hover-bg-light-red:focus,.swagger-ui .hover-bg-light-red:hover{background-color:#ff725c}.swagger-ui .hover-bg-orange:focus,.swagger-ui .hover-bg-orange:hover{background-color:#ff6300}.swagger-ui .hover-bg-gold:focus,.swagger-ui .hover-bg-gold:hover{background-color:#ffb700}.swagger-ui .hover-bg-yellow:focus,.swagger-ui .hover-bg-yellow:hover{background-color:gold}.swagger-ui .hover-bg-light-yellow:focus,.swagger-ui .hover-bg-light-yellow:hover{background-color:#fbf1a9}.swagger-ui .hover-bg-purple:focus,.swagger-ui .hover-bg-purple:hover{background-color:#5e2ca5}.swagger-ui .hover-bg-light-purple:focus,.swagger-ui .hover-bg-light-purple:hover{background-color:#a463f2}.swagger-ui .hover-bg-dark-pink:focus,.swagger-ui .hover-bg-dark-pink:hover{background-color:#d5008f}.swagger-ui .hover-bg-hot-pink:focus,.swagger-ui .hover-bg-hot-pink:hover{background-color:#ff41b4}.swagger-ui .hover-bg-pink:focus,.swagger-ui .hover-bg-pink:hover{background-color:#ff80cc}.swagger-ui .hover-bg-light-pink:focus,.swagger-ui .hover-bg-light-pink:hover{background-color:#ffa3d7}.swagger-ui .hover-bg-dark-green:focus,.swagger-ui .hover-bg-dark-green:hover{background-color:#137752}.swagger-ui .hover-bg-green:focus,.swagger-ui .hover-bg-green:hover{background-color:#19a974}.swagger-ui .hover-bg-light-green:focus,.swagger-ui .hover-bg-light-green:hover{background-color:#9eebcf}.swagger-ui .hover-bg-navy:focus,.swagger-ui .hover-bg-navy:hover{background-color:#001b44}.swagger-ui .hover-bg-dark-blue:focus,.swagger-ui .hover-bg-dark-blue:hover{background-color:#00449e}.swagger-ui .hover-bg-blue:focus,.swagger-ui .hover-bg-blue:hover{background-color:#357edd}.swagger-ui .hover-bg-light-blue:focus,.swagger-ui .hover-bg-light-blue:hover{background-color:#96ccff}.swagger-ui .hover-bg-lightest-blue:focus,.swagger-ui .hover-bg-lightest-blue:hover{background-color:#cdecff}.swagger-ui .hover-bg-washed-blue:focus,.swagger-ui .hover-bg-washed-blue:hover{background-color:#f6fffe}.swagger-ui .hover-bg-washed-green:focus,.swagger-ui .hover-bg-washed-green:hover{background-color:#e8fdf5}.swagger-ui .hover-bg-washed-yellow:focus,.swagger-ui .hover-bg-washed-yellow:hover{background-color:#fffceb}.swagger-ui .hover-bg-washed-red:focus,.swagger-ui .hover-bg-washed-red:hover{background-color:#ffdfdf}.swagger-ui .hover-bg-inherit:focus,.swagger-ui .hover-bg-inherit:hover{background-color:inherit}.swagger-ui .pa0{padding:0}.swagger-ui .pa1{padding:.25rem}.swagger-ui .pa2{padding:.5rem}.swagger-ui .pa3{padding:1rem}.swagger-ui .pa4{padding:2rem}.swagger-ui .pa5{padding:4rem}.swagger-ui .pa6{padding:8rem}.swagger-ui .pa7{padding:16rem}.swagger-ui .pl0{padding-left:0}.swagger-ui .pl1{padding-left:.25rem}.swagger-ui .pl2{padding-left:.5rem}.swagger-ui .pl3{padding-left:1rem}.swagger-ui .pl4{padding-left:2rem}.swagger-ui .pl5{padding-left:4rem}.swagger-ui .pl6{padding-left:8rem}.swagger-ui .pl7{padding-left:16rem}.swagger-ui .pr0{padding-right:0}.swagger-ui .pr1{padding-right:.25rem}.swagger-ui .pr2{padding-right:.5rem}.swagger-ui .pr3{padding-right:1rem}.swagger-ui .pr4{padding-right:2rem}.swagger-ui .pr5{padding-right:4rem}.swagger-ui .pr6{padding-right:8rem}.swagger-ui .pr7{padding-right:16rem}.swagger-ui .pb0{padding-bottom:0}.swagger-ui .pb1{padding-bottom:.25rem}.swagger-ui .pb2{padding-bottom:.5rem}.swagger-ui .pb3{padding-bottom:1rem}.swagger-ui .pb4{padding-bottom:2rem}.swagger-ui .pb5{padding-bottom:4rem}.swagger-ui .pb6{padding-bottom:8rem}.swagger-ui .pb7{padding-bottom:16rem}.swagger-ui .pt0{padding-top:0}.swagger-ui .pt1{padding-top:.25rem}.swagger-ui .pt2{padding-top:.5rem}.swagger-ui .pt3{padding-top:1rem}.swagger-ui .pt4{padding-top:2rem}.swagger-ui .pt5{padding-top:4rem}.swagger-ui .pt6{padding-top:8rem}.swagger-ui .pt7{padding-top:16rem}.swagger-ui .pv0{padding-top:0;padding-bottom:0}.swagger-ui .pv1{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0{padding-left:0;padding-right:0}.swagger-ui .ph1{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0{margin:0}.swagger-ui .ma1{margin:.25rem}.swagger-ui .ma2{margin:.5rem}.swagger-ui .ma3{margin:1rem}.swagger-ui .ma4{margin:2rem}.swagger-ui .ma5{margin:4rem}.swagger-ui .ma6{margin:8rem}.swagger-ui .ma7{margin:16rem}.swagger-ui .ml0{margin-left:0}.swagger-ui .ml1{margin-left:.25rem}.swagger-ui .ml2{margin-left:.5rem}.swagger-ui .ml3{margin-left:1rem}.swagger-ui .ml4{margin-left:2rem}.swagger-ui .ml5{margin-left:4rem}.swagger-ui .ml6{margin-left:8rem}.swagger-ui .ml7{margin-left:16rem}.swagger-ui .mr0{margin-right:0}.swagger-ui .mr1{margin-right:.25rem}.swagger-ui .mr2{margin-right:.5rem}.swagger-ui .mr3{margin-right:1rem}.swagger-ui .mr4{margin-right:2rem}.swagger-ui .mr5{margin-right:4rem}.swagger-ui .mr6{margin-right:8rem}.swagger-ui .mr7{margin-right:16rem}.swagger-ui .mb0{margin-bottom:0}.swagger-ui .mb1{margin-bottom:.25rem}.swagger-ui .mb2{margin-bottom:.5rem}.swagger-ui .mb3{margin-bottom:1rem}.swagger-ui .mb4{margin-bottom:2rem}.swagger-ui .mb5{margin-bottom:4rem}.swagger-ui .mb6{margin-bottom:8rem}.swagger-ui .mb7{margin-bottom:16rem}.swagger-ui .mt0{margin-top:0}.swagger-ui .mt1{margin-top:.25rem}.swagger-ui .mt2{margin-top:.5rem}.swagger-ui .mt3{margin-top:1rem}.swagger-ui .mt4{margin-top:2rem}.swagger-ui .mt5{margin-top:4rem}.swagger-ui .mt6{margin-top:8rem}.swagger-ui .mt7{margin-top:16rem}.swagger-ui .mv0{margin-top:0;margin-bottom:0}.swagger-ui .mv1{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0{margin-left:0;margin-right:0}.swagger-ui .mh1{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7{margin-left:16rem;margin-right:16rem}@media screen and (min-width:30em){.swagger-ui .pa0-ns{padding:0}.swagger-ui .pa1-ns{padding:.25rem}.swagger-ui .pa2-ns{padding:.5rem}.swagger-ui .pa3-ns{padding:1rem}.swagger-ui .pa4-ns{padding:2rem}.swagger-ui .pa5-ns{padding:4rem}.swagger-ui .pa6-ns{padding:8rem}.swagger-ui .pa7-ns{padding:16rem}.swagger-ui .pl0-ns{padding-left:0}.swagger-ui .pl1-ns{padding-left:.25rem}.swagger-ui .pl2-ns{padding-left:.5rem}.swagger-ui .pl3-ns{padding-left:1rem}.swagger-ui .pl4-ns{padding-left:2rem}.swagger-ui .pl5-ns{padding-left:4rem}.swagger-ui .pl6-ns{padding-left:8rem}.swagger-ui .pl7-ns{padding-left:16rem}.swagger-ui .pr0-ns{padding-right:0}.swagger-ui .pr1-ns{padding-right:.25rem}.swagger-ui .pr2-ns{padding-right:.5rem}.swagger-ui .pr3-ns{padding-right:1rem}.swagger-ui .pr4-ns{padding-right:2rem}.swagger-ui .pr5-ns{padding-right:4rem}.swagger-ui .pr6-ns{padding-right:8rem}.swagger-ui .pr7-ns{padding-right:16rem}.swagger-ui .pb0-ns{padding-bottom:0}.swagger-ui .pb1-ns{padding-bottom:.25rem}.swagger-ui .pb2-ns{padding-bottom:.5rem}.swagger-ui .pb3-ns{padding-bottom:1rem}.swagger-ui .pb4-ns{padding-bottom:2rem}.swagger-ui .pb5-ns{padding-bottom:4rem}.swagger-ui .pb6-ns{padding-bottom:8rem}.swagger-ui .pb7-ns{padding-bottom:16rem}.swagger-ui .pt0-ns{padding-top:0}.swagger-ui .pt1-ns{padding-top:.25rem}.swagger-ui .pt2-ns{padding-top:.5rem}.swagger-ui .pt3-ns{padding-top:1rem}.swagger-ui .pt4-ns{padding-top:2rem}.swagger-ui .pt5-ns{padding-top:4rem}.swagger-ui .pt6-ns{padding-top:8rem}.swagger-ui .pt7-ns{padding-top:16rem}.swagger-ui .pv0-ns{padding-top:0;padding-bottom:0}.swagger-ui .pv1-ns{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-ns{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-ns{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-ns{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-ns{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-ns{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-ns{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-ns{padding-left:0;padding-right:0}.swagger-ui .ph1-ns{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-ns{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-ns{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-ns{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-ns{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-ns{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-ns{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-ns{margin:0}.swagger-ui .ma1-ns{margin:.25rem}.swagger-ui .ma2-ns{margin:.5rem}.swagger-ui .ma3-ns{margin:1rem}.swagger-ui .ma4-ns{margin:2rem}.swagger-ui .ma5-ns{margin:4rem}.swagger-ui .ma6-ns{margin:8rem}.swagger-ui .ma7-ns{margin:16rem}.swagger-ui .ml0-ns{margin-left:0}.swagger-ui .ml1-ns{margin-left:.25rem}.swagger-ui .ml2-ns{margin-left:.5rem}.swagger-ui .ml3-ns{margin-left:1rem}.swagger-ui .ml4-ns{margin-left:2rem}.swagger-ui .ml5-ns{margin-left:4rem}.swagger-ui .ml6-ns{margin-left:8rem}.swagger-ui .ml7-ns{margin-left:16rem}.swagger-ui .mr0-ns{margin-right:0}.swagger-ui .mr1-ns{margin-right:.25rem}.swagger-ui .mr2-ns{margin-right:.5rem}.swagger-ui .mr3-ns{margin-right:1rem}.swagger-ui .mr4-ns{margin-right:2rem}.swagger-ui .mr5-ns{margin-right:4rem}.swagger-ui .mr6-ns{margin-right:8rem}.swagger-ui .mr7-ns{margin-right:16rem}.swagger-ui .mb0-ns{margin-bottom:0}.swagger-ui .mb1-ns{margin-bottom:.25rem}.swagger-ui .mb2-ns{margin-bottom:.5rem}.swagger-ui .mb3-ns{margin-bottom:1rem}.swagger-ui .mb4-ns{margin-bottom:2rem}.swagger-ui .mb5-ns{margin-bottom:4rem}.swagger-ui .mb6-ns{margin-bottom:8rem}.swagger-ui .mb7-ns{margin-bottom:16rem}.swagger-ui .mt0-ns{margin-top:0}.swagger-ui .mt1-ns{margin-top:.25rem}.swagger-ui .mt2-ns{margin-top:.5rem}.swagger-ui .mt3-ns{margin-top:1rem}.swagger-ui .mt4-ns{margin-top:2rem}.swagger-ui .mt5-ns{margin-top:4rem}.swagger-ui .mt6-ns{margin-top:8rem}.swagger-ui .mt7-ns{margin-top:16rem}.swagger-ui .mv0-ns{margin-top:0;margin-bottom:0}.swagger-ui .mv1-ns{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-ns{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-ns{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-ns{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-ns{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-ns{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-ns{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-ns{margin-left:0;margin-right:0}.swagger-ui .mh1-ns{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-ns{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-ns{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-ns{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-ns{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-ns{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-ns{margin-left:16rem;margin-right:16rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .pa0-m{padding:0}.swagger-ui .pa1-m{padding:.25rem}.swagger-ui .pa2-m{padding:.5rem}.swagger-ui .pa3-m{padding:1rem}.swagger-ui .pa4-m{padding:2rem}.swagger-ui .pa5-m{padding:4rem}.swagger-ui .pa6-m{padding:8rem}.swagger-ui .pa7-m{padding:16rem}.swagger-ui .pl0-m{padding-left:0}.swagger-ui .pl1-m{padding-left:.25rem}.swagger-ui .pl2-m{padding-left:.5rem}.swagger-ui .pl3-m{padding-left:1rem}.swagger-ui .pl4-m{padding-left:2rem}.swagger-ui .pl5-m{padding-left:4rem}.swagger-ui .pl6-m{padding-left:8rem}.swagger-ui .pl7-m{padding-left:16rem}.swagger-ui .pr0-m{padding-right:0}.swagger-ui .pr1-m{padding-right:.25rem}.swagger-ui .pr2-m{padding-right:.5rem}.swagger-ui .pr3-m{padding-right:1rem}.swagger-ui .pr4-m{padding-right:2rem}.swagger-ui .pr5-m{padding-right:4rem}.swagger-ui .pr6-m{padding-right:8rem}.swagger-ui .pr7-m{padding-right:16rem}.swagger-ui .pb0-m{padding-bottom:0}.swagger-ui .pb1-m{padding-bottom:.25rem}.swagger-ui .pb2-m{padding-bottom:.5rem}.swagger-ui .pb3-m{padding-bottom:1rem}.swagger-ui .pb4-m{padding-bottom:2rem}.swagger-ui .pb5-m{padding-bottom:4rem}.swagger-ui .pb6-m{padding-bottom:8rem}.swagger-ui .pb7-m{padding-bottom:16rem}.swagger-ui .pt0-m{padding-top:0}.swagger-ui .pt1-m{padding-top:.25rem}.swagger-ui .pt2-m{padding-top:.5rem}.swagger-ui .pt3-m{padding-top:1rem}.swagger-ui .pt4-m{padding-top:2rem}.swagger-ui .pt5-m{padding-top:4rem}.swagger-ui .pt6-m{padding-top:8rem}.swagger-ui .pt7-m{padding-top:16rem}.swagger-ui .pv0-m{padding-top:0;padding-bottom:0}.swagger-ui .pv1-m{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-m{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-m{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-m{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-m{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-m{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-m{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-m{padding-left:0;padding-right:0}.swagger-ui .ph1-m{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-m{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-m{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-m{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-m{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-m{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-m{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-m{margin:0}.swagger-ui .ma1-m{margin:.25rem}.swagger-ui .ma2-m{margin:.5rem}.swagger-ui .ma3-m{margin:1rem}.swagger-ui .ma4-m{margin:2rem}.swagger-ui .ma5-m{margin:4rem}.swagger-ui .ma6-m{margin:8rem}.swagger-ui .ma7-m{margin:16rem}.swagger-ui .ml0-m{margin-left:0}.swagger-ui .ml1-m{margin-left:.25rem}.swagger-ui .ml2-m{margin-left:.5rem}.swagger-ui .ml3-m{margin-left:1rem}.swagger-ui .ml4-m{margin-left:2rem}.swagger-ui .ml5-m{margin-left:4rem}.swagger-ui .ml6-m{margin-left:8rem}.swagger-ui .ml7-m{margin-left:16rem}.swagger-ui .mr0-m{margin-right:0}.swagger-ui .mr1-m{margin-right:.25rem}.swagger-ui .mr2-m{margin-right:.5rem}.swagger-ui .mr3-m{margin-right:1rem}.swagger-ui .mr4-m{margin-right:2rem}.swagger-ui .mr5-m{margin-right:4rem}.swagger-ui .mr6-m{margin-right:8rem}.swagger-ui .mr7-m{margin-right:16rem}.swagger-ui .mb0-m{margin-bottom:0}.swagger-ui .mb1-m{margin-bottom:.25rem}.swagger-ui .mb2-m{margin-bottom:.5rem}.swagger-ui .mb3-m{margin-bottom:1rem}.swagger-ui .mb4-m{margin-bottom:2rem}.swagger-ui .mb5-m{margin-bottom:4rem}.swagger-ui .mb6-m{margin-bottom:8rem}.swagger-ui .mb7-m{margin-bottom:16rem}.swagger-ui .mt0-m{margin-top:0}.swagger-ui .mt1-m{margin-top:.25rem}.swagger-ui .mt2-m{margin-top:.5rem}.swagger-ui .mt3-m{margin-top:1rem}.swagger-ui .mt4-m{margin-top:2rem}.swagger-ui .mt5-m{margin-top:4rem}.swagger-ui .mt6-m{margin-top:8rem}.swagger-ui .mt7-m{margin-top:16rem}.swagger-ui .mv0-m{margin-top:0;margin-bottom:0}.swagger-ui .mv1-m{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-m{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-m{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-m{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-m{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-m{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-m{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-m{margin-left:0;margin-right:0}.swagger-ui .mh1-m{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-m{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-m{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-m{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-m{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-m{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-m{margin-left:16rem;margin-right:16rem}}@media screen and (min-width:60em){.swagger-ui .pa0-l{padding:0}.swagger-ui .pa1-l{padding:.25rem}.swagger-ui .pa2-l{padding:.5rem}.swagger-ui .pa3-l{padding:1rem}.swagger-ui .pa4-l{padding:2rem}.swagger-ui .pa5-l{padding:4rem}.swagger-ui .pa6-l{padding:8rem}.swagger-ui .pa7-l{padding:16rem}.swagger-ui .pl0-l{padding-left:0}.swagger-ui .pl1-l{padding-left:.25rem}.swagger-ui .pl2-l{padding-left:.5rem}.swagger-ui .pl3-l{padding-left:1rem}.swagger-ui .pl4-l{padding-left:2rem}.swagger-ui .pl5-l{padding-left:4rem}.swagger-ui .pl6-l{padding-left:8rem}.swagger-ui .pl7-l{padding-left:16rem}.swagger-ui .pr0-l{padding-right:0}.swagger-ui .pr1-l{padding-right:.25rem}.swagger-ui .pr2-l{padding-right:.5rem}.swagger-ui .pr3-l{padding-right:1rem}.swagger-ui .pr4-l{padding-right:2rem}.swagger-ui .pr5-l{padding-right:4rem}.swagger-ui .pr6-l{padding-right:8rem}.swagger-ui .pr7-l{padding-right:16rem}.swagger-ui .pb0-l{padding-bottom:0}.swagger-ui .pb1-l{padding-bottom:.25rem}.swagger-ui .pb2-l{padding-bottom:.5rem}.swagger-ui .pb3-l{padding-bottom:1rem}.swagger-ui .pb4-l{padding-bottom:2rem}.swagger-ui .pb5-l{padding-bottom:4rem}.swagger-ui .pb6-l{padding-bottom:8rem}.swagger-ui .pb7-l{padding-bottom:16rem}.swagger-ui .pt0-l{padding-top:0}.swagger-ui .pt1-l{padding-top:.25rem}.swagger-ui .pt2-l{padding-top:.5rem}.swagger-ui .pt3-l{padding-top:1rem}.swagger-ui .pt4-l{padding-top:2rem}.swagger-ui .pt5-l{padding-top:4rem}.swagger-ui .pt6-l{padding-top:8rem}.swagger-ui .pt7-l{padding-top:16rem}.swagger-ui .pv0-l{padding-top:0;padding-bottom:0}.swagger-ui .pv1-l{padding-top:.25rem;padding-bottom:.25rem}.swagger-ui .pv2-l{padding-top:.5rem;padding-bottom:.5rem}.swagger-ui .pv3-l{padding-top:1rem;padding-bottom:1rem}.swagger-ui .pv4-l{padding-top:2rem;padding-bottom:2rem}.swagger-ui .pv5-l{padding-top:4rem;padding-bottom:4rem}.swagger-ui .pv6-l{padding-top:8rem;padding-bottom:8rem}.swagger-ui .pv7-l{padding-top:16rem;padding-bottom:16rem}.swagger-ui .ph0-l{padding-left:0;padding-right:0}.swagger-ui .ph1-l{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-l{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-l{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-l{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-l{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-l{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-l{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-l{margin:0}.swagger-ui .ma1-l{margin:.25rem}.swagger-ui .ma2-l{margin:.5rem}.swagger-ui .ma3-l{margin:1rem}.swagger-ui .ma4-l{margin:2rem}.swagger-ui .ma5-l{margin:4rem}.swagger-ui .ma6-l{margin:8rem}.swagger-ui .ma7-l{margin:16rem}.swagger-ui .ml0-l{margin-left:0}.swagger-ui .ml1-l{margin-left:.25rem}.swagger-ui .ml2-l{margin-left:.5rem}.swagger-ui .ml3-l{margin-left:1rem}.swagger-ui .ml4-l{margin-left:2rem}.swagger-ui .ml5-l{margin-left:4rem}.swagger-ui .ml6-l{margin-left:8rem}.swagger-ui .ml7-l{margin-left:16rem}.swagger-ui .mr0-l{margin-right:0}.swagger-ui .mr1-l{margin-right:.25rem}.swagger-ui .mr2-l{margin-right:.5rem}.swagger-ui .mr3-l{margin-right:1rem}.swagger-ui .mr4-l{margin-right:2rem}.swagger-ui .mr5-l{margin-right:4rem}.swagger-ui .mr6-l{margin-right:8rem}.swagger-ui .mr7-l{margin-right:16rem}.swagger-ui .mb0-l{margin-bottom:0}.swagger-ui .mb1-l{margin-bottom:.25rem}.swagger-ui .mb2-l{margin-bottom:.5rem}.swagger-ui .mb3-l{margin-bottom:1rem}.swagger-ui .mb4-l{margin-bottom:2rem}.swagger-ui .mb5-l{margin-bottom:4rem}.swagger-ui .mb6-l{margin-bottom:8rem}.swagger-ui .mb7-l{margin-bottom:16rem}.swagger-ui .mt0-l{margin-top:0}.swagger-ui .mt1-l{margin-top:.25rem}.swagger-ui .mt2-l{margin-top:.5rem}.swagger-ui .mt3-l{margin-top:1rem}.swagger-ui .mt4-l{margin-top:2rem}.swagger-ui .mt5-l{margin-top:4rem}.swagger-ui .mt6-l{margin-top:8rem}.swagger-ui .mt7-l{margin-top:16rem}.swagger-ui .mv0-l{margin-top:0;margin-bottom:0}.swagger-ui .mv1-l{margin-top:.25rem;margin-bottom:.25rem}.swagger-ui .mv2-l{margin-top:.5rem;margin-bottom:.5rem}.swagger-ui .mv3-l{margin-top:1rem;margin-bottom:1rem}.swagger-ui .mv4-l{margin-top:2rem;margin-bottom:2rem}.swagger-ui .mv5-l{margin-top:4rem;margin-bottom:4rem}.swagger-ui .mv6-l{margin-top:8rem;margin-bottom:8rem}.swagger-ui .mv7-l{margin-top:16rem;margin-bottom:16rem}.swagger-ui .mh0-l{margin-left:0;margin-right:0}.swagger-ui .mh1-l{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-l{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-l{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-l{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-l{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-l{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-l{margin-left:16rem;margin-right:16rem}}.swagger-ui .na1{margin:-.25rem}.swagger-ui .na2{margin:-.5rem}.swagger-ui .na3{margin:-1rem}.swagger-ui .na4{margin:-2rem}.swagger-ui .na5{margin:-4rem}.swagger-ui .na6{margin:-8rem}.swagger-ui .na7{margin:-16rem}.swagger-ui .nl1{margin-left:-.25rem}.swagger-ui .nl2{margin-left:-.5rem}.swagger-ui .nl3{margin-left:-1rem}.swagger-ui .nl4{margin-left:-2rem}.swagger-ui .nl5{margin-left:-4rem}.swagger-ui .nl6{margin-left:-8rem}.swagger-ui .nl7{margin-left:-16rem}.swagger-ui .nr1{margin-right:-.25rem}.swagger-ui .nr2{margin-right:-.5rem}.swagger-ui .nr3{margin-right:-1rem}.swagger-ui .nr4{margin-right:-2rem}.swagger-ui .nr5{margin-right:-4rem}.swagger-ui .nr6{margin-right:-8rem}.swagger-ui .nr7{margin-right:-16rem}.swagger-ui .nb1{margin-bottom:-.25rem}.swagger-ui .nb2{margin-bottom:-.5rem}.swagger-ui .nb3{margin-bottom:-1rem}.swagger-ui .nb4{margin-bottom:-2rem}.swagger-ui .nb5{margin-bottom:-4rem}.swagger-ui .nb6{margin-bottom:-8rem}.swagger-ui .nb7{margin-bottom:-16rem}.swagger-ui .nt1{margin-top:-.25rem}.swagger-ui .nt2{margin-top:-.5rem}.swagger-ui .nt3{margin-top:-1rem}.swagger-ui .nt4{margin-top:-2rem}.swagger-ui .nt5{margin-top:-4rem}.swagger-ui .nt6{margin-top:-8rem}.swagger-ui .nt7{margin-top:-16rem}@media screen and (min-width:30em){.swagger-ui .na1-ns{margin:-.25rem}.swagger-ui .na2-ns{margin:-.5rem}.swagger-ui .na3-ns{margin:-1rem}.swagger-ui .na4-ns{margin:-2rem}.swagger-ui .na5-ns{margin:-4rem}.swagger-ui .na6-ns{margin:-8rem}.swagger-ui .na7-ns{margin:-16rem}.swagger-ui .nl1-ns{margin-left:-.25rem}.swagger-ui .nl2-ns{margin-left:-.5rem}.swagger-ui .nl3-ns{margin-left:-1rem}.swagger-ui .nl4-ns{margin-left:-2rem}.swagger-ui .nl5-ns{margin-left:-4rem}.swagger-ui .nl6-ns{margin-left:-8rem}.swagger-ui .nl7-ns{margin-left:-16rem}.swagger-ui .nr1-ns{margin-right:-.25rem}.swagger-ui .nr2-ns{margin-right:-.5rem}.swagger-ui .nr3-ns{margin-right:-1rem}.swagger-ui .nr4-ns{margin-right:-2rem}.swagger-ui .nr5-ns{margin-right:-4rem}.swagger-ui .nr6-ns{margin-right:-8rem}.swagger-ui .nr7-ns{margin-right:-16rem}.swagger-ui .nb1-ns{margin-bottom:-.25rem}.swagger-ui .nb2-ns{margin-bottom:-.5rem}.swagger-ui .nb3-ns{margin-bottom:-1rem}.swagger-ui .nb4-ns{margin-bottom:-2rem}.swagger-ui .nb5-ns{margin-bottom:-4rem}.swagger-ui .nb6-ns{margin-bottom:-8rem}.swagger-ui .nb7-ns{margin-bottom:-16rem}.swagger-ui .nt1-ns{margin-top:-.25rem}.swagger-ui .nt2-ns{margin-top:-.5rem}.swagger-ui .nt3-ns{margin-top:-1rem}.swagger-ui .nt4-ns{margin-top:-2rem}.swagger-ui .nt5-ns{margin-top:-4rem}.swagger-ui .nt6-ns{margin-top:-8rem}.swagger-ui .nt7-ns{margin-top:-16rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .na1-m{margin:-.25rem}.swagger-ui .na2-m{margin:-.5rem}.swagger-ui .na3-m{margin:-1rem}.swagger-ui .na4-m{margin:-2rem}.swagger-ui .na5-m{margin:-4rem}.swagger-ui .na6-m{margin:-8rem}.swagger-ui .na7-m{margin:-16rem}.swagger-ui .nl1-m{margin-left:-.25rem}.swagger-ui .nl2-m{margin-left:-.5rem}.swagger-ui .nl3-m{margin-left:-1rem}.swagger-ui .nl4-m{margin-left:-2rem}.swagger-ui .nl5-m{margin-left:-4rem}.swagger-ui .nl6-m{margin-left:-8rem}.swagger-ui .nl7-m{margin-left:-16rem}.swagger-ui .nr1-m{margin-right:-.25rem}.swagger-ui .nr2-m{margin-right:-.5rem}.swagger-ui .nr3-m{margin-right:-1rem}.swagger-ui .nr4-m{margin-right:-2rem}.swagger-ui .nr5-m{margin-right:-4rem}.swagger-ui .nr6-m{margin-right:-8rem}.swagger-ui .nr7-m{margin-right:-16rem}.swagger-ui .nb1-m{margin-bottom:-.25rem}.swagger-ui .nb2-m{margin-bottom:-.5rem}.swagger-ui .nb3-m{margin-bottom:-1rem}.swagger-ui .nb4-m{margin-bottom:-2rem}.swagger-ui .nb5-m{margin-bottom:-4rem}.swagger-ui .nb6-m{margin-bottom:-8rem}.swagger-ui .nb7-m{margin-bottom:-16rem}.swagger-ui .nt1-m{margin-top:-.25rem}.swagger-ui .nt2-m{margin-top:-.5rem}.swagger-ui .nt3-m{margin-top:-1rem}.swagger-ui .nt4-m{margin-top:-2rem}.swagger-ui .nt5-m{margin-top:-4rem}.swagger-ui .nt6-m{margin-top:-8rem}.swagger-ui .nt7-m{margin-top:-16rem}}@media screen and (min-width:60em){.swagger-ui .na1-l{margin:-.25rem}.swagger-ui .na2-l{margin:-.5rem}.swagger-ui .na3-l{margin:-1rem}.swagger-ui .na4-l{margin:-2rem}.swagger-ui .na5-l{margin:-4rem}.swagger-ui .na6-l{margin:-8rem}.swagger-ui .na7-l{margin:-16rem}.swagger-ui .nl1-l{margin-left:-.25rem}.swagger-ui .nl2-l{margin-left:-.5rem}.swagger-ui .nl3-l{margin-left:-1rem}.swagger-ui .nl4-l{margin-left:-2rem}.swagger-ui .nl5-l{margin-left:-4rem}.swagger-ui .nl6-l{margin-left:-8rem}.swagger-ui .nl7-l{margin-left:-16rem}.swagger-ui .nr1-l{margin-right:-.25rem}.swagger-ui .nr2-l{margin-right:-.5rem}.swagger-ui .nr3-l{margin-right:-1rem}.swagger-ui .nr4-l{margin-right:-2rem}.swagger-ui .nr5-l{margin-right:-4rem}.swagger-ui .nr6-l{margin-right:-8rem}.swagger-ui .nr7-l{margin-right:-16rem}.swagger-ui .nb1-l{margin-bottom:-.25rem}.swagger-ui .nb2-l{margin-bottom:-.5rem}.swagger-ui .nb3-l{margin-bottom:-1rem}.swagger-ui .nb4-l{margin-bottom:-2rem}.swagger-ui .nb5-l{margin-bottom:-4rem}.swagger-ui .nb6-l{margin-bottom:-8rem}.swagger-ui .nb7-l{margin-bottom:-16rem}.swagger-ui .nt1-l{margin-top:-.25rem}.swagger-ui .nt2-l{margin-top:-.5rem}.swagger-ui .nt3-l{margin-top:-1rem}.swagger-ui .nt4-l{margin-top:-2rem}.swagger-ui .nt5-l{margin-top:-4rem}.swagger-ui .nt6-l{margin-top:-8rem}.swagger-ui .nt7-l{margin-top:-16rem}}.swagger-ui .collapse{border-collapse:collapse;border-spacing:0}.swagger-ui .striped--light-silver:nth-child(odd){background-color:#aaa}.swagger-ui .striped--moon-gray:nth-child(odd){background-color:#ccc}.swagger-ui .striped--light-gray:nth-child(odd){background-color:#eee}.swagger-ui .striped--near-white:nth-child(odd){background-color:#f4f4f4}.swagger-ui .stripe-light:nth-child(odd){background-color:hsla(0,0%,100%,.1)}.swagger-ui .stripe-dark:nth-child(odd){background-color:rgba(0,0,0,.1)}.swagger-ui .strike{text-decoration:line-through}.swagger-ui .underline{text-decoration:underline}.swagger-ui .no-underline{text-decoration:none}@media screen and (min-width:30em){.swagger-ui .strike-ns{text-decoration:line-through}.swagger-ui .underline-ns{text-decoration:underline}.swagger-ui .no-underline-ns{text-decoration:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .strike-m{text-decoration:line-through}.swagger-ui .underline-m{text-decoration:underline}.swagger-ui .no-underline-m{text-decoration:none}}@media screen and (min-width:60em){.swagger-ui .strike-l{text-decoration:line-through}.swagger-ui .underline-l{text-decoration:underline}.swagger-ui .no-underline-l{text-decoration:none}}.swagger-ui .tl{text-align:left}.swagger-ui .tr{text-align:right}.swagger-ui .tc{text-align:center}.swagger-ui .tj{text-align:justify}@media screen and (min-width:30em){.swagger-ui .tl-ns{text-align:left}.swagger-ui .tr-ns{text-align:right}.swagger-ui .tc-ns{text-align:center}.swagger-ui .tj-ns{text-align:justify}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .tl-m{text-align:left}.swagger-ui .tr-m{text-align:right}.swagger-ui .tc-m{text-align:center}.swagger-ui .tj-m{text-align:justify}}@media screen and (min-width:60em){.swagger-ui .tl-l{text-align:left}.swagger-ui .tr-l{text-align:right}.swagger-ui .tc-l{text-align:center}.swagger-ui .tj-l{text-align:justify}}.swagger-ui .ttc{text-transform:capitalize}.swagger-ui .ttl{text-transform:lowercase}.swagger-ui .ttu{text-transform:uppercase}.swagger-ui .ttn{text-transform:none}@media screen and (min-width:30em){.swagger-ui .ttc-ns{text-transform:capitalize}.swagger-ui .ttl-ns{text-transform:lowercase}.swagger-ui .ttu-ns{text-transform:uppercase}.swagger-ui .ttn-ns{text-transform:none}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ttc-m{text-transform:capitalize}.swagger-ui .ttl-m{text-transform:lowercase}.swagger-ui .ttu-m{text-transform:uppercase}.swagger-ui .ttn-m{text-transform:none}}@media screen and (min-width:60em){.swagger-ui .ttc-l{text-transform:capitalize}.swagger-ui .ttl-l{text-transform:lowercase}.swagger-ui .ttu-l{text-transform:uppercase}.swagger-ui .ttn-l{text-transform:none}}.swagger-ui .f-6,.swagger-ui .f-headline{font-size:6rem}.swagger-ui .f-5,.swagger-ui .f-subheadline{font-size:5rem}.swagger-ui .f1{font-size:3rem}.swagger-ui .f2{font-size:2.25rem}.swagger-ui .f3{font-size:1.5rem}.swagger-ui .f4{font-size:1.25rem}.swagger-ui .f5{font-size:1rem}.swagger-ui .f6{font-size:.875rem}.swagger-ui .f7{font-size:.75rem}@media screen and (min-width:30em){.swagger-ui .f-6-ns,.swagger-ui .f-headline-ns{font-size:6rem}.swagger-ui .f-5-ns,.swagger-ui .f-subheadline-ns{font-size:5rem}.swagger-ui .f1-ns{font-size:3rem}.swagger-ui .f2-ns{font-size:2.25rem}.swagger-ui .f3-ns{font-size:1.5rem}.swagger-ui .f4-ns{font-size:1.25rem}.swagger-ui .f5-ns{font-size:1rem}.swagger-ui .f6-ns{font-size:.875rem}.swagger-ui .f7-ns{font-size:.75rem}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .f-6-m,.swagger-ui .f-headline-m{font-size:6rem}.swagger-ui .f-5-m,.swagger-ui .f-subheadline-m{font-size:5rem}.swagger-ui .f1-m{font-size:3rem}.swagger-ui .f2-m{font-size:2.25rem}.swagger-ui .f3-m{font-size:1.5rem}.swagger-ui .f4-m{font-size:1.25rem}.swagger-ui .f5-m{font-size:1rem}.swagger-ui .f6-m{font-size:.875rem}.swagger-ui .f7-m{font-size:.75rem}}@media screen and (min-width:60em){.swagger-ui .f-6-l,.swagger-ui .f-headline-l{font-size:6rem}.swagger-ui .f-5-l,.swagger-ui .f-subheadline-l{font-size:5rem}.swagger-ui .f1-l{font-size:3rem}.swagger-ui .f2-l{font-size:2.25rem}.swagger-ui .f3-l{font-size:1.5rem}.swagger-ui .f4-l{font-size:1.25rem}.swagger-ui .f5-l{font-size:1rem}.swagger-ui .f6-l{font-size:.875rem}.swagger-ui .f7-l{font-size:.75rem}}.swagger-ui .measure{max-width:30em}.swagger-ui .measure-wide{max-width:34em}.swagger-ui .measure-narrow{max-width:20em}.swagger-ui .indent{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps{font-variant:small-caps}.swagger-ui .truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@media screen and (min-width:30em){.swagger-ui .measure-ns{max-width:30em}.swagger-ui .measure-wide-ns{max-width:34em}.swagger-ui .measure-narrow-ns{max-width:20em}.swagger-ui .indent-ns{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-ns{font-variant:small-caps}.swagger-ui .truncate-ns{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .measure-m{max-width:30em}.swagger-ui .measure-wide-m{max-width:34em}.swagger-ui .measure-narrow-m{max-width:20em}.swagger-ui .indent-m{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-m{font-variant:small-caps}.swagger-ui .truncate-m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}@media screen and (min-width:60em){.swagger-ui .measure-l{max-width:30em}.swagger-ui .measure-wide-l{max-width:34em}.swagger-ui .measure-narrow-l{max-width:20em}.swagger-ui .indent-l{text-indent:1em;margin-top:0;margin-bottom:0}.swagger-ui .small-caps-l{font-variant:small-caps}.swagger-ui .truncate-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}}.swagger-ui .overflow-container{overflow-y:scroll}.swagger-ui .center{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto{margin-right:auto}.swagger-ui .ml-auto{margin-left:auto}@media screen and (min-width:30em){.swagger-ui .center-ns{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-ns{margin-right:auto}.swagger-ui .ml-auto-ns{margin-left:auto}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .center-m{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-m{margin-right:auto}.swagger-ui .ml-auto-m{margin-left:auto}}@media screen and (min-width:60em){.swagger-ui .center-l{margin-right:auto;margin-left:auto}.swagger-ui .mr-auto-l{margin-right:auto}.swagger-ui .ml-auto-l{margin-left:auto}}.swagger-ui .clip{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}@media screen and (min-width:30em){.swagger-ui .clip-ns{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .clip-m{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}@media screen and (min-width:60em){.swagger-ui .clip-l{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}}.swagger-ui .ws-normal{white-space:normal}.swagger-ui .nowrap{white-space:nowrap}.swagger-ui .pre{white-space:pre}@media screen and (min-width:30em){.swagger-ui .ws-normal-ns{white-space:normal}.swagger-ui .nowrap-ns{white-space:nowrap}.swagger-ui .pre-ns{white-space:pre}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .ws-normal-m{white-space:normal}.swagger-ui .nowrap-m{white-space:nowrap}.swagger-ui .pre-m{white-space:pre}}@media screen and (min-width:60em){.swagger-ui .ws-normal-l{white-space:normal}.swagger-ui .nowrap-l{white-space:nowrap}.swagger-ui .pre-l{white-space:pre}}.swagger-ui .v-base{vertical-align:baseline}.swagger-ui .v-mid{vertical-align:middle}.swagger-ui .v-top{vertical-align:top}.swagger-ui .v-btm{vertical-align:bottom}@media screen and (min-width:30em){.swagger-ui .v-base-ns{vertical-align:baseline}.swagger-ui .v-mid-ns{vertical-align:middle}.swagger-ui .v-top-ns{vertical-align:top}.swagger-ui .v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .v-base-m{vertical-align:baseline}.swagger-ui .v-mid-m{vertical-align:middle}.swagger-ui .v-top-m{vertical-align:top}.swagger-ui .v-btm-m{vertical-align:bottom}}@media screen and (min-width:60em){.swagger-ui .v-base-l{vertical-align:baseline}.swagger-ui .v-mid-l{vertical-align:middle}.swagger-ui .v-top-l{vertical-align:top}.swagger-ui .v-btm-l{vertical-align:bottom}}.swagger-ui .dim{opacity:1;transition:opacity .15s ease-in}.swagger-ui .dim:focus,.swagger-ui .dim:hover{opacity:.5;transition:opacity .15s ease-in}.swagger-ui .dim:active{opacity:.8;transition:opacity .15s ease-out}.swagger-ui .glow{transition:opacity .15s ease-in}.swagger-ui .glow:focus,.swagger-ui .glow:hover{opacity:1;transition:opacity .15s ease-in}.swagger-ui .hide-child .child{opacity:0;transition:opacity .15s ease-in}.swagger-ui .hide-child:active .child,.swagger-ui .hide-child:focus .child,.swagger-ui .hide-child:hover .child{opacity:1;transition:opacity .15s ease-in}.swagger-ui .underline-hover:focus,.swagger-ui .underline-hover:hover{text-decoration:underline}.swagger-ui .grow{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out, -webkit-transform .25s ease-out}.swagger-ui .grow:focus,.swagger-ui .grow:hover{-webkit-transform:scale(1.05);transform:scale(1.05)}.swagger-ui .grow:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .grow-large{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);transition:-webkit-transform .25s ease-in-out;transition:transform .25s ease-in-out;transition:transform .25s ease-in-out, -webkit-transform .25s ease-in-out}.swagger-ui .grow-large:focus,.swagger-ui .grow-large:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.swagger-ui .grow-large:active{-webkit-transform:scale(.95);transform:scale(.95)}.swagger-ui .pointer:hover{cursor:pointer}.swagger-ui .shadow-hover{cursor:pointer;position:relative;transition:all .5s cubic-bezier(.165,.84,.44,1)}.swagger-ui .shadow-hover:after{content:"";box-shadow:0 0 16px 2px rgba(0,0,0,.2);border-radius:inherit;opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;transition:opacity .5s cubic-bezier(.165,.84,.44,1)}.swagger-ui .shadow-hover:focus:after,.swagger-ui .shadow-hover:hover:after{opacity:1}.swagger-ui .bg-animate,.swagger-ui .bg-animate:focus,.swagger-ui .bg-animate:hover{transition:background-color .15s ease-in-out}.swagger-ui .z-0{z-index:0}.swagger-ui .z-1{z-index:1}.swagger-ui .z-2{z-index:2}.swagger-ui .z-3{z-index:3}.swagger-ui .z-4{z-index:4}.swagger-ui .z-5{z-index:5}.swagger-ui .z-999{z-index:999}.swagger-ui .z-9999{z-index:9999}.swagger-ui .z-max{z-index:2147483647}.swagger-ui .z-inherit{z-index:inherit}.swagger-ui .z-initial{z-index:auto}.swagger-ui .z-unset{z-index:unset}.swagger-ui .nested-copy-line-height ol,.swagger-ui .nested-copy-line-height p,.swagger-ui .nested-copy-line-height ul{line-height:1.5}.swagger-ui .nested-headline-line-height h1,.swagger-ui .nested-headline-line-height h2,.swagger-ui .nested-headline-line-height h3,.swagger-ui .nested-headline-line-height h4,.swagger-ui .nested-headline-line-height h5,.swagger-ui .nested-headline-line-height h6{line-height:1.25}.swagger-ui .nested-list-reset ol,.swagger-ui .nested-list-reset ul{padding-left:0;margin-left:0;list-style-type:none}.swagger-ui .nested-copy-indent p+p{text-indent:.1em;margin-top:0;margin-bottom:0}.swagger-ui .nested-copy-seperator p+p{margin-top:1.5em}.swagger-ui .nested-img img{width:100%;max-width:100%;display:block}.swagger-ui .nested-links a{color:#357edd;transition:color .15s ease-in}.swagger-ui .nested-links a:focus,.swagger-ui .nested-links a:hover{color:#96ccff;transition:color .15s ease-in}.swagger-ui .wrapper{width:100%;max-width:1460px;margin:0 auto;padding:0 20px;box-sizing:border-box}.swagger-ui .opblock-tag-section{display:flex;flex-direction:column}.swagger-ui .opblock-tag{display:flex;align-items:center;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui .opblock-tag:hover{background:rgba(0,0,0,.02)}.swagger-ui .opblock-tag{font-size:24px;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-tag.no-desc span{flex:1}.swagger-ui .opblock-tag svg{transition:all .4s}.swagger-ui .opblock-tag small{font-size:14px;font-weight:400;flex:1;padding:0 10px;font-family:sans-serif;color:#3b4151}.swagger-ui .parameter__type{font-size:12px;padding:5px 0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .parameter-controls{margin-top:.75em}.swagger-ui .examples__title{display:block;font-size:1.1em;font-weight:700;margin-bottom:.75em}.swagger-ui .examples__section{margin-top:1.5em}.swagger-ui .examples__section-header{font-weight:700;font-size:.9rem;margin-bottom:.5rem}.swagger-ui .examples-select{margin-bottom:.75em}.swagger-ui .examples-select__section-label{font-weight:700;font-size:.9rem;margin-right:.5rem}.swagger-ui .example__section{margin-top:1.5em}.swagger-ui .example__section-header{font-weight:700;font-size:.9rem;margin-bottom:.5rem}.swagger-ui .view-line-link{position:relative;top:3px;width:20px;margin:0 5px;cursor:pointer;transition:all .5s}.swagger-ui .opblock{margin:0 0 15px;border:1px solid #000;border-radius:4px;box-shadow:0 0 3px rgba(0,0,0,.19)}.swagger-ui .opblock .tab-header{display:flex;flex:1}.swagger-ui .opblock .tab-header .tab-item{padding:0 40px;cursor:pointer}.swagger-ui .opblock .tab-header .tab-item:first-of-type{padding:0 40px 0 0}.swagger-ui .opblock .tab-header .tab-item.active h4 span{position:relative}.swagger-ui .opblock .tab-header .tab-item.active h4 span:after{position:absolute;bottom:-15px;left:50%;width:120%;height:4px;content:"";-webkit-transform:translateX(-50%);transform:translateX(-50%);background:grey}.swagger-ui .opblock.is-open .opblock-summary{border-bottom:1px solid #000}.swagger-ui .opblock .opblock-section-header{display:flex;align-items:center;padding:8px 20px;min-height:50px;background:hsla(0,0%,100%,.8);box-shadow:0 1px 2px rgba(0,0,0,.1)}.swagger-ui .opblock .opblock-section-header>label{font-size:12px;font-weight:700;display:flex;align-items:center;margin:0 0 0 auto;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-section-header>label>span{padding:0 10px 0 0}.swagger-ui .opblock .opblock-section-header h4{font-size:14px;flex:1;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary-method{font-size:14px;font-weight:700;min-width:80px;padding:6px 15px;text-align:center;border-radius:3px;background:#000;text-shadow:0 1px 0 rgba(0,0,0,.1);font-family:sans-serif;color:#fff}.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:16px;display:flex;align-items:center;word-break:break-word;padding:0 10px;font-family:monospace;font-weight:600;color:#3b4151}@media (max-width:768px){.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:12px}}.swagger-ui .opblock .opblock-summary-path__deprecated{text-decoration:line-through}.swagger-ui .opblock .opblock-summary-operation-id{font-size:14px}.swagger-ui .opblock .opblock-summary-description{font-size:13px;flex:1 1 auto;word-break:break-word;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock .opblock-summary{display:flex;align-items:center;padding:5px;cursor:pointer}.swagger-ui .opblock .opblock-summary .view-line-link{position:relative;top:2px;width:0;margin:0;cursor:pointer;transition:all .5s}.swagger-ui .opblock .opblock-summary:hover .view-line-link{width:18px;margin:0 5px}.swagger-ui .opblock.opblock-post{border-color:#49cc90;background:rgba(73,204,144,.1)}.swagger-ui .opblock.opblock-post .opblock-summary-method{background:#49cc90}.swagger-ui .opblock.opblock-post .opblock-summary{border-color:#49cc90}.swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span:after{background:#49cc90}.swagger-ui .opblock.opblock-put{border-color:#fca130;background:rgba(252,161,48,.1)}.swagger-ui .opblock.opblock-put .opblock-summary-method{background:#fca130}.swagger-ui .opblock.opblock-put .opblock-summary{border-color:#fca130}.swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span:after{background:#fca130}.swagger-ui .opblock.opblock-delete{border-color:#f93e3e;background:rgba(249,62,62,.1)}.swagger-ui .opblock.opblock-delete .opblock-summary-method{background:#f93e3e}.swagger-ui .opblock.opblock-delete .opblock-summary{border-color:#f93e3e}.swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span:after{background:#f93e3e}.swagger-ui .opblock.opblock-get{border-color:#61affe;background:rgba(97,175,254,.1)}.swagger-ui .opblock.opblock-get .opblock-summary-method{background:#61affe}.swagger-ui .opblock.opblock-get .opblock-summary{border-color:#61affe}.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span:after{background:#61affe}.swagger-ui .opblock.opblock-patch{border-color:#50e3c2;background:rgba(80,227,194,.1)}.swagger-ui .opblock.opblock-patch .opblock-summary-method{background:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary{border-color:#50e3c2}.swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span:after{background:#50e3c2}.swagger-ui .opblock.opblock-head{border-color:#9012fe;background:rgba(144,18,254,.1)}.swagger-ui .opblock.opblock-head .opblock-summary-method{background:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary{border-color:#9012fe}.swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span:after{background:#9012fe}.swagger-ui .opblock.opblock-options{border-color:#0d5aa7;background:rgba(13,90,167,.1)}.swagger-ui .opblock.opblock-options .opblock-summary-method{background:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary{border-color:#0d5aa7}.swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span:after{background:#0d5aa7}.swagger-ui .opblock.opblock-deprecated{opacity:.6;border-color:#ebebeb;background:hsla(0,0%,92.2%,.1)}.swagger-ui .opblock.opblock-deprecated .opblock-summary-method{background:#ebebeb}.swagger-ui .opblock.opblock-deprecated .opblock-summary{border-color:#ebebeb}.swagger-ui .opblock.opblock-deprecated .tab-header .tab-item.active h4 span:after{background:#ebebeb}.swagger-ui .opblock .opblock-schemes{padding:8px 20px}.swagger-ui .opblock .opblock-schemes .schemes-title{padding:0 10px 0 0}.swagger-ui .filter .operation-filter-input{width:100%;margin:20px 0;padding:10px;border:2px solid #d8dde7}.swagger-ui .model-example{margin-top:1em}.swagger-ui .tab{display:flex;padding:0;list-style:none}.swagger-ui .tab li{font-size:12px;min-width:60px;padding:0;cursor:pointer;font-family:sans-serif;color:#3b4151}.swagger-ui .tab li:first-of-type{position:relative;padding-left:0;padding-right:12px}.swagger-ui .tab li:first-of-type:after{position:absolute;top:0;right:6px;width:1px;height:100%;content:"";background:rgba(0,0,0,.2)}.swagger-ui .tab li.active{font-weight:700}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-external-docs-wrapper,.swagger-ui .opblock-title_normal{font-size:12px;margin:0 0 5px;padding:15px 20px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper h4,.swagger-ui .opblock-external-docs-wrapper h4,.swagger-ui .opblock-title_normal h4{font-size:12px;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-description-wrapper p,.swagger-ui .opblock-external-docs-wrapper p,.swagger-ui .opblock-title_normal p{font-size:14px;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .opblock-external-docs-wrapper h4{padding-left:0}.swagger-ui .execute-wrapper{padding:20px;text-align:right}.swagger-ui .execute-wrapper .btn{width:100%;padding:8px 40px}.swagger-ui .body-param-options{display:flex;flex-direction:column}.swagger-ui .body-param-options .body-param-edit{padding:10px 0}.swagger-ui .body-param-options label{padding:8px 0}.swagger-ui .body-param-options label select{margin:3px 0 0}.swagger-ui .responses-inner{padding:20px}.swagger-ui .responses-inner h4,.swagger-ui .responses-inner h5{font-size:12px;margin:10px 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_status{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_status .response-undocumented{font-size:11px;font-family:monospace;font-weight:600;color:#909090}.swagger-ui .response-col_links{padding-left:2em;max-width:40em;font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .response-col_links .response-undocumented{font-size:11px;font-family:monospace;font-weight:600;color:#909090}.swagger-ui .opblock-body .opblock-loading-animation{display:block;margin:3em auto}.swagger-ui .opblock-body pre.microlight{font-size:12px;margin:0;padding:10px;white-space:pre-wrap;word-wrap:break-word;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto;border-radius:4px;background:#41444e;overflow-wrap:break-word;font-family:monospace;font-weight:600;color:#fff}.swagger-ui .opblock-body pre.microlight span{color:#fff!important}.swagger-ui .opblock-body pre.microlight .headerline{display:block}.swagger-ui .highlight-code{position:relative}.swagger-ui .highlight-code>.microlight{overflow-y:auto;max-height:400px;min-height:6em}.swagger-ui .download-contents{position:absolute;bottom:10px;right:10px;cursor:pointer;background:#7d8293;text-align:center;padding:5px;border-radius:4px;font-family:sans-serif;font-weight:600;color:#fff;font-size:14px;height:30px;width:75px}.swagger-ui .scheme-container{margin:0 0 20px;padding:30px 0;background:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.15)}.swagger-ui .scheme-container .schemes{display:flex;align-items:flex-end}.swagger-ui .scheme-container .schemes>label{font-size:12px;font-weight:700;display:flex;flex-direction:column;margin:-20px 15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .scheme-container .schemes>label select{min-width:130px;text-transform:uppercase}.swagger-ui .loading-container{padding:40px 0 60px;margin-top:1em;min-height:1px;display:flex;justify-content:center;align-items:center;flex-direction:column}.swagger-ui .loading-container .loading{position:relative}.swagger-ui .loading-container .loading:after{font-size:10px;font-weight:700;position:absolute;top:50%;left:50%;content:"loading";-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-transform:uppercase;font-family:sans-serif;color:#3b4151}.swagger-ui .loading-container .loading:before{position:absolute;top:50%;left:50%;display:block;width:60px;height:60px;margin:-30px;content:"";-webkit-animation:rotation 1s linear infinite,opacity .5s;animation:rotation 1s linear infinite,opacity .5s;opacity:1;border:2px solid rgba(85,85,85,.1);border-top-color:rgba(0,0,0,.6);border-radius:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden}@-webkit-keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotation{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.swagger-ui .response-controls{padding-top:1em;display:flex}.swagger-ui .response-control-media-type{margin-right:1em}.swagger-ui .response-control-media-type--accept-controller select{border-color:green}.swagger-ui .response-control-media-type__accept-message{color:green;font-size:.7em}.swagger-ui .response-control-examples__title,.swagger-ui .response-control-media-type__title{display:block;margin-bottom:.2em;font-size:.7em}@-webkit-keyframes blinker{50%{opacity:0}}@keyframes blinker{50%{opacity:0}}.swagger-ui section h3{font-family:sans-serif;color:#3b4151}.swagger-ui a.nostyle{display:inline}.swagger-ui a.nostyle,.swagger-ui a.nostyle:visited{text-decoration:inherit;color:inherit;cursor:pointer}.swagger-ui .version-pragma{height:100%;padding:5em 0}.swagger-ui .version-pragma__message{display:flex;justify-content:center;height:100%;font-size:1.2em;text-align:center;line-height:1.5em;padding:0 .6em}.swagger-ui .version-pragma__message>div{max-width:55ch;flex:1}.swagger-ui .version-pragma__message code{background-color:#dedede;padding:4px 4px 2px;white-space:pre}.swagger-ui .btn{font-size:14px;font-weight:700;padding:5px 23px;transition:all .3s;border:2px solid grey;border-radius:4px;background:transparent;box-shadow:0 1px 2px rgba(0,0,0,.1);font-family:sans-serif;color:#3b4151}.swagger-ui .btn.btn-sm{font-size:12px;padding:4px 23px}.swagger-ui .btn[disabled]{cursor:not-allowed;opacity:.3}.swagger-ui .btn:hover{box-shadow:0 0 5px rgba(0,0,0,.3)}.swagger-ui .btn.cancel{border-color:#ff6060;background-color:transparent;font-family:sans-serif;color:#ff6060}.swagger-ui .btn.authorize{line-height:1;display:inline;color:#49cc90;border-color:#49cc90;background-color:transparent}.swagger-ui .btn.authorize span{float:left;padding:4px 20px 0 0}.swagger-ui .btn.authorize svg{fill:#49cc90}.swagger-ui .btn.execute{background-color:#4990e2;color:#fff;border-color:#4990e2}.swagger-ui .btn-group{display:flex;padding:30px}.swagger-ui .btn-group .btn{flex:1}.swagger-ui .btn-group .btn:first-child{border-radius:4px 0 0 4px}.swagger-ui .btn-group .btn:last-child{border-radius:0 4px 4px 0}.swagger-ui .authorization__btn{padding:0 10px;border:none;background:none}.swagger-ui .authorization__btn.locked{opacity:1}.swagger-ui .authorization__btn.unlocked{opacity:.4}.swagger-ui .expand-methods,.swagger-ui .expand-operation{border:none;background:none}.swagger-ui .expand-methods svg,.swagger-ui .expand-operation svg{width:20px;height:20px}.swagger-ui .expand-methods{padding:0 10px}.swagger-ui .expand-methods:hover svg{fill:#404040}.swagger-ui .expand-methods svg{transition:all .3s;fill:#707070}.swagger-ui button{cursor:pointer;outline:none}.swagger-ui button.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui select{font-size:14px;font-weight:700;padding:5px 40px 5px 10px;border:2px solid #41444e;border-radius:4px;background:#f7f7f7 url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCI+PHBhdGggZD0iTTEzLjQxOCA3Ljg1OWEuNjk1LjY5NSAwIDAxLjk3OCAwIC42OC42OCAwIDAxMCAuOTY5bC0zLjkwOCAzLjgzYS42OTcuNjk3IDAgMDEtLjk3OSAwbC0zLjkwOC0zLjgzYS42OC42OCAwIDAxMC0uOTY5LjY5NS42OTUgMCAwMS45NzggMEwxMCAxMWwzLjQxOC0zLjE0MXoiLz48L3N2Zz4=) right 10px center no-repeat;background-size:20px;box-shadow:0 1px 2px 0 rgba(0,0,0,.25);font-family:sans-serif;color:#3b4151;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui select[multiple]{margin:5px 0;padding:5px;background:#f7f7f7}.swagger-ui select.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui .opblock-body select{min-width:230px}@media (max-width:768px){.swagger-ui .opblock-body select{min-width:180px}}.swagger-ui label{font-size:12px;font-weight:700;margin:0 0 5px;font-family:sans-serif;color:#3b4151}.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text],.swagger-ui textarea{min-width:100px;margin:5px 0;padding:8px 10px;border:1px solid #d9d9d9;border-radius:4px;background:#fff}@media (max-width:768px){.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text],.swagger-ui textarea{max-width:175px}}.swagger-ui input[type=email].invalid,.swagger-ui input[type=file].invalid,.swagger-ui input[type=password].invalid,.swagger-ui input[type=search].invalid,.swagger-ui input[type=text].invalid,.swagger-ui textarea.invalid{-webkit-animation:shake .4s 1;animation:shake .4s 1;border-color:#f93e3e;background:#feebeb}.swagger-ui input[disabled],.swagger-ui select[disabled],.swagger-ui textarea[disabled]{background-color:#fafafa;color:#888;cursor:not-allowed}.swagger-ui select[disabled]{border-color:#888}.swagger-ui textarea[disabled]{background-color:#41444e;color:#fff}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-1px,0,0);transform:translate3d(-1px,0,0)}20%,80%{-webkit-transform:translate3d(2px,0,0);transform:translate3d(2px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-4px,0,0);transform:translate3d(-4px,0,0)}40%,60%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}}.swagger-ui textarea{font-size:12px;width:100%;min-height:280px;padding:10px;border:none;border-radius:4px;outline:none;background:hsla(0,0%,100%,.8);font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui textarea:focus{border:2px solid #61affe}.swagger-ui textarea.curl{font-size:12px;min-height:100px;margin:0;padding:10px;resize:none;border-radius:4px;background:#41444e;font-family:monospace;font-weight:600;color:#fff}.swagger-ui .checkbox{padding:5px 0 10px;transition:opacity .5s;color:#303030}.swagger-ui .checkbox label{display:flex}.swagger-ui .checkbox p{font-weight:400!important;font-style:italic;margin:0!important;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .checkbox input[type=checkbox]{display:none}.swagger-ui .checkbox input[type=checkbox]+label>.item{position:relative;top:3px;display:inline-block;width:16px;height:16px;margin:0 8px 0 0;padding:5px;cursor:pointer;border-radius:1px;background:#e8e8e8;box-shadow:0 0 0 2px #e8e8e8;flex:none}.swagger-ui .checkbox input[type=checkbox]+label>.item:active{-webkit-transform:scale(.9);transform:scale(.9)}.swagger-ui .checkbox input[type=checkbox]:checked+label>.item{background:#e8e8e8 url("data:image/svg+xml;charset=utf-8,%3Csvg width='10' height='8' viewBox='3 7 10 8' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2341474E' fill-rule='evenodd' d='M6.333 15L3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z'/%3E%3C/svg%3E") 50% no-repeat}.swagger-ui .dialog-ux{position:fixed;z-index:9999;top:0;right:0;bottom:0;left:0}.swagger-ui .dialog-ux .backdrop-ux{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.8)}.swagger-ui .dialog-ux .modal-ux{position:absolute;z-index:9999;top:50%;left:50%;width:100%;min-width:300px;max-width:650px;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border:1px solid #ebebeb;border-radius:4px;background:#fff;box-shadow:0 10px 30px 0 rgba(0,0,0,.2)}.swagger-ui .dialog-ux .modal-ux-content{overflow-y:auto;max-height:540px;padding:20px}.swagger-ui .dialog-ux .modal-ux-content p{font-size:12px;margin:0 0 5px;color:#41444e;font-family:sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-content h4{font-size:18px;font-weight:600;margin:15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .dialog-ux .modal-ux-header{display:flex;padding:12px 0;border-bottom:1px solid #ebebeb;align-items:center}.swagger-ui .dialog-ux .modal-ux-header .close-modal{padding:0 10px;border:none;background:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.swagger-ui .dialog-ux .modal-ux-header h3{font-size:20px;font-weight:600;margin:0;padding:0 20px;flex:1;font-family:sans-serif;color:#3b4151}.swagger-ui .model{font-size:12px;font-weight:300;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .model .deprecated span,.swagger-ui .model .deprecated td{color:#a0a0a0!important}.swagger-ui .model .deprecated>td:first-of-type{text-decoration:line-through}.swagger-ui .model-toggle{font-size:10px;position:relative;top:6px;display:inline-block;margin:auto .3em;cursor:pointer;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in, -webkit-transform .15s ease-in;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-transform-origin:50% 50%;transform-origin:50% 50%}.swagger-ui .model-toggle.collapsed{-webkit-transform:rotate(0deg);transform:rotate(0deg)}.swagger-ui .model-toggle:after{display:block;width:20px;height:20px;content:"";background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") 50% no-repeat;background-size:100%}.swagger-ui .model-jump-to-path{position:relative;cursor:pointer}.swagger-ui .model-jump-to-path .view-line-link{position:absolute;top:-.4em;cursor:pointer}.swagger-ui .model-title{position:relative}.swagger-ui .model-title:hover .model-hint{visibility:visible}.swagger-ui .model-hint{position:absolute;top:-1.8em;visibility:hidden;padding:.1em .5em;white-space:nowrap;color:#ebebeb;border-radius:4px;background:rgba(0,0,0,.7)}.swagger-ui .model p{margin:0 0 1em}.swagger-ui section.models{margin:30px 0;border:1px solid rgba(59,65,81,.3);border-radius:4px}.swagger-ui section.models.is-open{padding:0 0 20px}.swagger-ui section.models.is-open h4{margin:0 0 5px;border-bottom:1px solid rgba(59,65,81,.3)}.swagger-ui section.models h4{font-size:16px;display:flex;align-items:center;margin:0;padding:10px 20px 10px 10px;cursor:pointer;transition:all .2s;font-family:sans-serif;color:#606060}.swagger-ui section.models h4 svg{transition:all .4s}.swagger-ui section.models h4 span{flex:1}.swagger-ui section.models h4:hover{background:rgba(0,0,0,.02)}.swagger-ui section.models h5{font-size:16px;margin:0 0 10px;font-family:sans-serif;color:#707070}.swagger-ui section.models .model-jump-to-path{position:relative;top:5px}.swagger-ui section.models .model-container{margin:0 20px 15px;position:relative;transition:all .5s;border-radius:4px;background:rgba(0,0,0,.05)}.swagger-ui section.models .model-container:hover{background:rgba(0,0,0,.07)}.swagger-ui section.models .model-container:first-of-type{margin:20px}.swagger-ui section.models .model-container:last-of-type{margin:0 20px}.swagger-ui section.models .model-container .models-jump-to-path{position:absolute;top:8px;right:5px;opacity:.65}.swagger-ui section.models .model-box{background:none}.swagger-ui .model-box{padding:10px;display:inline-block;border-radius:4px;background:rgba(0,0,0,.1)}.swagger-ui .model-box .model-jump-to-path{position:relative;top:4px}.swagger-ui .model-box.deprecated{opacity:.5}.swagger-ui .model-title{font-size:16px;font-family:sans-serif;color:#505050}.swagger-ui .model-deprecated-warning{font-size:16px;font-weight:600;margin-right:1em;font-family:sans-serif;color:#f93e3e}.swagger-ui span>span.model .brace-close{padding:0 0 0 10px}.swagger-ui .prop-name{display:inline-block;margin-right:1em}.swagger-ui .prop-type{color:#55a}.swagger-ui .prop-enum{display:block}.swagger-ui .prop-format{color:#606060}.swagger-ui .servers>label{font-size:12px;margin:-20px 15px 0 0;font-family:sans-serif;color:#3b4151}.swagger-ui .servers>label select{min-width:130px;max-width:100%}.swagger-ui .servers h4.message{padding-bottom:2em}.swagger-ui .servers table tr{width:30em}.swagger-ui .servers table td{display:inline-block;max-width:15em;vertical-align:middle;padding-top:10px;padding-bottom:10px}.swagger-ui .servers table td:first-of-type{padding-right:2em}.swagger-ui .servers table td input{width:100%;height:100%}.swagger-ui .servers .computed-url{margin:2em 0}.swagger-ui .servers .computed-url code{display:inline-block;padding:4px;font-size:16px;margin:0 1em}.swagger-ui .servers-title{font-size:12px;font-weight:700}.swagger-ui .operation-servers h4.message{margin-bottom:2em}.swagger-ui table{width:100%;padding:0 10px;border-collapse:collapse}.swagger-ui table.model tbody tr td{padding:0;vertical-align:top}.swagger-ui table.model tbody tr td:first-of-type{width:174px;padding:0 0 0 2em}.swagger-ui table.headers td{font-size:12px;font-weight:300;vertical-align:middle;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui table tbody tr td{padding:10px 0 0;vertical-align:top}.swagger-ui table tbody tr td:first-of-type{max-width:20%;min-width:6em;padding:10px 0}.swagger-ui table thead tr td,.swagger-ui table thead tr th{font-size:12px;font-weight:700;padding:12px 0;text-align:left;border-bottom:1px solid rgba(59,65,81,.2);font-family:sans-serif;color:#3b4151}.swagger-ui .parameters-col_description{width:99%;margin-bottom:2em}.swagger-ui .parameters-col_description input[type=text]{width:100%;max-width:340px}.swagger-ui .parameters-col_description select{border-width:1px}.swagger-ui .parameter__name{font-size:16px;font-weight:400;margin-right:.75em;font-family:sans-serif;color:#3b4151}.swagger-ui .parameter__name.required{font-weight:700}.swagger-ui .parameter__name.required:after{font-size:10px;position:relative;top:-6px;padding:5px;content:"required";color:rgba(255,0,0,.6)}.swagger-ui .parameter__extension,.swagger-ui .parameter__in{font-size:12px;font-style:italic;font-family:monospace;font-weight:600;color:grey}.swagger-ui .parameter__deprecated{font-size:12px;font-style:italic;font-family:monospace;font-weight:600;color:red}.swagger-ui .parameter__empty_value_toggle{font-size:13px;padding-top:5px;padding-bottom:12px}.swagger-ui .parameter__empty_value_toggle input{margin-right:7px}.swagger-ui .parameter__empty_value_toggle.disabled{opacity:.7}.swagger-ui .table-container{padding:20px}.swagger-ui .response-col_description{width:99%}.swagger-ui .response-col_links{min-width:6em}.swagger-ui .topbar{padding:10px 0;background-color:#1b1b1b}.swagger-ui .topbar .topbar-wrapper,.swagger-ui .topbar a{display:flex;align-items:center}.swagger-ui .topbar a{font-size:1.5em;font-weight:700;flex:1;max-width:300px;text-decoration:none;font-family:sans-serif;color:#fff}.swagger-ui .topbar a span{margin:0;padding:0 10px}.swagger-ui .topbar .download-url-wrapper{display:flex;flex:3;justify-content:flex-end}.swagger-ui .topbar .download-url-wrapper input[type=text]{width:100%;margin:0;border:2px solid #62a03f;border-radius:4px 0 0 4px;outline:none}.swagger-ui .topbar .download-url-wrapper .select-label{display:flex;align-items:center;width:100%;max-width:600px;margin:0;color:#f0f0f0}.swagger-ui .topbar .download-url-wrapper .select-label span{font-size:16px;flex:1;padding:0 10px 0 0;text-align:right}.swagger-ui .topbar .download-url-wrapper .select-label select{flex:2;width:100%;border:2px solid #62a03f;outline:none;box-shadow:none}.swagger-ui .topbar .download-url-wrapper .download-url-button{font-size:16px;font-weight:700;padding:4px 30px;border:none;border-radius:0 4px 4px 0;background:#62a03f;font-family:sans-serif;color:#fff}.swagger-ui .info{margin:50px 0}.swagger-ui .info hgroup.main{margin:0 0 20px}.swagger-ui .info hgroup.main a{font-size:12px}.swagger-ui .info pre{font-size:14px}.swagger-ui .info li,.swagger-ui .info p,.swagger-ui .info table{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .info h1,.swagger-ui .info h2,.swagger-ui .info h3,.swagger-ui .info h4,.swagger-ui .info h5{font-family:sans-serif;color:#3b4151}.swagger-ui .info a{font-size:14px;transition:all .4s;font-family:sans-serif;color:#4990e2}.swagger-ui .info a:hover{color:#1f69c0}.swagger-ui .info>div{margin:0 0 5px}.swagger-ui .info .base-url{font-size:12px;font-weight:300!important;margin:0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .info .title{font-size:36px;margin:0;font-family:sans-serif;color:#3b4151}.swagger-ui .info .title small{font-size:10px;position:relative;top:-5px;display:inline-block;margin:0 0 0 5px;padding:2px 4px;vertical-align:super;border-radius:57px;background:#7d8492}.swagger-ui .info .title small pre{margin:0;padding:0;font-family:sans-serif;color:#fff}.swagger-ui .auth-btn-wrapper{display:flex;padding:10px 0;justify-content:center}.swagger-ui .auth-btn-wrapper .btn-done{margin-right:1em}.swagger-ui .auth-wrapper{display:flex;flex:1;justify-content:flex-end}.swagger-ui .auth-wrapper .authorize{padding-right:20px;margin-right:10px}.swagger-ui .auth-container{margin:0 0 10px;padding:10px 20px;border-bottom:1px solid #ebebeb}.swagger-ui .auth-container:last-of-type{margin:0;padding:10px 20px;border:0}.swagger-ui .auth-container h4{margin:5px 0 15px!important}.swagger-ui .auth-container .wrapper{margin:0;padding:0}.swagger-ui .auth-container input[type=password],.swagger-ui .auth-container input[type=text]{min-width:230px}.swagger-ui .auth-container .errors{font-size:12px;padding:10px;border-radius:4px;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .scopes h2{font-size:14px;font-family:sans-serif;color:#3b4151}.swagger-ui .scope-def{padding:0 0 20px}.swagger-ui .errors-wrapper{margin:20px;padding:10px 20px;-webkit-animation:scaleUp .5s;animation:scaleUp .5s;border:2px solid #f93e3e;border-radius:4px;background:rgba(249,62,62,.1)}.swagger-ui .errors-wrapper .error-wrapper{margin:0 0 10px}.swagger-ui .errors-wrapper .errors h4{font-size:14px;margin:0;font-family:monospace;font-weight:600;color:#3b4151}.swagger-ui .errors-wrapper .errors small{color:#606060}.swagger-ui .errors-wrapper hgroup{display:flex;align-items:center}.swagger-ui .errors-wrapper hgroup h4{font-size:20px;margin:0;flex:1;font-family:sans-serif;color:#3b4151}@-webkit-keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scaleUp{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.swagger-ui .Resizer.vertical.disabled{display:none}.swagger-ui .markdown p,.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown p,.swagger-ui .renderedMarkdown pre{margin:1em auto}.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown pre{color:#000;font-weight:400;white-space:pre-wrap;background:none;padding:0}.swagger-ui .markdown code,.swagger-ui .renderedMarkdown code{font-size:14px;padding:5px 7px;border-radius:4px;background:rgba(0,0,0,.05);font-family:monospace;font-weight:600;color:#9012fe}.swagger-ui .markdown pre>code,.swagger-ui .renderedMarkdown pre>code{display:block} - -/*# sourceMappingURL=swagger-ui.css.map*/ \ No newline at end of file diff --git a/docs/api-adv/assemblies/index.html b/docs/api-adv/assemblies/index.html index 6e3bf8d..fb641cb 100644 --- a/docs/api-adv/assemblies/index.html +++ b/docs/api-adv/assemblies/index.html @@ -1,15 +1,12 @@ -Assemblies | Assemblies |

Assemblies

This page describes the APIs Onshape provides for working with assemblies.

📘 Notes

\ No newline at end of file diff --git a/docs/api-adv/associativity/index.html b/docs/api-adv/associativity/index.html index dee79cb..01c811a 100644 --- a/docs/api-adv/associativity/index.html +++ b/docs/api-adv/associativity/index.html @@ -1,8 +1,8 @@ -Associativity |

Associativity

Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be:

  1. Read the tessellated model data.
  2. Select the face of interest.
  3. Store the Face ID and Document Microversion ID for the face.
  4. [ user changes model ]
  5. Call the REST API to translate from the known Face ID to an ID in the new model.
  6. Re-apply application-specific data to the face(s) in the new model. Note that a face may become zero, one or multiple faces in the new model, depending on what changes the user made.

Associativity Example

  1. Create a cube in Onshape:
    image alt text
  2. Get the document microversion ID from the URL: https://cad.onshape.com/api/d/<docid>/w/<wid>/microversionId.
  3. Use the appropriate REST API to get the tessellated faces (getPartStudioFaces) +Associativity |

    Associativity

    Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be:

    1. Read the tessellated model data.
    2. Select the face of interest.
    3. Store the Face ID and Document Microversion ID for the face.
    4. [ user changes model ]
    5. Call the REST API to translate from the known Face ID to an ID in the new model.
    6. Re-apply application-specific data to the face(s) in the new model. Note that a face may become zero, one or multiple faces in the new model, depending on what changes the user made.

    Associativity Example

    1. Create a cube in Onshape:
      image alt text
    2. Get the document microversion ID from the URL: https://cad.onshape.com/api/d/<docid>/w/<wid>/microversionId.
    3. Use the appropriate REST API to get the tessellated faces (getPartStudioFaces) and edges (getPartStudioEdges}. Note the ids:
      • Part ID: JHD
      • Front face ID: JHO
      • Top edge of the front face ID: JHd
      • Right edge of the top face ID: JHt
    4. Split cube with the Front plane and translate the IDs:

    image alt text

    POST

    https://cad.onshape.com/api/partstudios/d/<docid>/w/<wid>/e/<eid>/idtranslations
     

    Body:

    {
       "sourceDocumentMicroversion" : "47e75ab2ee8b4356a76ebd47",
    @@ -54,4 +54,4 @@
         ],
         "targetDocumentMicroversion": "52aa74d34b624f3aaef33204"
     }
    -
    \ No newline at end of file +
\ No newline at end of file diff --git a/docs/api-adv/billing/index.html b/docs/api-adv/billing/index.html index a1749dc..b16ad5a 100644 --- a/docs/api-adv/billing/index.html +++ b/docs/api-adv/billing/index.html @@ -1,14 +1,15 @@ -Billing | Billing |

Billing

This document describes APIs that will allow partners to interact with the Onshape billing system.

Please address questions to “api-support@onshape.com” for the fastest response.

Overview

All billing is done through “plans” that are created in the Developer Portal. A “plan” has the following attributes:

Name (also called SKU)A unique (within your company) plan name
DescriptionA user-visible description of the plan
AmountThe cost of the plan (may be one-time or recurring, depending on the type)
TypeMonthly, One-time or Consumable

Onshape defines three kinds of plans:

Plan typeDescription
Recurring +Name (also called SKU) A unique (within your company) plan name Description A user-visible description of the plan Amount The cost of the plan (may be one-time or recurring, depending on the type) Type Monthly, One-time or Consumable Onshape defines three kinds of plans:">

Billing

This document describes APIs that will allow partners to interact with the Onshape billing system.

Please address questions to “api-support@onshape.com” for the fastest response.

Overview

All billing is done through “plans” that are created in the Developer Portal. A “plan” has the following attributes:

Name (also called SKU)A unique (within your company) plan name
DescriptionA user-visible description of the plan
AmountThe cost of the plan (may be one-time or recurring, depending on the type)
TypeMonthly, One-time or Consumable

Onshape defines three kinds of plans:

Plan typeDescription
Recurring (Monthly Subscription)A plan that is renewed monthly at a fixed cost. All Apps in the app store must have a Free monthly plan (which is created by default), and may have additional paid plans.
One-timeA plan that is purchased once (not renewed monthly). A user may purchase these multiple times.
ConsumableA plan that represents a consumable unit, such as "hours of rendering" or “simulation runs”. Consumable plans are not fully implemented at this time, but the consumable functionality can be implemented using One-time Purchase plans as described below.

Users may purchase plans through the App Store interface. In addition, if your application has the OAuth Purchase Scope, your application can initiate “in-app” purchases by calling Onshape to request a purchase.

The basic steps for interacting with Onshape Billing:

  1. Define one or more plans using the Developer Portal interface
  2. Use the Onshape API to determine the current user’s plan
  3. Provide features and/or limits based on the current plan

Using the Onshape Billing API

GET /api/accounts/purchases

Returns a list of purchase made by the current user for plans owned by the current application. Use this information to determine what capabilities or features the user is entitled to use.

DELETE /api/accounts/purchases/<purchase id>

Cancel a recurring purchase.

POST /api/accounts/purchases/<purchase id>/consume

Indicate the use of a consumable. (Not fully implemented at this time)

GET /api/billing/plans/client/<client id>

Get a list of the billing plans defined for this client.

Initiating a purchase from an application (in-app purchases)

To initiate a purchase of a subscription or one time item you must set the browser’s location to particular URL within the Onshape stack:

https://cad.onshape.com/billing/purchase?redirectUri=RRRR&clientId=CCCC&sku=SSSS&userId=UUUU

Each of the query parameters should be URL encoded. The clientId is your application’s OAuth Client ID, the sku is the name/sku field for an item (you can find this in the developer portal or it’s retrievable through the /api/billing/plans REST endpoints). The user Id should be the Onshape user Id for the current user and is available through the /api/users/session REST endpoint. The redirectUri is the URI the user will be returned to within your website when the purchase is finished.

When the browser’s location is changed to this pattern the Onshape stack will serve content to confirm the users identity, confirm the details of what is being purchased (or obtained if the item is free) and then after the user agrees to the purchase will confirm the transaction (with our payment processor if the item is not free) and then redirect the user back to the supplied redirectUri (the browser location will be changed to the redirectUri). Additionally Onshape will add a success=true or success=false query parameter to the redirectURI indicating whether the user completed successfully (payment was taken if required etc.) or failed, either due to cancelling the purchase or an issue with payment.

When the browser fetches the redirectUri your application must call back through the /api/account/purchases API to get confirmation of the purchase - do NOT assume that a fetch of the redirectUri with a success=true query parameter actually indicates a purchase has occurred. Query the Onshape stack with the /api/account/purchases API to ensure that the required item has actually been bought.

Consumable Items

A detailed description of the interface for managing consumable purchases will be provided shortly. You can use one-time plans to achieve similar results:

  1. Define a one-time purchase plan with a description indicating the nature of the purchase, for example:

    RENDER-10 Ten rendering hours $100

  2. Keep track of the number of hours that the user has consumed. You can store and retrieve this information in Onshape using the following APIs. These APIs allow you to store and retrieve arbitrary information on a per-user basis.

    POST /applications/clients/:cid/settings/users/:uid -GET /applications/clients/:cid/settings/users/:uid

  3. Check the number of available “units” by getting the purchases and the record of consumables. Be sure to include UI in your application that the user can use to see their remaining quantity.

  4. Alternately, you can store the consumption data in your own system; you do not need to use the Onshape API to manage that data.

Onshape intends to provide a richer set of APIs that help track the purchase and consumption of consumables in the near future.

Other billing models

You can use these mechanisms to implement other models. For example, a time-limited trial could be implemented by scanning purchases for the first “purchase” and denying service if it is more than a defined number of days in the past. A “fixed number of uses per month” could be implemented as a monthly subscription, string usage data with the settings API, and denying service after a fixed number of uses.

Samples

Onshape will provide sample code for both desktop and integrated applications demonstrating the use of the billing APIs and workflow. If you are subscribed to the Onshape Github Partner group, you will have access to those samples as soon as they are posted.

Testing

Please contact api-support@onshape.com to discuss details of testing billing & subscriptions.

\ No newline at end of file +GET /applications/clients/:cid/settings/users/:uid

  • Check the number of available “units” by getting the purchases and the record of consumables. Be sure to include UI in your application that the user can use to see their remaining quantity.

  • Alternately, you can store the consumption data in your own system; you do not need to use the Onshape API to manage that data.

  • Onshape intends to provide a richer set of APIs that help track the purchase and consumption of consumables in the near future.

    Other billing models

    You can use these mechanisms to implement other models. For example, a time-limited trial could be implemented by scanning purchases for the first “purchase” and denying service if it is more than a defined number of days in the past. A “fixed number of uses per month” could be implemented as a monthly subscription, string usage data with the settings API, and denying service after a fixed number of uses.

    Samples

    Onshape will provide sample code for both desktop and integrated applications demonstrating the use of the billing APIs and workflow. If you are subscribed to the Onshape Github Partner group, you will have access to those samples as soon as they are posted.

    Testing

    Please contact api-support@onshape.com to discuss details of testing billing & subscriptions.

    \ No newline at end of file diff --git a/docs/api-adv/configs/index.html b/docs/api-adv/configs/index.html index d1e1f21..5022cff 100644 --- a/docs/api-adv/configs/index.html +++ b/docs/api-adv/configs/index.html @@ -1,9 +1,8 @@ -Configurations |

    Configurations

    This page describes the APIs Onshape provides for working with Configurations.

    You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing. You can also create your own Configurations for an Assembly, regardless of any existing Part Studio Configurations. Assembly Configurations work the same way as Part Studio Configurations, but are limited to configuring Mates (not Mate connectors), instances, and patterns.

    📘 Notes

    • This page provides sample code as curls. See the curl documentation for more information.
    • All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.
    • This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as DWVEM Please see API Guide: API Intro for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces ({}) in your API calls.
    • For Enterprise accounts, replace cad in all Onshape URLs with your company domain. +Configurations |

      Configurations

      This page describes the APIs Onshape provides for working with Configurations.

      You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing. You can also create your own Configurations for an Assembly, regardless of any existing Part Studio Configurations. Assembly Configurations work the same way as Part Studio Configurations, but are limited to configuring Mates (not Mate connectors), instances, and patterns.

      📘 Notes

      • This page provides sample code as curls. See the curl documentation for more information.
      • All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.
      • This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as DWVEM Please see API Guide: API Intro for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces ({}) in your API calls.
      • For Enterprise accounts, replace cad in all Onshape URLs with your company domain. https://cad.onshape.com > https://companyName.onshape.com

      Endpoints

      • Element/getConfiguration: Get the configuration data for a Part Studio or Assembly.
        curl -X 'GET' \
             'https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configuration' \
             -H 'Accept: application/json;charset=UTF-8; qs=0.09' \
        @@ -143,4 +142,4 @@
             -H 'Accept: */*' \
             -H 'Authorization: Basic CREDENTIALS' \
         
      • This endpoint returns a redirect URL. Navigate to the returned URL in your browser to download the export.
        • Hint: The URL will look something like this, but with different IDs:
        https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851/parasolid?version=0&includeExportIds=false&configuration=List_izOjbm5HCRXEld%253D_500_mm&binaryExport=false
        -
      • Now we need to import our Parasolid to confirm the correct configuration was used. Open your document in the Onshape UI, click the Insert new tab button, and then select Import.
        Insert new tab menu with Import highlighted in Onshape UI
      • Navigate to the export you downloaded (with the .x_t extension) and import it into Onshape.
      • Use the measure tool to confirm the length of the imported drillbit is 500 mm.
        Measure tool in Onshape UI showing drill length as 500 mm
      • Workflow Video

        This video demonstrates how to complete the above tutorials in the Onshape API Explorer.

        Additional Resources

      \ No newline at end of file +
    • Now we need to import our Parasolid to confirm the correct configuration was used. Open your document in the Onshape UI, click the Insert new tab button, and then select Import.
      Insert new tab menu with Import highlighted in Onshape UI
    • Navigate to the export you downloaded (with the .x_t extension) and import it into Onshape.
    • Use the measure tool to confirm the length of the imported drillbit is 500 mm.
      Measure tool in Onshape UI showing drill length as 500 mm
    • Workflow Video

      This video demonstrates how to complete the above tutorials in the Onshape API Explorer.

      Additional Resources

    \ No newline at end of file diff --git a/docs/api-adv/drawings/index.html b/docs/api-adv/drawings/index.html index d78a5b4..40ec9c2 100644 --- a/docs/api-adv/drawings/index.html +++ b/docs/api-adv/drawings/index.html @@ -1,15 +1,12 @@ -Drawings | Drawings |

    Drawings

    This page describes the APIs Onshape provides for creating and manipulating Onshape drawings.

    📘 Notes

    1. Return to your document and see that the centerline has been added to the document at the snap points.
      drawing front view of a box with two holes with a centerline between the hole centers

    Additional Resources

    \ No newline at end of file diff --git a/docs/api-adv/errors/index.html b/docs/api-adv/errors/index.html index 4aab42d..a89ced4 100644 --- a/docs/api-adv/errors/index.html +++ b/docs/api-adv/errors/index.html @@ -1,11 +1,13 @@ -Response Codes | Response Codes |

    Response Codes

    This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we’ve provided a brief description of the response and recommended next steps.

    Success (2xx)

    The client call was successful.

    200 - OK

    The client call was successful. No action needed.

    204 - No Content

    The client call was successful, and there’s nothing to return in the response body. The empty response body cannot be parsed.

    Redirect (3xx)

    307 - Temporary Redirect

    The client call was successful, and a redirection URL was returned. Follow the URL provided in the response.

    Client Error (4xx)

    There’s an error with the client request. Find the error code below, and follow the instructions for resolution.

    400 - Bad Request

    The request cannot be processed by the server due a client-side error. This could be a malformed request syntax or other issue. Check the request parameters (GET and POST) and request body (POST) to determine the cause of the failure.

    401 - Unauthorized

    The request failed the authentication/authorization checks. This could mean that the client is not logged in, API keys are invalid, OAuth failed, etc. Make sure the client is authenticated.

    403 - Forbidden

    The client doesn’t have the correct permissions to perform this operation. Check that the API Keys or OAuth authentication have sufficient permissions to perform the operation. For example, POST operations typically require write scope; if the API Key was created with only read scope, the server will return a 403 error.

    You might also need to check document and user permissions. For more details, see Share Documents (for everyone) and Understanding and Administering Project Roles and Permission Schemes (for Enterprise users and administrators).

    404 - Not Found

    The server can’t find what the client is looking for. For example, a 404 error will be returned if the client tries to make a GET request for a document that doesn’t exist.

    405 - Method Not Allowed

    Use of that method is not supported. For example, you cannot perform a DELETE request on a document version, because versions are read-only. Only GET requests on document versions are allowed.

    406 - Not Acceptable

    The server cannot provide a response for the media type requested. See https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1.

    409 - Conflict

    The client call includes duplicate values, causing a conflict. Modify the request to remove any conflicting values.

    415 - Media Type Not Supported

    The client call includes unsupported data types or invalid JSON. Review the client code. When performing data imports and exports, follow all Translation guidelines to ensure all media and file types are supported.

    429 - Too Many Requests

    The client sent too many requests to a particular endpoint in a given time window. The number of requests allowed per time window vary and are subject to change. Onshape does not publish this information. If the client receives HTTP 429 responses, delay and then retry, or reduce its request rate.

    499 - Timeout

    This call is taking too long. Please try again later.

    Server Error (5xx)

    There’s an error with the Onshape servers. Find the error code below, and follow the instructions for resolution.

    500 - Internal Server Error

    The request resulted in an error. Set a limit for the number of retries, and if the request continues to fail, reach out to support.

    503 - Service Unavailable

    Something is wrong with the Onshape servers. Retry after the delay specified in the response. Set a limit for the number of retries, and if the request continues to fail, reach out to support.

    \ No newline at end of file +204 - No Content The client call was successful, and there’s nothing to return in the response body. The empty response body cannot be parsed.">

    Response Codes

    This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we’ve provided a brief description of the response and recommended next steps.

    Success (2xx)

    The client call was successful.

    200 - OK

    The client call was successful. No action needed.

    204 - No Content

    The client call was successful, and there’s nothing to return in the response body. The empty response body cannot be parsed.

    Redirect (3xx)

    307 - Temporary Redirect

    The client call was successful, and a redirection URL was returned. Follow the URL provided in the response.

    Client Error (4xx)

    There’s an error with the client request. Find the error code below, and follow the instructions for resolution.

    400 - Bad Request

    The request cannot be processed by the server due a client-side error. This could be a malformed request syntax or other issue. Check the request parameters (GET and POST) and request body (POST) to determine the cause of the failure.

    401 - Unauthorized

    The request failed the authentication/authorization checks. This could mean that the client is not logged in, API keys are invalid, OAuth failed, etc. Make sure the client is authenticated.

    403 - Forbidden

    The client doesn’t have the correct permissions to perform this operation. Check that the API Keys or OAuth authentication have sufficient permissions to perform the operation. For example, POST operations typically require write scope; if the API Key was created with only read scope, the server will return a 403 error.

    You might also need to check document and user permissions. For more details, see Share Documents (for everyone) and Understanding and Administering Project Roles and Permission Schemes (for Enterprise users and administrators).

    404 - Not Found

    The server can’t find what the client is looking for. For example, a 404 error will be returned if the client tries to make a GET request for a document that doesn’t exist.

    405 - Method Not Allowed

    Use of that method is not supported. For example, you cannot perform a DELETE request on a document version, because versions are read-only. Only GET requests on document versions are allowed.

    406 - Not Acceptable

    The server cannot provide a response for the media type requested. See https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1.

    409 - Conflict

    The client call includes duplicate values, causing a conflict. Modify the request to remove any conflicting values.

    415 - Media Type Not Supported

    The client call includes unsupported data types or invalid JSON. Review the client code. When performing data imports and exports, follow all Translation guidelines to ensure all media and file types are supported.

    429 - Too Many Requests

    The client sent too many requests to a particular endpoint in a given time window. The number of requests allowed per time window vary and are subject to change. Onshape does not publish this information. If the client receives HTTP 429 responses, delay and then retry, or reduce its request rate.

    499 - Timeout

    This call is taking too long. Please try again later.

    Server Error (5xx)

    There’s an error with the Onshape servers. Find the error code below, and follow the instructions for resolution.

    500 - Internal Server Error

    The request resulted in an error. Set a limit for the number of retries, and if the request continues to fail, reach out to support.

    503 - Service Unavailable

    Something is wrong with the Onshape servers. Retry after the delay specified in the response. Set a limit for the number of retries, and if the request continues to fail, reach out to support.

    \ No newline at end of file diff --git a/docs/api-adv/featureaccess/index.html b/docs/api-adv/featureaccess/index.html index df83062..b434e2c 100644 --- a/docs/api-adv/featureaccess/index.html +++ b/docs/api-adv/featureaccess/index.html @@ -1,15 +1,12 @@ -Features | Features |

    Features

    This page describes the APIs Onshape provides for creating and manipulating features and the Feature List in a Part Studio.

    📘 Notes

    \ No newline at end of file diff --git a/docs/api-adv/fs/index.html b/docs/api-adv/fs/index.html index 6b79466..754500f 100644 --- a/docs/api-adv/fs/index.html +++ b/docs/api-adv/fs/index.html @@ -1,15 +1,12 @@ -Evaluating FeatureScript | Evaluating FeatureScript |

    Evaluating FeatureScript

    This page describes some of the APIs Onshape provides for evaluating FeatureScript.

    📘 Notes

    \ No newline at end of file diff --git a/docs/api-adv/index.html b/docs/api-adv/index.html index 6bcc24e..cca5769 100644 --- a/docs/api-adv/index.html +++ b/docs/api-adv/index.html @@ -1,3 +1 @@ -API Guides |
    \ No newline at end of file +API Guides |
    \ No newline at end of file diff --git a/docs/api-adv/index.xml b/docs/api-adv/index.xml index 87efb0c..bec9b6a 100644 --- a/docs/api-adv/index.xml +++ b/docs/api-adv/index.xml @@ -1,2934 +1,21 @@ -– API Guideshttps://onshape-public.github.io/docs/api-adv/Recent content in API Guides onHugo -- gohugo.ioen-usThu, 15 Aug 2024 00:00:00 +0000Docs: Assemblieshttps://onshape-public.github.io/docs/api-adv/assemblies/Tue, 13 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/assemblies/ -<p>This page describes the APIs Onshape provides for working with assemblies.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/createInstance">Assembly/createInstance</a>: Insert an instance of a part, sketch, assembly, or Part Studio into an assembly: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/assemblies/d/{targetDid}/w/{targetWid}/e/{targetEid}/instances&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; --d &#39;{ -&#34;configuration&#34;: &#34;string&#34;, -&#34;documentId&#34;: &#34;{sourceDid}&#34;, -&#34;elementId&#34;: &#34;{sourceEid}&#34;, -&#34;featureId&#34;: &#34;string&#34;, -&#34;includePartTypes&#34;: [ -&#34;PARTS&#34; -], -&#34;isAssembly&#34;: true, -&#34;isHidden&#34;: true, -&#34;isSuppressed&#34;: true, -&#34;isWholePartStudio&#34;: true, -&#34;microversionId&#34;: &#34;string&#34;, -&#34;partId&#34;: &#34;string&#34;, -&#34;partNumber&#34;: &#34;string&#34;, -&#34;revision&#34;: &#34;string&#34;, -&#34;versionId&#34;: &#34;{sourceEid}&#34; -}&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="insert-a-part-into-an-assembly">Insert a part into an assembly</h3> -<ol> -<li>Open the Part Studio that contains the part you want to insert into an assembly. Make a note of the following in the URL: -<ul> -<li><code>documentId</code> - we&rsquo;ll refer to this as our <code>sourceDid</code> for this example</li> -<li><code>elementId</code> of the Part Studio that contains the part - this is our <code>sourceEid</code></li> -<li><code>versionId</code> - this is our <code>sourceVId</code>, if one exists</li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> endpoint to get the part&rsquo;s <code>partId</code>: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/parts/d/{did}/w/{wid}/e/{eid}?withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>Now open the assembly you want to insert the part into. Make a note of the following from the URL: -<ul> -<li><code>documentId</code> - we&rsquo;ll refer to this as our <code>targetDid</code></li> -<li><code>workspaceId</code> - this is our <code>targetWId</code></li> -<li><code>elementId</code> of the assembly - this is our <code>targetEid</code></li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/createInstance">Assembly/createInstance</a> endpoint on the assembly to insert an instance of the part into the assembly: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/assemblies/d/{targetDid}/w/{targetWid}/e/{targetEid}/instances&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;documentId&#34;: &#34;{sourceDid}&#34;, -&#34;elementId&#34;: &#34;{sourceEid}&#34;, -&#34;includePartTypes&#34;: [ -&#34;PARTS&#34; -], -&#34;partId&#34;: &#34;{partId}&#34; -}&#39; -</code></pre><ul> -<li>Note: you can add <code>&quot;versionId&quot;: &quot;{sourceVid}&quot;</code> to the request body if needed.</li> -</ul> -</li> -<li>Refresh your assembly and confirm the part is included.</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly">API Explorer: Assemblies</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/assembly.htm">Onshape Help: Assemblies</a></li> -</ul>Docs: Associativityhttps://onshape-public.github.io/docs/api-adv/associativity/Mon, 18 May 2020 20:28:26 -0400https://onshape-public.github.io/docs/api-adv/associativity/ -<p>Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be:</p> -<ol> -<li>Read the tessellated model data.</li> -<li>Select the face of interest.</li> -<li>Store the Face ID and Document Microversion ID for the face.</li> -<li>[ user changes model ]</li> -<li>Call the REST API to translate from the known Face ID to an ID in the new model.</li> -<li>Re-apply application-specific data to the face(s) in the new model. Note that a face may become zero, one or multiple faces in the new model, depending on what changes the user made.</li> -</ol> -<h2 id="associativity-example">Associativity Example</h2> -<ol> -<li>Create a cube in Onshape:</br> -<img src="https://onshape-public.github.io/images/associativityimage03.png" alt="image alt text"></li> -<li>Get the document microversion ID from the URL: <code>https://cad.onshape.com/api/d/&lt;docid&gt;/w/&lt;wid&gt;/microversionId</code>.</li> -<li>Use the appropriate REST API to get the tessellated faces (<code>getPartStudioFaces</code>) -and edges (<code>getPartStudioEdges</code>}. Note the ids: -<ul> -<li>Part ID: <code>JHD</code></li> -<li>Front face ID: <code>JHO</code></li> -<li>Top edge of the front face ID: <code>JHd</code></li> -<li>Right edge of the top face ID: <code>JHt</code></li> -</ul> -</li> -<li>Split cube with the Front plane and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage00.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span> ] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;SPLIT&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>, <span style="color:#a50">&#34;JIH&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHO&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHd&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;SPLIT&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JI5&#34;</span>, <span style="color:#a50">&#34;JI9&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;78bc7f3fcf82475085c2f3ab&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><ol start="4"> -<li>Delete one of the parts, and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage01.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span>] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;FAILED_TO_RESOLVE&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;FAILED_TO_RESOLVE&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JI5&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;52aa74d34b624f3aaef33204&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><ol start="5"> -<li>Roll back the delete and the split, and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage02.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span>] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHO&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHd&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHt&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;52aa74d34b624f3aaef33204&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div>Docs: Billinghttps://onshape-public.github.io/docs/api-adv/billing/Mon, 18 May 2020 20:29:36 -0400https://onshape-public.github.io/docs/api-adv/billing/ -<p>This document describes APIs that will allow partners to interact with the Onshape billing system.</p> -<p>Please address questions to &ldquo;<a href="mailto:api-support@onshape.com">api-support@onshape.com</a>&rdquo; for the fastest response.</p> -<h2 id="overview">Overview</h2> -<p>All billing is done through &ldquo;plans&rdquo; that are created in the Developer Portal. A “plan” has the following attributes:</p> -<table> -<tr> -<td>Name (also called SKU)</td> -<td>A unique (within your company) plan name</td> -</tr> -<tr> -<td>Description</td> -<td>A user-visible description of the plan</td> -</tr> -<tr> -<td>Amount</td> -<td>The cost of the plan (may be one-time or recurring, depending on the type)</td> -</tr> -<tr> -<td>Type</td> -<td>Monthly, One-time or Consumable</td> -</tr> -</table> -<p>Onshape defines three kinds of plans:</p> -<table> -<tr> -<td>Plan type</td> -<td>Description</td> -</tr> -<tr> -<td>Recurring -(Monthly Subscription)</td> -<td>A plan that is renewed monthly at a fixed cost. All Apps in the app store must have a Free monthly plan (which is created by default), and may have additional paid plans.</td> -</tr> -<tr> -<td>One-time</td> -<td>A plan that is purchased once (not renewed monthly). A user may purchase these multiple times.</td> -</tr> -<tr> -<td>Consumable</td> -<td>A plan that represents a consumable unit, such as "hours of rendering" or “simulation runs”. Consumable plans are not fully implemented at this time, but the consumable functionality can be implemented using One-time Purchase plans as described below.</td> -</tr> -</table> -<p>Users may purchase plans through the App Store interface. In addition, if your application has the OAuth Purchase Scope, your application can initiate &ldquo;in-app&rdquo; purchases by calling Onshape to request a purchase.</p> -<p>The basic steps for interacting with Onshape Billing:</p> -<ol> -<li>Define one or more plans using the Developer Portal interface</li> -<li>Use the Onshape API to determine the current user’s plan</li> -<li>Provide features and/or limits based on the current plan</li> -</ol> -<h2 id="using-the-onshape-billing-api">Using the Onshape Billing API</h2> -<p><code>GET /api/accounts/purchases</code></p> -<p>Returns a list of purchase made by the current user for plans owned by the current application. Use this information to determine what capabilities or features the user is entitled to use.</p> -<p><code>DELETE /api/accounts/purchases/&lt;purchase id&gt;</code></p> -<p>Cancel a recurring purchase.</p> -<p><code>POST /api/accounts/purchases/&lt;purchase id&gt;/consume</code></p> -<p>Indicate the use of a consumable. (Not fully implemented at this time)</p> -<p><code>GET /api/billing/plans/client/&lt;client id&gt;</code></p> -<p>Get a list of the billing plans defined for this client.</p> -<h2 id="initiating-a-purchase-from-an-application-in-app-purchases">Initiating a purchase from an application (in-app purchases)</h2> -<p>To initiate a purchase of a subscription or one time item you must set the browser’s location to particular URL within the Onshape stack:</p> -<p><code>https://cad.onshape.com/billing/purchase?redirectUri=RRRR&amp;clientId=CCCC&amp;sku=SSSS&amp;userId=UUUU</code></p> -<p>Each of the query parameters should be URL encoded. The clientId is your application’s OAuth Client ID, the sku is the name/sku field for an item (you can find this in the developer portal or it’s retrievable through the /api/billing/plans REST endpoints). The user Id should be the Onshape user Id for the current user and is available through the /api/users/session REST endpoint. The redirectUri is the URI the user will be returned to within your website when the purchase is finished.</p> -<p>When the browser’s location is changed to this pattern the Onshape stack will serve content to confirm the users identity, confirm the details of what is being purchased (or obtained if the item is free) and then after the user agrees to the purchase will confirm the transaction (with our payment processor if the item is not free) and then redirect the user back to the supplied redirectUri (the browser location will be changed to the redirectUri). Additionally Onshape will add a <code>success=true</code> or <code>success=false</code> query parameter to the redirectURI indicating whether the user completed successfully (payment was taken if required etc.) or failed, either due to cancelling the purchase or an issue with payment.</p> -<p>When the browser fetches the redirectUri your application must call back through the <code>/api/account/purchases</code> API to get confirmation of the purchase - do NOT assume that a fetch of the redirectUri with a <code>success=true</code> query parameter actually indicates a purchase has occurred. Query the Onshape stack with the <code>/api/account/purchases</code> API to ensure that the required item has actually been bought.</p> -<h2 id="consumable-items">Consumable Items</h2> -<p>A detailed description of the interface for managing consumable purchases will be provided shortly. You can use one-time plans to achieve similar results:</p> -<ol> -<li> -<p>Define a one-time purchase plan with a description indicating the nature of the purchase, for example:</p> -<p>RENDER-10 Ten rendering hours $100</p> -</li> -<li> -<p>Keep track of the number of hours that the user has consumed. You can store and retrieve this information in Onshape using the following APIs. These APIs allow you to store and retrieve arbitrary information on a per-user basis.</p> -<p>POST /applications/clients/:cid/settings/users/:uid -GET /applications/clients/:cid/settings/users/:uid</p> -</li> -<li> -<p>Check the number of available &ldquo;units&rdquo; by getting the purchases and the record of consumables. Be sure to include UI in your application that the user can use to see their remaining quantity.</p> -</li> -<li> -<p>Alternately, you can store the consumption data in your own system; you do not need to use the Onshape API to manage that data.</p> -</li> -</ol> -<p>Onshape intends to provide a richer set of APIs that help track the purchase and consumption of consumables in the near future.</p> -<h2 id="other-billing-models">Other billing models</h2> -<p>You can use these mechanisms to implement other models. For example, a time-limited trial could be implemented by scanning purchases for the first &ldquo;purchase&rdquo; and denying service if it is more than a defined number of days in the past. A “fixed number of uses per month” could be implemented as a monthly subscription, string usage data with the settings API, and denying service after a fixed number of uses.</p> -<h2 id="samples">Samples</h2> -<p>Onshape will provide sample code for both desktop and integrated applications demonstrating the use of the billing APIs and workflow. If you are subscribed to the Onshape Github Partner group, you will have access to those samples as soon as they are posted.</p> -<h2 id="testing">Testing</h2> -<p>Please contact <a href="mailto:api-support@onshape.com">api-support@onshape.com</a> to discuss details of testing billing &amp; subscriptions.</p>Docs: Configurationshttps://onshape-public.github.io/docs/api-adv/configs/Fri, 05 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/configs/ -<p>This page describes the APIs Onshape provides for working with <a href="https://cad.onshape.com/help/Content/configurations.htm">Configurations</a>.</p> -<p>You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing. You can also create your own Configurations for an Assembly, regardless of any existing Part Studio Configurations. Assembly Configurations work the same way as Part Studio Configurations, but are limited to configuring Mates (<em>not</em> Mate connectors), instances, and patterns.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a>: Get the configuration data for a Part Studio or Assembly. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/updateConfiguration">Element/updateConfiguration</a>: Update the configuration data for a Part Studio or Assembly. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ }&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/decodeConfiguration">Element/decodeConfiguration</a>: Process an encoded configuration file. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configurationencodings/{encodingId}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a>: Create an encoded map of configurations. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;{configValue}&#34; -} -] -}&#39; -</code></pre></li> -</ul> -<h3 id="encoded-configuration-strings">Encoded Configuration Strings</h3> -<p>The <a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a> and <a href="https://cad.onshape.com/glassworks/explorer/#/Element/decodeConfiguration">Element/decodeConfiguration</a> APIs convert parameters from JSON to a URL-encoded string in the following format: <code>&quot;configuration=parameterId%3DparameterValue&quot;</code></p> -<p>For example,</p> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;List_izOjbm5HCRXEld&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -} -</code></pre><p>encodes to:</p> -<pre tabindex="0"><code>&#34;configuration=List_izOjbm5HCRXEld%3D_500_mm&#34; -</code></pre><p>and:</p> -<pre tabindex="0"><code>&#34;configuration=List_izOjbm5HCRXEld%3DDefault&#34; -</code></pre><p>decodes to:</p> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;List_izOjbm5HCRXEld&#34;, -&#34;parameterValue&#34;: &#34;Default&#34; -} -] -} -</code></pre><h2 id="sample-workflows">Sample Workflows</h2> -<p>These sample workflows all build off one another. Completing all of the workflows will take you step-by-step through the process of getting Configuration information, encoding the information for use, and using the encoded configuration to create a configured export. You can also watch the <a href="#workflow-video">video</a> to see the entire workflow in the Glassworks API Explorer.</p> -<h3 id="get-a-configuration">Get a Configuration</h3> -<p>In this example, we&rsquo;ll use the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a> endpoint to get the Configuration information from a Part Studio.</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID.</li> -<li>Click the Configurations dropdown in the Features list, and observe that there are two options for the drillbit length, <code>250 mm</code> and <code>500 mm</code>. -</br></br><img src="https://onshape-public.github.io/images/configs-example-ui.png" alt=" " width=550></li> -<li>Set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a> endpoint to get the Configuration for the Part Studio. Don&rsquo;t forget to replace the URL parameters with the IDs from your copy of the document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/w/{wid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -<li>Review the Configuration information detailed in the response. You can see that the Part Studio contains one configuration (<code>Drill_Bit_Length</code>) with two options (<code>250 mm</code> and <code>500 mm</code>): -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTConfigurationResponse-2019&#34;, -&#34;currentConfiguration&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;namespace&#34;: &#34;&#34;, -&#34;nodeId&#34;: &#34;{nodeId1}&#34;, -&#34;value&#34;: &#34;Default&#34;, -&#34;enumName&#34;: &#34;{paramId_conf}&#34;, -&#34;parameterId&#34;: &#34;{paramId}&#34; -} -], -&#34;configurationParameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMConfigurationParameterEnum-105&#34;, -&#34;defaultValue&#34;: &#34;Default&#34;, -&#34;enumName&#34;: &#34;{enumName}&#34;, -&#34;namespace&#34;: &#34;&#34;, -&#34;options&#34;: [ -{ -&#34;btType&#34;: &#34;BTMEnumOption-592&#34;, -&#34;optionName&#34;: &#34;250 mm&#34;, -&#34;option&#34;: &#34;Default&#34;, -&#34;nodeId&#34;: &#34;{nodeId2}&#34; -}, -{ -&#34;btType&#34;: &#34;BTMEnumOption-592&#34;, -&#34;optionName&#34;: &#34;500 mm&#34;, -&#34;option&#34;: &#34;_500_mm&#34;, -&#34;nodeId&#34;: &#34;{nodeId3}&#34; -} -], -&#34;isCosmetic&#34;: false, -&#34;parameterId&#34;: &#34;{paramId}&#34;, -&#34;parameterName&#34;: &#34;Drill_Bit_Length&#34;, -&#34;nodeId&#34;: &#34;{nodeId4}&#34; -} -], -&#34;serializationVersion&#34;: &#34;1.2.0&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 2296 -} -</code></pre></li> -</ol> -<h3 id="encode-a-configuration-string">Encode a configuration string</h3> -<p>In this example, we&rsquo;ll encode a Configuration so it can be used as part of a translation (i.e., an export). Please read the <a href="#encoded-configuration-strings">Encoded Configuration Strings</a> section before beginning this example.</p> -<ol> -<li>This example builds off the previous one. Please complete the <a href="#get-a-configuration">Get a Part Studio Configuration</a> workflow to obtain the raw Configuration output for the Part Studio.</li> -<li>Set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a> endpoint. Don&rsquo;t forget to replace the URL parameters with the IDs from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ }&#39; -</code></pre></li> -<li>Now we need to create our JSON body for the request. Note the structure of the body: -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;string&#34;, -&#34;parameterValue&#34;: &#34;string&#34; -} -], -&#34;standardContentParametersId&#34;: &#34;string&#34; -} -</code></pre>Fill out the request body with our information: -<ul> -<li>We&rsquo;re not using a standard content part, so we can delete the second key/value pair.</li> -<li>The parameterId can be found in the response from the previous example. It usually begins with (<code>List_</code>)</li> -<li>For the parameter value, we&rsquo;ll enter one of our configuration options from the previous example. In this case, we&rsquo;ll use <code>_500_mm</code> to export a 500 mm drillbit part.</li> -</ul> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -} -</code></pre></li> -<li>Now we can make our call: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -}&#39; -</code></pre></li> -<li>The call responds with two values: the ID of the encoding, and the encoded configuration string. We can use this configuration string (returned in the <code>queryParam</code> field) any time we want to specify the 500 mm drillbit length. -<pre tabindex="0"><code>{ -&#34;encodedId&#34;: &#34;{encodedId}&#34;, -&#34;queryParam&#34;: &#34;configuration={configString}&#34; -} -</code></pre></li> -</ol> -<h3 id="export-a-configured-part">Export a configured part</h3> -<p>In this example, we will export a configured part. We have a drillbit with two configurations: <code>250 mm</code> and <code>500 mm</code> lengths. To export a 500 mm drillbit, we can specify the configuration as part of the export.</p> -<ol> -<li>This example builds off the previous two. Please complete this exercise after the <a href="#encode-a-configuration">Encode a configuration</a> workflow.</li> -<li>Next, set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportParasolid">PartStudio/exportParasolid</a> endpoint. Don&rsquo;t forget to replace the URL parameters with the IDs from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. Note that this endpoint includes an optional <code>configuration</code> parameter. This is where we&rsquo;ll enter the configuration string we found in the previous example. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/parasolid?version=0&amp;includeExportIds=false&amp;configuration={configString}&amp;binaryExport=false&#39; \ --H &#39;Accept: */*&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -<li>This endpoint returns a redirect URL. Navigate to the returned URL in your browser to download the export. -<ul> -<li>Hint: The URL will look something like this, but with different IDs:</li> -</ul> -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851/parasolid?version=0&amp;includeExportIds=false&amp;configuration=List_izOjbm5HCRXEld%253D_500_mm&amp;binaryExport=false -</code></pre></li> -<li>Now we need to import our Parasolid to confirm the correct configuration was used. Open your document in the Onshape UI, click the Insert new tab button, and then select Import. -</br><img src="https://onshape-public.github.io/images/configs-insert-menu.png" alt="Insert new tab menu with Import highlighted in Onshape UI" width=250></li> -<li>Navigate to the export you downloaded (with the <code>.x_t</code> extension) and import it into Onshape.</li> -<li>Use the measure tool to confirm the length of the imported drillbit is 500 mm. -</br><img src="https://onshape-public.github.io/images/configs-measure-tool.png" alt="Measure tool in Onshape UI showing drill length as 500 mm" width=400></li> -</ol> -<h2 id="workflow-video">Workflow Video</h2> -<p>This video demonstrates how to complete the above tutorials in the Onshape API Explorer. -</br></p> -<p> -<div class="wistia_responsive_padding" style="padding:77.08% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><iframe src="https://fast.wistia.net/embed/iframe/o4pvoyjwuk?seo=true&videoFoam=true" title="configs-export-example Video" allow="autoplay; fullscreen" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" msallowfullscreen width="100%" height="100%"></iframe></div></div> -<script src="https://fast.wistia.net/assets/external/E-v1.js" async></script> -</p> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element">API Explorer: Configurations</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/configurations.htm">Onshape Help: Configurations</a></li> -</ul>Docs: Drawingshttps://onshape-public.github.io/docs/api-adv/drawings/Thu, 12 Oct 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/drawings/ -<p>This page describes the APIs Onshape provides for creating and manipulating Onshape drawings.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<p>To create drawings, Onshape allows you to send all drawing data points and information through the API as part of the request body JSON.</p> -<p>The following endpoints are available:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Create a drawing</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON request body options from the BTDrawingParams schema&gt; -}&#39; -</code></pre>Specify the document in which to create the drawing in the URL, and pass any additional options as part of the request body. You can provide a name for the drawing, manipulate the drawing graphics area, specify a part or template to create the drawing from, and more. -<ul> -<li>See documentation for all available options in the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">API Explorer</a>.</li> -<li>For instructions on viewing the documentation for the request body schemas, see our <a href="https://onshape-public.github.io/docs/api-intro/explorer#view-request-body-docs">API Explorer</a> page. -Check out the <a href="#sample-workflows">Sample Workflows</a> section below for some practical examples.<p></br> -<img src="https://onshape-public.github.io/images/BTDrawingParamsSchema.png" alt="BTDrawingParams schema in the createDrawingAppElement endpoint"></br></p></li> -</ul> -</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Modify a drawing</a> -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Description of the modification.&#34;, -&#34;jsonRequests&#34;: [ -{ -&lt;JSON request body options from the jsonRequests schema&gt; -} -] -}&#39; -</code></pre>Specify the drawing to modify in the URL, and pass the information on the modification in the request body. Note that the <code>jsonRequests</code> schema is not defined in the Glassworks API Explorer; see the <a href="https://github.com/onshape-public/onshapedrawingjson">OnshapeDrawingJson</a> repository for this information, and check out the <a href="#sample-workflows">Sample Workflows</a> section below for some practical examples.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Get the drawing modification status</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/modify/status/{mrid} --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre>Provide the modification ID (from the <code>modifyDrawing</code> response body) to get the status of the modification.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Translate a drawing</a>: See the <a href="https://onshape-public.github.io/docs/api-adv/translation#export-a-drawing-as-a-json">Translations API Guide</a>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Get drawing translation formats</a>: See the <a href="https://onshape-public.github.io/docs/api-adv/translation#export-a-drawing-as-a-json">Translations API Guide</a>.</li> -</ul> -<h3 id="viewing-drawing-errors">Viewing drawing errors</h3> -<p>You can <a href="https://onshape-public.github.io/docs/api-adv/translation.md#export-a-drawing-as-a-json">export your drawing to a JSON</a> to find errors with your drawing. Each <code>view</code> in the JSON includes an <code>errorState</code> for reporting drawing errors.</p> -<h2 id="sample-app">Sample App</h2> -<p>Please see the <a href="https://github.com/onshape-public/onshape-ts-drawing-client">Onshape TypeScript Drawing Client</a> for a working example of using the Onshape Drawing APIs in an application.</p> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="create-a-drawing-from-a-part">Create a drawing from a part</h3> -<p>In this example, we&rsquo;ll create a drawing from the <strong>FLYWHEEL</strong> part in <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/v/405ba186c3a70e0227ab2941/e/6bed6b43463f6a46a37b4a22">this public document</a>.</p> -<ol> -<li>Create or open an Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with the document ID and workspace ID of your document (i.e., the <em>target</em> document), and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add the request body information: -<ul> -<li>Add <code>flywheelDrawing</code> as the <code>drawingName</code> field.</li> -<li>We must specify the <em>source</em> document&rsquo;s document and version IDs. Note that since our target document and source document are different, we use the <code>external</code> document and version ID fields.</li> -<li>We must also provide the ID of the part to create the drawing from, and the ID of the element (i.e., tab) in which the part lives. -</br> -(Hint: You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> to get a list of part IDs in an element.)</br> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;flywheelDrawing&#34;, -&#34;externalDocumentId&#34;: &#34;e60c4803eaf2ac8be492c18e&#34;, -&#34;externalDocumentVersionId&#34;: &#34;405ba186c3a70e0227ab2941&#34;, -&#34;elementId&#34;: &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;partId&#34;: &#34;JiD&#34; -}&#39; -</code></pre></li> -</ul> -</li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>flywheelDrawing</code> element containing the drawing: -</br><img src="https://onshape-public.github.io/images/flywheelDrawingExample1.png" alt="new drawing created from a part in an external document" width=650></li> -</ol> -<h3 id="create-a-drawing-from-a-template">Create a drawing from a template</h3> -<p>In this example, we&rsquo;ll create a drawing from the standard ANSI template in <a href="https://cad.onshape.com/documents/cbe6e776694549b5ba1a3e88/w/24d08acf10234dbc8d3ab585/e/17eef7862b224f6fb12cbc46">this public document</a>.</p> -<ol> -<li>Open any Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with the document ID and workspace ID of your document (i.e., the <em>target</em> document), and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add the request body information: -<ul> -<li>Add <code>templateAnsiDrawing</code> as the <code>drawingName</code> field.</li> -<li>We must specify the <em>source</em> document&rsquo;s document ID and workspace ID.</li> -<li>We must also provide the ID of the element (i.e., tab) in which the template lives.</li> -<li>Note that we use the <code>template</code> document, workspace, and element ID fields when referring to a specific template for drawing creation. -</br> -<pre tabindex="0"><code>curl &#39;https://cad.onshape.com/api/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json, text/plain, */*&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;templateAnsiDrawing&#34;, -&#34;templateDocumentId&#34;:&#34;cbe6e776694549b5ba1a3e88&#34;, -&#34;templateWorkspaceId&#34;:&#34;24d08acf10234dbc8d3ab585&#34;, -&#34;templateElementId&#34;:&#34;17eef7862b224f6fb12cbc46&#34; -}&#39; -</code></pre></li> -</ul> -</li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>templateAnsiDrawing</code> element containing the empty drawing template.</li> -</ol> -<h3 id="create-a-drawing-in-a-custom-graphics-area">Create a drawing in a custom graphics area</h3> -<ol> -<li>Open any Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with your document, and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the drawings area. In this example, we&rsquo;ll add an additional column and row to the drawings area, a title block, and add a border around it. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;customGraphicsArea&#34;, -&#34;border&#34;: &#34;true&#34;, -&#34;numberHorizontalZones&#34;: &#34;3&#34;, -&#34;numberVerticalZones&#34;: &#34;3&#34; -&#34;titleblock&#34;: true -}&#39; -</code></pre></li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>customGraphicsArea</code> element: -</br><img src="https://onshape-public.github.io/images/customDrawingArea.png" alt="new drawing created with border and extra column and row" width=550></li> -</ol> -<h3 id="add-a-note-to-a-drawing">Add a note to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll create an <code>Onshape::Note</code> on the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the contents and size of the annotation. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a note to the drawing.&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;type&#34;: &#34;Onshape::Note&#34;, -&#34;note&#34;: { -&#34;position&#34;: { -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;coordinate&#34;: [ -1, -10, -0 -] -}, -&#34;contents&#34;: &#34;This is a note&#34;, -&#34;textHeight&#34;: 0.2, -&#34;logicalId&#34;: &#34;note1&#34; -} -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new note. Note that your drawing may not match this image exactly, depending on your drawing and document properties. This sample document uses Inches for units. -</br><img src="https://onshape-public.github.io/images/drawings-addnote.png" alt="drawing with note annotation" width=550></li> -</ol> -<h3 id="add-a-callout-to-a-drawing">Add a callout to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Callout</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the contents and size of the annotation: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a callout to the drawing.&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;callout&#34;: -{ -&#34;borderShape&#34;: &#34;Circle&#34;, -&#34;borderSize&#34;: 0, -&#34;contents&#34;: &#34;Example Callout&#34;, -&#34;contentsBottom&#34;: &#34;bottom&#34;, -&#34;contentsLeft&#34;: &#34;left&#34;, -&#34;contentsRight&#34;: &#34;right&#34;, -&#34;contentsTop&#34;: &#34;top&#34;, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -2.5, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -}, -&#34;textHeight&#34;: 0.12, -&#34;logicalId&#34;: &#34;callout1&#34; -}, -&#34;type&#34;: &#34;Onshape::Callout&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new callout. -</br><img src="https://onshape-public.github.io/images/drawings-addcallout.png" alt="callout added to drawing" width=550></li> -</ol> -<h3 id="add-a-centerline-to-a-drawing">Add a centerline to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Centerline</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the coordinates of the centerline ends.</li> -</ol> -<ul> -<li>Note: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.</li> -<li>Note: if you have access, you can refer to the <a href="https://docs.opendesign.com/td/">ODA documentation</a> for more detailed formatting information. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a centerline to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;pointToPointCenterline&#34;: { -&#34;point1&#34;: { -&#34;coordinate&#34;: [ -2, -4, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point1&#34;, -&#34;viewId&#34;: &#34;51fa8b6040e411dfd17a4cda&#34; -}, -&#34;point2&#34;: { -&#34;coordinate&#34;: [ -7, -6, -1 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point2&#34;, -&#34;viewId&#34;: &#34;ay6a8b6020e4h7dfdnn1499i&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Centerline::PointToPoint&#34; -} -] -}] -}&#39; -</code></pre></li> -</ul> -<ol start="4"> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new centerline.</li> -</ol> -<h3 id="add-a-dimension-to-a-drawing">Add a dimension to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Dimension</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the coordinates and formatting options for the dimension. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a dimension to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;radialDimension&#34;: { -&#34;centerPoint&#34;: { -&#34;coordinate&#34;: [ -0.2800021171569824, -0.014964947476983043, -0.079502 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point1&#34;, -&#34;viewId&#34;: &#34;e11c38795c04ca55047f7ea7&#34; -}, -&#34;chordPoint&#34;: { -&#34;coordinate&#34;: [ -0.2920149764955524, -0.010030535983985095, -0.079502 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point2&#34;, -&#34;viewId&#34;: &#34;e11c38795c04ca55047f7ea7&#34; -}, -&#34;formatting&#34;: { -&#34;dimdec&#34;: 2, -&#34;dimlim&#34;: false, -&#34;dimpost&#34;: &#34;R&lt;&gt;&#34;, -&#34;dimtm&#34;: 0, -&#34;dimtol&#34;: false, -&#34;dimtp&#34;: 0, -&#34;type&#34;: &#34;Onshape::Formatting::Dimension&#34; -}, -&#34;logicalId&#34;: &#34;dimension1&#34;, -&#34;textOverride&#34;: &#34;&#34;, -&#34;textPosition&#34;: { -&#34;coordinate&#34;: [ -191.80537349378181, -89.76274130852224, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Dimension::Radial&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new dimension.</li> -</ol> -<h3 id="add-a-geometric-tolerance-to-a-drawing">Add a geometric tolerance to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::GeometricTolerance</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the frames and position of the annotation: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a geometric tolerance to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;geometricTolerance&#34;: { -&#34;frames&#34;: [ -&#34;{\\fDrawing Symbols Sans;◎}%%v{\\fDrawing Symbols Sans;∅}tol1{\\fDrawing Symbols Sans;Ⓜ}%%v%%v%%v%%v%%v\n&#34;, -&#34;{\\fDrawing Symbols Sans;⌖}%%vto2{\\fDrawing Symbols Sans;Ⓛ}%%v%%v%%v%%v%%v\n&#34; -], -&#34;logicalId&#34;: &#34;geometricTolerance1&#34;, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -6, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::GeometricTolerance&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new annotation. -</br><img src="https://onshape-public.github.io/images/drawings-addtolerance.png" alt="new drawing created with border and extra column and row" width=550></li> -</ol> -<h3 id="add-an-inspection-symbol-to-a-drawing">Add an inspection symbol to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::InspectionSymbol</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the shape and position of the inspection symbol. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add an inspection symbol to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;inspectionSymbol&#34;: { -&#34;borderShape&#34;: &#34;Circle&#34;, -&#34;borderSize&#34;: 2, -&#34;logicalId&#34;: &#34;inspection1&#34;, -&#34;parentAnnotation&#34;: &#34;h:10000577&#34;, -&#34;parentLineIndex&#34;: 0.0, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -2.6, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -}, -&#34;textHeight&#34;: 2 -}, -&#34;type&#34;: &#34;Onshape::InspectionSymbol&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new inspection symbol.</li> -</ol> -<h3 id="add-a-table-to-a-drawing">Add a table to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Table::GeneralTable</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the location, number of rows, and number of columns for the table. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;New table&#34;, -&#34;jsonRequests&#34;: [ { -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;annotations&#34;: [ -{ &#34;table&#34;: { -&#34;cells&#34;: [ -{ -&#34;column&#34;: 0, -&#34;content&#34;: &#34;1.1&#34;, -&#34;row&#34;: 0 -}, -{ -&#34;column&#34;: 0, -&#34;content&#34;: &#34;2.1&#34;, -&#34;row&#34;: 1 -}, -{ -&#34;column&#34;: 1, -&#34;content&#34;: &#34;1.2&#34;, -&#34;row&#34;: 0 -}, -{ -&#34;column&#34;: 1, -&#34;content&#34;: &#34;2.2&#34;, -&#34;row&#34;: 1 -} -], -&#34;columns&#34;: 2, -&#34;rows&#34;: 2, -&#34;showHeaderRow&#34;: false, -&#34;showTitleRow&#34;: false, -&#34;position&#34;: { -&#34;coordinate&#34;: [100.0, 400.0, 0.0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Table::GeneralTable&#34; -}] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new table.</li> -</ol> -<h3 id="specify-a-snap-point">Specify a snap point</h3> -<p>You can use the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> to choose the snap points for annotations. Available types of snap points are:</p> -<pre tabindex="0"><code> ModeApint // Apparent intersection -ModeCenter // Center point -ModeEnd // End point -ModeIns // Insertion point -ModeIntersec // Intersection -ModeMid // Midpoint -ModeNear // Nearest point -ModeNode // Node -ModePar // Parallel -ModePerp // Perpendicular -ModeQuad // Quadrant -ModeStart // Start point -ModeTan // Tangent point -</code></pre><ol> -<li>Create a sketch in Onshape with two circles, then extrude both circles.</li> -<li>Create a drawing of the part&rsquo;s front view. We&rsquo;ll use the Drawings API to a point to point centerline snapped to the centers of the holes. -</br><img src="https://onshape-public.github.io/images/drawings-snap-before-01.png" alt="drawing front view of a box with two holes" width=350></li> -<li>Next, we&rsquo;ll need to get the view ID of the drawing. Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingViews_1">Drawing/getDrawingViews_1</a> endpoint on your document to get a list of all views in the drawing, and copy the <code>viewId</code> from the response:</li> -</ol> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/views&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre><ol start="4"> -<li>Use the <code>viewId</code> from the last step to get the <code>uniqueId</code> (or <code>edgeId</code>) of each circle&rsquo;s center from the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingViewJsonGeometry_1">Drawing/getDrawingViewJsonGeometry_1)</a> endpoint:</li> -</ol> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/views/{viewId}/jsongeometry&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre><ol start="5"> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code></code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add a <code>pointToPointCenterline</code> to the drawing. Make sure to update the request body values as followis:</li> -</ol> -<ul> -<li><code>messageName</code>: <code>&quot;onshapeCreateAnnotation&quot;</code></li> -<li><code>formatVersion</code>: <code>&quot;2021-01-01&quot;</code></li> -<li><code>uniqueId</code>: From Step 4</li> -<li><code>viewId</code>: From Step 3</li> -<li><code>coordinates</code>: The values must be sent as part of the request, but are ignored. -<pre tabindex="0"><code> curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d { -&#34;description&#34;: &#34;creating a snap point&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;pointToPointCenterline&#34;: { -&#34;point1&#34;: { -&#34;coordinate&#34;: [0,0,0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;{uniqueId1}&#34;, -&#34;viewId&#34;: &#34;{viewId}&#34;, -&#34;snapPointType&#34;: &#34;ModeCenter&#34; -}, -&#34;point2&#34;: { -&#34;coordinate&#34;: [0,0,0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;{uniqueId2}&#34;, -&#34;viewId&#34;: &#34;{viewId}&#34;, -&#34;snapPointType&#34;: &#34;ModeCenter&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Centerline::PointToPoint&#34; -} -] -}] -} -</code></pre></li> -</ul> -<ol start="7"> -<li>Return to your document and see that the centerline has been added to the document at the snap points. -</br><img src="https://onshape-public.github.io/images/drawings-snap-after-01.png" alt="drawing front view of a box with two holes with a centerline between the hole centers" width=350></li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://onshape-public.github.io/docs/api-intro//#onshape-api-request">Guide to Onshape APIs</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">Guide to the API Explorer</a></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing">API Explorer: Drawings</a></li> -<li><a href="https://cad.onshape.com/help/Content/drawings.htm">Onshape Help: Drawings</a></li> -</ul>Docs: Featureshttps://onshape-public.github.io/docs/api-adv/featureaccess/Mon, 18 May 2020 20:37:28 -0400https://onshape-public.github.io/docs/api-adv/featureaccess/ -<p>This page describes the APIs Onshape provides for creating and manipulating features and the Feature List in a Part Studio.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {vid}, {mid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, version, microversion, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong>cad</strong> in all Onshape URLs with your company domain. -https://<strong>cad</strong>.onshape.com &gt; https://<strong>companyName</strong>.onshape.com</li> -</ul> -</blockquote> -<h2 id="featurescript-vs-rest-api">FeatureScript vs REST API</h2> -<p>When working with complex geometry, you might find working directly in FeatureScript easier than working with the Onshape REST API. <a href="https://cad.onshape.com/FsDoc/">Click here to see the FeatureScript documentation.</a></p> -<h2 id="endpoints">Endpoints</h2> -<p>The following endpoints are available for working with features and the Feature List:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features?rollbackBarIndex=-1&amp;includeGeometryIds=true&amp;noSketchGeometry=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">Add a Feature</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{wid}/features&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;&#34;, -&#34;name&#34;: &#34;&#34;, -&#34;parameters&#34;: [] -} -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updatePartStudioFeature">Update a Feature</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;parameters&#34;: [] -} -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updateFeatures">Update Multiple Features</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/updates&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTUpdateFeaturesCall-1748&#34;, -&#34;features&#34;: [ -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid1}&#34;, -&#34;parameters&#34;: [] -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid2}&#34;, -&#34;parameters&#34;: [] -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/deletePartStudioFeature">Delete a Feature</a> -<pre tabindex="0"><code>curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -</ul> -<h3 id="json-encoding">JSON encoding</h3> -<p>Instead of providing a translation layer between a feature&rsquo;s internal and external formats, these APIs present the internal format of the feature definitions to the user. The best way to familiarize yourself with the formats involved is by calling the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> endpoint on existing Part Studios.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>Onshape REST API parameters may change at any time. The documentation on this page is accurate for v8 of the Onshape API. The quickest way to verify what parameters are needed for a call is to create the sketch/feature in the Onshape UI, then call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> API and see what parameters are returned for the feature.</li> -</ul> -</blockquote> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>Default values are sometimes omitted in the encoded output. These defaults are: -<ul> -<li>String: <code>&quot;&quot;</code></li> -<li>Boolean: <code>false</code></li> -<li>Numeric: <code>0</code></li> -</ul> -</li> -<li>The JSON encoding uses a special tagging system to manage polymorphic data structures. Objects are generally by enclosing them within another object that declares the type information for the enclosed object.</li> -</ul> -</blockquote> -<h3 id="feature-types">Feature types</h3> -<p>Below, find the available types for working with features in the API.</p> -<ul> -<li><code>BTMFeature-134</code> - General feature type</li> -<li><code>BTMSketch-151</code> - Feature type for sketches</li> -</ul> -<h3 id="parameter-types">Parameter types</h3> -<p>All parameters have the following fields in common:</p> -<ul> -<li><code>parameterId</code> - Unique ID of the parameter</li> -<li><code>nodeId</code> - Unique ID of the parameter node</li> -</ul> -<p>The parameter types available for use in the API are:</p> -<ul> -<li><code>BTMParameterQuantity-147</code> -<ul> -<li><code>expression</code> - Define the value for the parameter</li> -</ul> -</li> -<li><code>BTMParameterQueryList-148 </code> - defined by one of the following: -<ul> -<li><code>SBTMIndividualQuery-138</code> -<ul> -<li><code>geometryIds</code> - List of geometry IDs the feature applies to</li> -</ul> -</li> -<li><code>SBTMIndividualSketchRegionQuery-140</code> -<ul> -<li><code>featureId</code> - Feature ID of the sketch for which to include all regions</li> -</ul> -</li> -</ul> -</li> -<li><code>BTMParameterBoolean-144</code> -<ul> -<li><code>value</code> - <code>true | false</code></li> -</ul> -</li> -<li><code>BTMParameterEnum-145</code> -<ul> -<li><code>enumName</code> - Name of the enum type that the value is a member of</li> -<li><code>value</code> - The enum member</li> -</ul> -</li> -</ul> -<h3 id="sketch-plane-ids">Sketch plane IDs</h3> -<p>The following string can be sent along with the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/evalFeatureScript">PartStudios/featurescript</a> API to get the plane ID. You can then use that ID to specify the plane on which to create a sketch.</p> -<pre tabindex="0"><code>function(context is Context, queries) { -return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;{planeName}\&#34;), EntityType.FACE))); -} -</code></pre><p>For example, to get the ID of the Top plane, you would make the following call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;script&#34;: &#34;function(context is Context, queries) { return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;Top\&#34;), EntityType.FACE))); }&#34; -}&#39; -</code></pre><h2 id="sample-workflows">Sample Workflows</h2> -<p>Below are several examples of how the API can be used in order to help you get started. The calls could be executed using your preferred software environment but interactive use in a REST-aware tool is likely the easiest way to try the examples.</p> -<h3 id="get-the-list-of-features-in-a-part-studio">Get the list of features in a Part Studio</h3> -<p>One of the best ways to familiarize yourself with the Onshape Feature APIs is to view the API details for existing features in a Part Studio. In this example, we&rsquo;ll add three features to a Part Studio, and then call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">PartStudio/getPartStudioFeatures</a> API on the Part Studio. We&rsquo;ll then be able to view the structure of the way features are represented in the API.</p> -<ol> -<li>Create a new document or open an existing one.</li> -<li>Create a new sketch in the document, and draw a long rectangle.</li> -<li>Extrude the rectangle.</li> -<li>Add a fillet to one edge of the part.</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">PartStudio/getPartStudioFeatures</a> API. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features?rollbackBarIndex=-1&amp;includeGeometryIds=true&amp;noSketchGeometry=false&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>Review the JSON returned in the response body. A lot of information is returned, but it will look something like the truncated snippet below. Notice that there are objects returned for each feature in the Part Studio&ndash; the sketch, the extrude, the fillet, and the chamfer. Each default plane and the origin in the Part Studio also appear in the <code>defaultFeatures</code> object. The Standard Geometry library is listed as an import, and the response also includes the state of each feature. : -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureListResponse-2457&#34;, -&#34;isComplete&#34;: true, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;rollbackIndex&#34;: 4, -&#34;features&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;entities&#34;: [...], -&#34;constraints&#34;: [...], -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid1}&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;subFeatures&#34;: [...], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...] -&#34;featureId&#34;: &#34;{fid2}&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;subFeatures&#34;: [], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Fillet 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid3}&#34;, -&#34;featureType&#34;: &#34;fillet&#34;, -&#34;subFeatures&#34;: [...], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Chamfer 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid4}&#34;, -} -], -&#34;featureStates&#34;: { -&#34;{fid1}&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -... -}, -&#34;defaultFeatures&#34;: [ -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Origin&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Top&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Front&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Right&#34;, -} -], -&#34;imports&#34;: [ -{ -&#34;btType&#34;: &#34;BTMImport-136&#34;, -&#34;path&#34;: &#34;onshape/std/geometry.fs&#34;, -&#34;version&#34;: &#34;2232.0&#34; -} -], -&#34;libraryVersion&#34;: 2232 -} -</code></pre></li> -</ol> -<h3 id="create-a-cube-feature">Create a cube feature</h3> -<p>In this example we will create a cube using the <code>cube</code> feature. The feature accepts a single parameter (the length of a side) and creates a cube with a corner at the origin and aligned with the three default planes.</p> -<ol> -<li>Create a new document or open an existing one. We&rsquo;ll create the cube feature in this document.</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. This is a call to the same endpoint as in the previous example, but is a <code>POST</code> instead of a <code>GET</code>. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>Add the following as the JSON body. -<ul> -<li>Note the <code>btType</code> defines this as a Feature.</li> -<li>We&rsquo;ve named the feature <code>cube</code> and inserted an instance of the feature named <code>Cube 1</code> into the Part Studio.</li> -<li>The <code>cube</code> feature has one parameter&ndash; the cube <code>sideLength</code> in inches, which is set to 1 by default.</li> -</ul> -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -} -</code></pre></li> -<li>Confirm your call matches the following, and then make the call: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -}&#39; -</code></pre></li> -<li>Return to your console to review the endpoint response. The output returns: -<ul> -<li>The feature definition that we provided as input with <code>nodeId</code>s and a <code>featureId</code>. Make a note of the <code>featureId</code>; we&rsquo;ll use it in the next example.</li> -<li>Information that the feature executed correctly</li> -<li>The serialization version and microversion of the document that resulted from the feature addition</li> -</ul> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionResponse-1617&#34;, -&#34;featureState&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;value&#34;: 0, -&#34;units&#34;: &#34;&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;nodeId&#34;: &#34;{nid1}&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;nodeId&#34;: &#34;{nid2}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;returnAfterSubfeatures&#34;: false, -&#34;subFeatures&#34;: [], -&#34;namespace&#34;: &#34;&#34; -}, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 0 -} -</code></pre></li> -<li>Open your document and confirm that the cube has been inserted into the Part Studio. -</br><img src="https://onshape-public.github.io/images/features-cube-example.png" alt="cube added to part studio via features api" width=550></li> -<li>Double-click <code>Cube 1</code> in the Feature List to open the Cube 1 dialog. Change the sideLength to 3 and click the checkbox. Note that the size of the cube changes automatically. -</br><img src="https://onshape-public.github.io/images/features-cube-example-02.png" alt="cube parameter updated to 3 inches" width=550></li> -</ol> -<h3 id="create-a-sketch">Create a sketch</h3> -<p>In this example, we&rsquo;ll create a circular sketch feature with the following properties:</p> -<ul> -<li>While other features use a <code>btType</code> of <code>BTMFeature-141</code>, sketches have their own special type: <code>BTMSketch-151</code></li> -<li>Sketches must use the <code>newSketch</code> featureType</li> -<li>Sketch plane ID: Front</li> -<li>Radius: 0.025 inches</li> -<li>Location: (0.05, 0.05)</li> -</ul> -<ol> -<li>Open a new PartStudio. Note the following: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (of the Part Studio tab)</li> -</ul> -</li> -<li>We want to create the circle on the Front plane, so we&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/evalFeatureScript">PartStudios/featurescript</a> endpoint to get its ID: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;script&#34;: &#34;function(context is Context, queries) { return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;Front\&#34;), EntityType.FACE))); }&#34; -}&#39; -</code></pre>The call returns the following, identifying the plane as <code>JCC</code>. -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureScriptEvalResponse-1859&#34;, -&#34;result&#34;: { -&#34;btType&#34;: &#34;com.belmonttech.serialize.fsvalue.BTFSValueArray&#34;, -&#34;value&#34;: [ -{ -&#34;btType&#34;: &#34;com.belmonttech.serialize.fsvalue.BTFSValueString&#34;, -&#34;value&#34;: &#34;JCC&#34;, -&#34;typeTag&#34;: &#34;&#34; -} -], -&#34;typeTag&#34;: &#34;&#34; -} -} -</code></pre></li> -<li>Now we&rsquo;ll create the JSON structure for our sketch. <em>All sketches must be created with the <code>BTMSketch-151</code> btType and the <code>newSketch</code> featureType.</em> Note how we&rsquo;ve specified the plane to use in the <code>sketchPlane</code> parameter, and the <code>geometry</code> details. -<pre tabindex="0"><code>{ -&#34;feature&#34; : { -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualQuery-138&#34;, -&#34;deterministicIds&#34;: [ &#34;JCC&#34; ] -} -], -&#34;parameterId&#34;: &#34;sketchPlane&#34; -} -], -&#34;entities&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketchCurve-4&#34;, -&#34;geometry&#34;: { -&#34;btType&#34;: &#34;BTCurveGeometryCircle-115&#34;, -&#34;radius&#34;: 0.025, -&#34;xcenter&#34;: 0.05, -&#34;ycenter&#34;: 0.05, -&#34;xdir&#34;: 1, -&#34;ydir&#34;: 0, -&#34;clockwise&#34;: false -}, -&#34;centerId&#34;: &#34;circle-entity.center&#34;, -&#34;entityId&#34;: &#34;circle-entity&#34; -} -], -&#34;constraints&#34;: [ -] -} -} -</code></pre></li> -<li>Now we&rsquo;ll add the JSON structure to the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> endpoint. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{wid}/features&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;feature&#34; : { -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualQuery-138&#34;, -&#34;deterministicIds&#34;: [ &#34;JCC&#34; ] -} -], -&#34;parameterId&#34;: &#34;sketchPlane&#34; -} -], -&#34;entities&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketchCurve-4&#34;, -&#34;geometry&#34;: { -&#34;btType&#34;: &#34;BTCurveGeometryCircle-115&#34;, -&#34;radius&#34;: 0.025, -&#34;xcenter&#34;: 0.05, -&#34;ycenter&#34;: 0.05, -&#34;xdir&#34;: 1, -&#34;ydir&#34;: 0, -&#34;clockwise&#34;: false -}, -&#34;centerId&#34;: &#34;circle-entity.center&#34;, -&#34;entityId&#34;: &#34;circle-entity&#34; -} -], -&#34;constraints&#34;: [ -] -} -}&#39; -</code></pre></li> -<li>Find the new sketch&rsquo;s <code>featureId</code> in the call response. You&rsquo;ll need this for the <a href="#create-a-cylinder">Create a cylinder</a> tutorial.</li> -<li>Open your Part Studio and confirm that the sketch has been added: -</br></br><img src="https://onshape-public.github.io/images/features-create-sketch.png" alt="circle sketch created via features api" width=550></li> -</ol> -<h3 id="create-a-cylinder">Create a cylinder</h3> -<p>In this tutorial, we&rsquo;ll extrude an sketch with the following properties: -</br></br><img src="https://onshape-public.github.io/images/features-extrude-dialog.png" alt="Extrude dialog in Onshape UI" width=350></p> -<ol> -<li>This tutorial expands on the <a href="#create-a-sketch">Create a sketch</a> tutorial. You&rsquo;ll need the following from the document containing your circular sketch: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID of the tab containing the sketch</li> -<li>Feature ID of the sketch -<ul> -<li>If you need to get this <code>featureId</code> again, you can call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document.</li> -</ul> -</li> -</ul> -</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>We&rsquo;ll start by initializing an extrude in the JSON with the <code>btType</code> and <code>featureType</code> shown below:</li> -</ol> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -] -} -} -</code></pre><ol start="4"> -<li>Now, we&rsquo;ll add values for the options we want to our <code>parameters</code> block. Don&rsquo;t forget to replace <code>{featureId}</code> in the code below with the feature ID of the sketch.</li> -</ol> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;SOLID&#34;, -&#34;enumName&#34;: &#34;ExtendedToolBodyType&#34;, -&#34;parameterId&#34;: &#34;bodyType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;NEW&#34;, -&#34;enumName&#34;: &#34;NewBodyOperationType&#34;, -&#34;parameterId&#34;: &#34;operationType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualSketchRegionQuery-140&#34;, -&#34;featureId&#34;: &#34;{featureId}&#34; -} -], -&#34;parameterId&#34;: &#34;entities&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;BLIND&#34;, -&#34;enumName&#34;: &#34;BoundingType&#34;, -&#34;parameterId&#34;: &#34;endBound&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;depth&#34; -} -</code></pre><ol start="5"> -<li>Now our JSON is complete, and we can make our call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;SOLID&#34;, -&#34;enumName&#34;: &#34;ExtendedToolBodyType&#34;, -&#34;parameterId&#34;: &#34;bodyType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;NEW&#34;, -&#34;enumName&#34;: &#34;NewBodyOperationType&#34;, -&#34;parameterId&#34;: &#34;operationType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualSketchRegionQuery-140&#34;, -&#34;featureId&#34;: &#34;{featureId}&#34; -} -], -&#34;parameterId&#34;: &#34;entities&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;BLIND&#34;, -&#34;enumName&#34;: &#34;BoundingType&#34;, -&#34;parameterId&#34;: &#34;endBound&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;depth&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -}&#39; -</code></pre><ol start="6"> -<li>Open your document and confirm that the sketch has been extruded into a cylinder. -</br></br><img src="https://onshape-public.github.io/images/features-extrude-example.png" alt="circle sketch created via features api" width=550></li> -</ol> -<h3 id="update-a-feature">Update a feature</h3> -<p>In this example we&rsquo;ll update our cube feature.</p> -<ol> -<li>Open the document in which you created the cube feature in <a href="#create-a-cube-feature">this example</a>. You will need the following from this document: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (for the element that contains the cube feature)</li> -<li>Feature ID (ID of the cube feature, returned in the API response in the previous example) -<ul> -<li>If you need to get this <code>featureId</code> again, you can call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document.</li> -</ul> -</li> -</ul> -</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updatePartStudioFeature">PartStudio/updatePartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>Add the following as the JSON body. -<ul> -<li>Note the <code>btType</code> defines this as a Feature.</li> -<li>We specify the <code>featureId</code> again in the request body. This must match the <code>featureId</code> sent in the URL exactly.</li> -<li>We must also specify the feature&rsquo;s <code>featureType</code> and <code>name</code> in this call; if we don&rsquo;t send those fields, the call will attempt to change these values to empty strings, resulting in errors.</li> -<li>The <code>cube</code> feature has one parameter&ndash; the cube <code>sideLength</code> in inches, which we will update to 2 inches:</li> -</ul> -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -] -} -} -</code></pre></li> -<li>Confirm your call matches the following, and then make the call: -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -] -} -}&#39; -</code></pre></li> -<li>Return to your console to review the endpoint response. The output returns: -<ul> -<li>The updated feature definition</li> -<li>Information that the feature executed correctly</li> -<li>The serialization version and microversion of the document that resulted from the feature update</li> -</ul> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionResponse-1617&#34;, -&#34;featureState&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;value&#34;: 0, -&#34;units&#34;: &#34;&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;nodeId&#34;: &#34;{nid1}&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;nodeId&#34;: &#34;{nid2}, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;returnAfterSubfeatures&#34;: false, -&#34;subFeatures&#34;: [], -&#34;namespace&#34;: &#34;&#34; -}, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 0 -} -</code></pre></li> -<li>Open your document and confirm that the cube has a side length of 2 inches. -</br><img src="https://onshape-public.github.io/images/features-cube-example-03.png" alt="cube added to part studio via features api" width=550></li> -</ol> -<h3 id="delete-a-feature">Delete a feature</h3> -<ol> -<li>Create a new document and add a cube feature to it. See <a href="#create-a-cube-feature">Create a cube feature</a> for instructions. Make a note of the following: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (for the element containing the cube feature)</li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document to get the <code>featureId</code> of the cube feature. See <a href="#get-the-list-of-features-in-a-part-studio">Get the Feature list</a> for instructions.</li> -<li>Create and execute the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/deletePartStudioFeature">PartStudio/deletePartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Confirm that the cube feature has been removed from your document.</li> -</ol>Docs: Evaluating FeatureScripthttps://onshape-public.github.io/docs/api-adv/fs/Thu, 15 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/fs/ -<p>This page describes some of the APIs Onshape provides for evaluating <a href="https://cad.onshape.com/FsDoc/">FeatureScript</a>.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --d &#39;{ -&#34;libraryVersion&#34;: 2144, -&#34;script&#34;: &#34;&#34; -} -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="calculate-a-tight-bounding-box">Calculate a tight bounding box</h3> -<p>Though the Onshape API offers a <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioBoundingBoxes">PartStudio/getPartStudioBoundingBoxes</a> endpoint, it does not result in a tight bounding box. The values returned are meant for graphics and visualization, and are approximate. To calculate a more accurate bounding box, we&rsquo;ll use the <a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a> endpoint.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a>. Replace the URL parameters with the IDs from the Part Studio you&rsquo;re working with, and replace <code>CREDENTIALS</code> with your authorization credentials. The endpoint will return a tight bounding box in the response. -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --d &#39;{ &#34;libraryVersion&#34;: 2144, -&#34;script&#34;: &#34;function(context is Context, definition is map) {const boundingBoxTight = evBox3d(context, { \n \&#34;topology\&#34; : qConstructionFilter(qEverything(), ConstructionObject.NO),\n \&#34;tight\&#34; : true\n}); \n return (boundingBoxTight);}&#34; -}&#39; -</code></pre></li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/FsDoc/">FeatureScript</a></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">API Explorer: Part Studio</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -</ul>Docs: Import & Exporthttps://onshape-public.github.io/docs/api-adv/translation/Wed, 27 Sep 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/translation/ -<p>This page describes the APIs Onshape provides for importing files to Onshape and exporting files from Onshape into different formats. We refer to the process of importing and exporting files from one format to another as <em>translating</em> the files.</p> -<p>Onshape provides several APIs to support this format translation. These fall into three categories:</p> -<ul> -<li><a href="#synchronous-exports">Synchronous exports</a> - Export Onshape content to glTF, STL, or Parasolid format.</li> -<li><a href="#asynchronous-exports">Asynchronous exports</a> - Export Onshape content into a variety of other formats.</li> -<li><a href="#imports">Import to Onshape</a> - Import a translatable file by uploading it to an Onshape blob element.</li> -</ul> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="synchronous-exports">Synchronous exports</h2> -<p>Onshape provides a simple way to export content to common formats (glTF, Parasolid, and STL). Most of the interfaces defined here operate by requesting an HTTP redirect to a different URL where the request is fulfilled. Applications must explicitly handle the redirect and attachment authentication headers to the follow-up request, or it will fail.</p> -<p>The following endpoints are available. We&rsquo;ve included an example curl with each one.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPartGltf">Export Part to glTF</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}/e/{eid}/partid/{partid}/gltf?rollbackBarIndex=-1&amp;outputSeparateFaceNodes=false&amp;outputFaceAppearances=false&#39; \ --H &#39;accept: model/gltf-binary;qs=0.08&#39; \ -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPS">Export Part to Parasolid</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}?elementId={eid}&amp;withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportStl">Export Part to STL</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}/e/{eid}/partid/{partid}/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: application/octet-stream&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioGltf">Export PartStudio to glTF</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/gltf?rollbackBarIndex=-1&amp;outputSeparateFaceNodes=false&amp;outputFaceAppearances=false&#39; \ --H &#39;accept: model/gltf-binary;qs=0.08&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportParasolid">Export PartStudio to Parasolid</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/parasolid?version=0&amp;includeExportIds=false&amp;binaryExport=false&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioStl">Export PartStudio to STL</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Document/export2Json">Export Document to JSON</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/documents/d/{did}/w/{wid}/e/{eid}/export&#39; \ --H &#39;accept: application/octet-stream&#39; \ -</code></pre></li> -</ul> -<h2 id="asynchronous-exports">Asynchronous exports</h2> -<p>The exports in the last section perform the format translation synchronously, returning the output immediately after some processing delay. Other format conversions are more complex and time-consuming, and in many cases, cannot be completed quickly enough to prevent connection errors. Note that the source format for an export is currently always automatically detected by Onshape. Part Studios and Assemblies are known to be <code>ONSHAPE</code> format. File uploads have their type determined by the filename suffix. For example, a file named <em>part7.step</em> is assumed to be in <code>STEP</code> format.</p> -<p>The following asynchronous translation APIs are available:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/createBlobTranslation">BlobElement/createBlobTranslation</a>: Export a Blob Element to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudios/createPartStudioTranslation</a>: Export a Part Studio to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a>: Export an Assembly to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a>: Export a Drawing to the specified <code>formatName</code>.</li> -</ul> -<p>These asynchronous exports include a few additional steps, which are explained in more detail in the <a href="#async-export-steps">next section</a>:</p> -<ol> -<li>See what formats are available for exporting your content with <strong><a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a></strong>.</li> -</ol> -<ul> -<li><strong>Note:</strong> Parts with mesh data cannot be exported to ACIS, IGES, or OBJ format.</li> -</ul> -<ol start="2"> -<li>Call the desired <strong>translation API</strong>. -<ul> -<li>Specify the target <strong><code>formatName</code></strong> in the request body JSON.</li> -<li>Specify <strong><code>storeInDocument=false</code></strong> (default) to export the content to new file.</li> -<li>Specify <strong><code>storeInDocument=true</code></strong> to export the content to a blob element in the source document.</li> -</ul> -</li> -<li>Poll the <strong><code>requestState</code></strong> in the translation response and wait for a result of <strong><code>DONE</code></strong>.</li> -<li>To retrieve the exported results: -<ul> -<li>External files: call <strong><a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Document/downloadExternalData</a></strong> on the <code>resultExternalDataIds</code> from the translation response.</li> -<li>Blob elements: call <strong><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a></strong> on the <code>resultElementIds</code> from the translation response.</li> -</ul> -</li> -</ol> -<h3 id="async-export-details">Async export details</h3> -<p>To export your Onshape content to another format:</p> -<ol> -<li>Determine what export format file types are available for your content by calling: <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translations/getAllTranslatorFormats</a>. -<ul> -<li>Note that Drawings have their own API for this call: <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Drawing/getDrawingTranslatorFormats</a></li> -</ul> -</li> -<li>Next, initiate the export by calling one of the asynchronous translation APIs. -<ul> -<li>Note that each of these APIs takes a JSON for specifying options for the export as part of the request body. Refer to the <a href="https://onshape-public.github.io/docs/api-intro/explorer">API Explorer</a> page for help viewing these JSON docs.</li> -<li>The target file format <strong>must be specified in the <code>formatName</code> field</strong> in the request body, and must match a valid format found in Step 1.</li> -<li>By default, <code>storeInDocument</code> is set to <code>false</code> in the request body to export to a single data file (or a zip of multiple files). Set to <code>true</code> to export as blob elements.</li> -</ul> -</li> -<li>Wait for the translation to complete. You can either register a webhook and wait to receive a notifcation that the translation is complete (see <a href="https://onshape-public.github.io/docs/app-dev/webhook/">Webhook Notifications</a>), or you can poll the translation&rsquo;s <code>requestState</code>: -<ul> -<li>You can poll the <code>requestState</code> from the initial translation&rsquo;s response, or you can call <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getTranslation">Translation/getTranslation</a> on the <code>translationId</code> from the initial translation&rsquo;s response.</li> -<li>When a translation is complete, <code>requestState</code> will change from <code>ACTIVE</code> to either <code>DONE</code> or <code>FAILED</code>.</li> -<li>When <code>requestState=DONE</code>, results are available to be used.</li> -</ul> -</li> -<li>Retrieve the exported results: -<ul> -<li>If you exported to an external file, call <a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Documents/downloadExternalData</a> to retrieve the exported result. -<ul> -<li>Note that this API takes the source document ID and a &ldquo;foreign ID&rdquo; as required parameters.</li> -<li>Use the <code>resultExternalDataIds</code> from the translation response as the foreign ID (<code>fid</code>).</li> -<li>External data is associated with, but external to, the document used as translation context. This data is not versioned like with in-document data.</li> -</ul> -</li> -<li>If your translation request body specified <code>storeInDocument=true</code>, retrieve the blob element data with <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a>. -<ul> -<li>The element IDs for the new blob elements can be found in the <code>resultElementIds</code> field in the translation response.</li> -</ul> -</li> -</ul> -</li> -</ol> -<h2 id="imports">Imports</h2> -<p>Files can be imported to Onshape as blob elements. When uploading a file to a blob element, either as a new element or an update to an existing element, if the file is a recognized format for import, it will be translated into <code>ONSHAPE</code> format by default. This behavior can be overridden by the application, if desired.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Translation/createTranslation">Translation/createTranslation</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;flattenAssemblies=true --F &#39;file=@/path/filename.ext&#39; --F &#39;formatName=&#39; \ -... -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/uploadFileCreateElement">BlobElement/uploadFileCreateElement</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;file=@/path/filename.ext&#39; --F &#39;formatName=&#39; \ -... -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/uploadFileUpdateElement">BlobElement/uploadFileUpdateElement</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;locationElementId=&#39; \ --F &#39;file=@/path/filename.ext&#39; -... -</code></pre></li> -</ul> -<p>Note that these endpoints require you to specify the target document ID and workspace ID. You must also include the file to import. These APIs also includes a request body JSON for specifying options for the import.</p> -<ul> -<li>Override the translation to <code>ONSHAPE</code> format by specifying a valid format in the <code>formatName</code> field. Get a list of valid import formats by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a>.</li> -<li>Specify <code>storeInDocument=true</code> to import the data as a blob element into the target document. Change to <code>false</code> to only create an external data file.</li> -<li>If the source file contains an assembly and <code>flattenAssemblies=true</code>, the assembly structure is removed and a single part studio is created.</li> -<li>Note that when using cURL, you must begin the path to the file with an <code>@</code> symbol.</li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="export-a-partstudio-to-stl">Export a PartStudio to STL</h3> -<p>We will export the <code>CRANK</code> PartStudio from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to an STL file.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioStl">Part Studios/exportPartStudioStl</a> endpoint on the document: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li>Navigate to the request URL to download the resulting STL file: -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch -</code></pre></li> -<li>Open the <em>CRANK.stl</em> file from wherever your downloads are saved.</li> -</ol> -<h3 id="export-a-part-to-parasolid">Export a Part to Parasolid</h3> -<p>We will export the <code>FLYWHEEL</code> part from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to an STL file.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMV">Part/getPartsWMV</a> endpoint on your document and get all the part IDs: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62?elementId=6bed6b43463f6a46a37b4a22&amp;withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Locate the part to export (hint: look for <code>name = yourPartName</code>) in the response body. Get the part ID from the <code>partId</code> field. In the example below, <code>partId = JiD</code> for <code>name=FLYWHEEL</code>: -<pre tabindex="0"><code>[ -... -{ -&#34;name&#34; : &#34;FLYWHEEL&#34;, -&#34;state&#34; : &#34;IN_PROGRESS&#34;, -&#34;propertySourceTypes&#34; : { -&#34;57f3fb8efa3416c06701d60f&#34; : 3, -&#34;57f3fb8efa3416c06701d60d&#34; : 3, -&#34;57f3fb8efa3416c06701d61e&#34; : 3, -&#34;57f3fb8efa3416c06701d60e&#34; : 3, -&#34;57f3fb8efa3416c06701d60c&#34; : 3 -}, -&#34;defaultColorHash&#34; : &#34;FzHLKqGeuTBFjmY_2_0&#34;, -&#34;ordinal&#34; : 1, -&#34;isMesh&#34; : false, -&#34;description&#34; : &#34;Flywheel&#34;, -&#34;microversionId&#34; : &#34;bdb504d2d4c948493a87ccf3&#34;, -&#34;partNumber&#34; : &#34;PRT-10241&#34;, -&#34;elementId&#34; : &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;partId&#34; : &#34;JiD&#34;, -&#34;bodyType&#34; : &#34;solid&#34;, -&#34;customProperties&#34; : { -&#34;57f3fb8efa3416c06701d61e&#34; : &#34;false&#34; -} -... -] -</code></pre></li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPS">Part/exportPS</a> endpoint on the FLYWHEEL part: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/partid/JiD/parasolid?version=0&#39; \ --H &#39;accept: application/octet-stream&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Navigate to the request URL to download the resulting file: -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/partid/JiD/parasolid?version=0 -</code></pre></li> -<li>Open the <em>CRANK.x_t</em> file from your downloads. Note that the file is automatically named after the PartStudio to which the part belongs.</li> -</ol> -<h3 id="export-a-partstudio-to-solidworks">Export a PartStudio to SOLIDWORKS</h3> -<p>We will export the <code>CRANK</code> PartStudio from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to a SOLIDWORKS file.</p> -<ol> -<li>Validate that SOLIDWORKS is a supported export file type by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validDestinationFormat=true</code> for <code>translatorName=SOLIDWORKS</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;SOLIDWORKS&#34;, -&#34;translatorName&#34;: &#34;solidworks&#34;, -&#34;couldBeAssembly&#34;: true -} -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudio/createPartStudioTranslation</a>. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;formatName&#34;: &#34;SOLIDWORKS&#34;, -&#34;storeInDocument&#34;: false, -&#34;translate&#34;: true -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>In this example, we&rsquo;ve just shown a snippet of the entire JSON.</li> -<li>A <code>formatName</code> string must be specified that matches one of the valid formats you found in the last step. In this example, we set <code>formatName</code> to <code>SOLIDWORKS.</code></li> -<li>We want to export this to a new file, so we&rsquo;ll leave <code>storeInDocument</code> set to <code>false</code>.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudio/createPartStudioTranslation</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;documentId&#34;: &#34;e60c4803eaf2ac8be492c18e&#34;, -&#34;requestElementId&#34;: &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;requestState&#34;: &#34;DONE&#34;, -&#34;resultExternalDataIds&#34;: &#34;[{resultId}]&#34;, -... -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Documents/downloadExternalData</a> to retrieve the exported result. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/documents/d/e60c4803eaf2ac8be492c18e/externaldata/{fid}&#39; -</code></pre><ul> -<li>Use the <code>resultExternalDataIds</code> value from the translation response as the foreign ID (<code>fid</code>).</li> -<li>The new SOLIDWORKS file is returned as the response and will be downloaded to wherever the API call is made.</li> -</ul> -</li> -</ol> -<h3 id="export-an-assembly-to-step">Export an Assembly to STEP</h3> -<p>In this example, we&rsquo;ll export an assembly from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/23a9385cd48c50167c32d6d1">this public document</a> to a STEP file.</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/23a9385cd48c50167c32d6d1">this public document</a> so you can export the assembly. Make a note of the documentId, workspaceId, and elementId of the assembly in your new document.</li> -<li>Validate that STEP is a supported export file type for assemblies by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validDestinationFormat=true</code> and <code>couldBeAssembly=true</code> for <code>translatorName=STEP</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;STEP&#34;, -&#34;translatorName&#34;: &#34;step&#34;, -&#34;couldBeAssembly&#34;: true -}, -... -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a>. Replace <code>{did}</code>, <code>{wid}</code>, and <code>{eid}</code> with the document, workspace, and element IDs from your copied document. Do NOT include the curly braces (<code>{}</code>) in the final call. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/assemblies/d/{did}/w/{wid}/e/{eid}/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;allowFaultyParts&#34;: true, -&#34;angularTolerance&#34;: 0.001, -&#34;formatName&#34;: &#34;STEP&#34;, -&#34;storeInDocument&#34;: true -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>In the example above, we&rsquo;ve just shown a snippet of the entire JSON where we allow faulty parts to be exported and set the angular tolerance to 0.001.</li> -<li>A <code>formatName</code> string must be specified that matches one of the valid formats you found in the last step. In this example, we set <code>formatName</code> to <code>STEP.</code></li> -<li>Set <code>storeInDocument</code> to <code>true</code> to upload the STEP file as a blob element in your document.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;resultDocumentId&#34; : &#34;{did}&#34;, -&#34;resultWorkspaceId&#34; : &#34;{wid}&#34;, -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;requestElementId&#34; : &#34;{eid}&#34;, -&#34;resultExternalDataIds&#34; : [ &#34;{resultExternalId}&#34; ], -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : {resulteid}, -&#34;name&#34; : &#34;GEARBOX_CHUCK&#34;, -&#34;id&#34; : &#34;{translationId}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v6/translations/{translationId}&#34; -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we make a note of the <code>resultElementId</code> in the response. This is the elementId of the STEP blob.</li> -<li>Now, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a> to retrieve the exported results. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{resulteid}&#39; \ --H &#39;accept: application/octet-stream&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><ul> -<li>Use the <code>resultElementIds</code> value from the translation response as the element ID (<code>{resulteid}</code>).</li> -<li>Note that you can also open your document, click the <code>GEARBOX_CHUCK.STEP</code> tab, and download the file from there.</li> -</ul> -</li> -</ol> -<h3 id="export-a-drawing-as-a-json">Export a Drawing as a JSON</h3> -<p>In this example, we&rsquo;ll export a Drawing from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/15b07287508246ccd038e31e">this public document</a> to a JSON file. Exporting a Drawing to JSON is useful when you need to gather information about that drawing (for example, finding valid coordinates on which to place an inspection symbol).</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/15b07287508246ccd038e31e">this public document</a> so you can export the assembly. Make a note of the documentId, workspaceId, and elementId of the assembly in your new document.</li> -<li>Validate that JSON is a supported export file type for Drawings by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Drawing/getDrawingTranslatorFormats</a> and confirming that <code>&quot;name&quot;: &quot;DRAWING_JSON&quot;</code> appears in the response for the drawing element in your copied document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;name&#34;: &#34;DRAWING_JSON&#34;, -&#34;translatorName&#34;: &#34;drawing_json&#34;, -&#34;couldBeAssembly&#34;: false -}, -... -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a>. Replace <code>{did}</code>, <code>{wid}</code>, and <code>{eid}</code> with the document, workspace, and element IDs from your copied document. Do NOT include the curly braces (<code>{}</code>) in the final call. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;formatName&#34;: &#34;DRAWING_JSON&#34; -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>The only required JSON field is <code>formatName</code>, in which we&rsquo;ve specified the format as found in the <code>getDrawingTranslatorFormats</code> response body.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;resultDocumentId&#34; : &#34;{did}&#34;, -&#34;resultWorkspaceId&#34; : &#34;{wid}&#34;, -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;requestElementId&#34; : &#34;{eid}&#34;, -&#34;resultExternalDataIds&#34; : [ &#34;{resultExternalId}&#34; ], -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : {eid}, -&#34;name&#34; : &#34;GEARBOX_CHUCK&#34;, -&#34;id&#34; : &#34;{translationId}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v6/translations/{translationId}&#34; -} -</code></pre><ul> -<li>Note that you can also call the <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getTranslation">Translation/getTranslation</a> endpoint on the <code>translationId</code> to see all in-progress translation information.</li> -</ul> -</li> -<li>Once <code>requestState=DONE</code>, we make a note of the <code>&quot;resultElementIds&quot; : {resulteid},</code> in the response. This is the element ID of the JSON blob.</li> -<li>Now, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a> to retrieve the exported results. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{resulteid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;accept: application/octet-stream&#39; -</code></pre><ul> -<li>Use the <code>{resultExternalId}</code> value from the translation response as the element ID (<code>{resulteid}</code>). Do not include the curly braces in your call.</li> -<li>Note that you can also open your document, click the <code>GEARBOX_CHUCK.JSON</code> tab, and download the file from there.</li> -</ul> -</li> -</ol> -<h3 id="import-a-parasolid-file-as-a-part">Import a Parasolid file as a Part</h3> -<p>In this example, we&rsquo;ll import the <em>FLYWHEEL</em> part from the <em>CRANK.x_t</em> file we created in the <a href="#export-a-part-to-parasolid">Export a Part to Parasolid</a> example.</p> -<ol> -<li>Open or create a new Onshape document in which to import the Part. Make a note of the documentId and workspaceId of your document.</li> -<li>Validate that Parasolid is a supported export file type for imports by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validSourceFormat=true</code> for <code>translatorName=parasolid</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;PARASOLID&#34;, -&#34;translatorName&#34;: &#34;parasolid&#34;, -&#34;couldBeAssembly&#34;: true -} -]s -</code></pre></li> -<li>Initialize the import by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/createTranslation">Translation/createTranslation</a>. In this example, the filename is <code>CRANK.x_t</code>. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39;s \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;formatName=&#39; \ --F &#39;flattenAssemblies=true&#39; \ --F &#39;translate=true&#39; \ --F &#39;file=@/pathToFile/CRANK.x_t&#39; \ -</code></pre><ul> -<li>Replace <code>{did}</code> and <code>{wid}</code> in the URL with the document and workspace IDs for the document you want to import the part to.</li> -<li>Note that when using cURL, you must begin the path to the file with an <code>@</code> symbol.</li> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the import.</li> -<li>When importing files, the API assumes we are importing to the <code>ONSHAPE</code> file type. You can override this and import to a different file type using the <code>formatName</code> field. In this case, we can leave the <code>formatName</code> field blank to import to the <code>ONSHAPE</code> file type.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getDocumentTranslations">Translation/getDocumentTranslations</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : [ &#34;{resulteid}&#34; ], -&#34;name&#34; : &#34;FLYWHEEL&#34;, -&#34;id&#34; : &#34;{id}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v1/translations/{tid}&#34; -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we can view the imported file as a Part in our Onshape document. The <code>FLYWHEEL</code> part appears in a new PartStudio named <code>CRANK</code> in our document.</li> -</ol> -<h3 id="export-a-configured-part">Export a configured part</h3> -<p>See the <a href="https://onshape-public.github.io/docs/api-adv/configs">Configurations API Guide</a> for examples.</p> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/help/Content/translation.htm">Onshape Help: Translation</a></li> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">Onshape Help: Webhooks</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/webhook">API Guide: Webhook Notifications</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Explorer</a></li> -</ul>Docs: Metadatahttps://onshape-public.github.io/docs/api-adv/metadata/Wed, 20 Dec 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/metadata/ -<p>This page describes the APIs Onshape provides for working with document metadata.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<h3 id="get-metadata">Get Metadata</h3> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWVMetadata">getWVMetadata</a>: Get metadata for a workspace or version. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEsMetadata">getWMVEsMetadata</a>: Get metadata for all elements in a document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">getWMVEMetadata</a>: Get metadata for an element. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPMetadata">getWMVEPMetadata</a>: Get metadata for a part. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/p/{pid}?rollbackBarIndex=-1&amp;inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPsMetadata">getWMVEPsMetadata</a>: Get metadata for all parts in a document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/p?inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getVEOPStandardContentMetadata">getVEOPStandardContentMetadata</a>: Get metadata for a standard content part. -<ul> -<li><code>{linkedDocumentId}</code>: ID of the document into which the standard content part is inserted.</li> -<li>You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/getAssemblyDefinition">getAssemblyDefinition</a> to get the other values needed for the call: -<ul> -<li><code>{did}</code>: ID of the document in which the standard content part lives.</li> -<li><code>{vid}</code>: ID of the version in which the standard content part lives.</li> -<li><code>{eid}</code>: ID of the element tab in which the standard content part lives.</li> -<li><code>{pid}</code>: Part ID of the standard content part.</li> -<li><code>{config}</code>: Encoded configuration string.</li> -</ul> -</li> -</ul> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/metadata/standardcontent/d/{did}/v/{vid}/e/{eid}/p/{pid}?configuration={config}&amp;linkDocumentId={linkDocument}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -</ul> -<h3 id="update-metadata">Update Metadata</h3> -<p>To update metadata, you send a JSON in the API request body. This JSON block must include a <code>jsonType</code> value and a <code>properties</code> object array. Each object in the <code>properties</code> array includes a <code>propertyId</code> and the metadata key/value pairs.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVMetadata">updateWVMetadata</a>: Update workspace or version metadata. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: (&#34;metadata-workspace&#34; | &#34;metadata-version&#34;) , -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId1&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -}, -{ -&#34;propertyId&#34;: &#34;propertyId2&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEMetadata">updateWVEMetadata</a>: Update element metadata. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEPMetadata">updateWVEPMetadata</a>: Update part metadata -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/{iden}/{pid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateVEOPStandardContentPartMetadata">updateVEOPStandardContentPartMetadata</a>: Update standard content part metadata. -<ul> -<li><code>{linkedDocumentId}</code>: ID of the document into which the standard content part is inserted.</li> -<li>You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/getAssemblyDefinition">getAssemblyDefinition</a> to get the other values needed for the call: -<ul> -<li><code>{did}</code>, <code>{vid}</code>, <code>{eid}</code>: IDs of the document, version, and element in which the standard content part lives.</li> -<li><code>{companyId}</code>: ID of the company that owns the standard content part. All metadata changes to this standard content part will populate for the entire company.</li> -<li><code>{pid}</code>: Part ID of the standard content part.</li> -<li><code>{config}</code>: Encoded configuration string.</li> -</ul> -</li> -<li>For each <code>items.properties</code> object, include a unique <code>propertyId</code> and at least one key/value metadata pair.</li> -<li>Updates made to standard content are global for all users and documents within the company.</li> -</ul> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/standardcontent/d/{did}?linkDocumentId={linkDocumentId}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;items&#34;: [ -{ -&#34;href&#34;: &#34;https://cad.onshape.com/api/metadata/standardcontent/d/did/v/vid/e/eid/c/companyId/p/pid?configuration=config&amp;linkDocumentId=linkDocumentId&amp;applyToAllConfigs=true&#34;, -&#34;properties&#34;: [ -{ -&#34;key&#34;: &#34;value&#34;, -&#34;propertyId&#34;: &#34;propertyId1&#34; -}, -{ -&#34;key&#34;: &#34;value&#34;, -&#34;propertyId&#34;: &#34;propertyId2&#34; -} -] -} -] -}&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="get-a-part-property">Get a part property</h3> -<p>In this example we&rsquo;ll get the name of a part by getting the metadata from the <code>DRILL_BIT</code> element in <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">Metadata/getWMVEMetadata</a> endpoint. Replace <code>CREDENTIALS</code> with your authentication credentials: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>In the response body, confirm that for <code>properties.name=Name</code>, <code>properties.value=DRILL_BIT</code>. -<pre tabindex="0"><code>{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;elementType&#34;: 0, -&#34;mimeType&#34;: &#34;onshape/partstudio&#34;, -&#34;elementId&#34;: &#34;958bceb5a2511b572dbbe851&#34;, -&#34;properties&#34;: [ -{ -&#34;name&#34;: &#34;Name&#34;, -&#34;value&#34;: &#34;DRILL_BIT&#34;, -&#34;defaultValue&#34;: null, -&#34;computedPropertyError&#34;: null, -&#34;propertySource&#34;: 0, -... -</code></pre></li> -</ol> -<h3 id="update-a-part-property">Update a part property</h3> -<p>In this example we will update a part&rsquo;s description by getting the current metadata for the part, and then posting an update to that metadata.</p> -<ol> -<li> -<p>Get your document information:</p> -<p>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID.</p> -</li> -<li> -<p>Get the ID of the part to update:</p> -<p>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> API on your copied document to get a list of part IDs in the element. Only one part exists in the document, with a part ID of <code>JHD</code>.</p> -<pre tabindex="0"><code>{ -&#34;name&#34;: &#34;Main&#34;, -... -&#34;microversionId&#34;: &#34;{mid}&#34;, -&#34;partNumber&#34;: null, -&#34;elementId&#34;: &#34;{eid}&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;bodyType&#34;: &#34;sheet&#34;, -... -} -</code></pre></li> -<li> -<p>Get the metadata of the part:</p> -<p>We&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPMetadata">Metadata/getWMVEPMetadata</a> endpoint to get the current metadata JSON for the part. Don&rsquo;t forget to replace the URL parameters with the IDs from your copied document, and replace <code>CREDENTIALS</code> with your authorization credentials.</p> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&amp;inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li> -<p>Locate the property to update in the response:</p> -<p>The call returns a response body in JSON format. Scroll to the <code>Description</code> properties block of the JSON response, and notice that the <code>value</code> field is an empty string.</p> -<pre tabindex="0"><code>... -{ -&#34;name&#34;: &#34;Description&#34;, -&#34;value&#34;: &#34;&#34;, -&#34;defaultValue&#34;: null, -&#34;computedPropertyError&#34;: null, -&#34;propertySource&#34;: 3, -&#34;validator&#34;: { }, -&#34;required&#34;: false, -&#34;editable&#34;: true, -&#34;propertyId&#34;: &#34;{propertyId}&#34;, -&#34;editableInUi&#34;: true, -&#34;dateFormat&#34;: null, -&#34;valueType&#34;: &#34;STRING&#34;, -&#34;enumValues&#34;: null, -&#34;multivalued&#34;: false, -&#34;computedAssemblyProperty&#34;: false, -&#34;computedProperty&#34;: false, -&#34;propertyOverrideStatus&#34;: 0 -}, -... -</code></pre></li> -<li> -<p>Find the metadata&rsquo;s property ID:</p> -<p>Copy Description&rsquo;s <code>propertyId</code>. We&rsquo;ll need this ID to update the metadata.</p> -</li> -<li> -<p>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEPMetadata">Metadata/updateWVEPMetadata</a> call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li> -<p>Add the request JSON to the call:</p> -<p>Note that we need to include the <code>jsonType</code>, the <code>partId</code>, the <code>propertyId</code>, and the value to update.</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Add the new property information:</p> -<p>In the request JSON, change the empty Description <code>value</code> string to <code>&quot;Drill bit&quot;</code>:</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;Drill bit&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>POST the new metadata:</p> -<p>Don&rsquo;t forget to replace the URL parameters and <code>CREDENTIALS</code> with your information.</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;Drill bit&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Confirm your changes:</p> -<p>Repeat steps 3 and 4 to confirm that the Description <code>value</code> for the part is now <code>Drill bit</code>.</p> -</li> -</ol> -<h3 id="update-a-tab-name">Update a tab name</h3> -<p>In this example we will update an element&rsquo;s tab name by getting the current metadata for the element, and then posting an update to that metadata. Remember that in Onshape, an element is typically represented as a tab in the Onshape UI.</p> -<ol> -<li> -<p>Get your document information:</p> -<p>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/4561b91a53c595c0010d5cdb">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID. Note the tab name of the element is &ldquo;NEW_PART&rdquo;.</p> -<p></br><img src="https://onshape-public.github.io/images/metadata-update-tab-before.png" alt="Onshape document with NEW_PART tab name" width=950></p> -</li> -<li> -<p>Get the metadata of the element:</p> -<p>We&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">Metadata/getWMVEMetadata</a> endpoint to get the current metadata JSON for the element. Don&rsquo;t forget to replace the URL parameters with the IDs from your copied document, and replace <code>CREDENTIALS</code> with your authorization credentials.</p> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li> -<p>Locate the property to update in the response:</p> -<p>The call returns a response body in JSON format. Scroll to the <code>Name</code> properties block of the JSON response, and notice that the <code>value</code> field matches our current tab name, &ldquo;NEW_PART&rdquo;.</p> -<pre tabindex="0"><code>{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;elementType&#34;: 0, -&#34;mimeType&#34;: &#34;onshape/partstudio&#34;, -&#34;elementId&#34;: &#34;{eid}&#34;, -&#34;properties&#34;: [ -{ -&#34;name&#34;: &#34;Name&#34;, -&#34;value&#34;: &#34;NEW_PART&#34;, -&#34;validator&#34;: {}, -&#34;required&#34;: true, -&#34;editable&#34;: true, -&#34;propertyId&#34;: &#34;{propertyId}&#34;, -}, -... -], -... -} -</code></pre></li> -<li> -<p>Find the metadata&rsquo;s property ID:</p> -<p>Copy the Name block&rsquo;s <code>propertyId</code> in the response. We&rsquo;ll need this ID to update the metadata.</p> -</li> -<li> -<p>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEMetadata">updateWVEMetadata</a> call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li> -<p>Add the request JSON to the call:</p> -<p>Note that we need to include the <code>propertyId</code> and the value to update.</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Add the new property information:</p> -<p>In the request JSON, replace <code>{propertyId}</code> with the property ID you found in Step 4, then change the empty <code>value</code> string to <code>&quot;PISTON&quot;</code>:</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;PISTON&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>POST the new metadata:</p> -<p>Don&rsquo;t forget to replace the URL parameters and <code>CREDENTIALS</code> with your information.</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;PISTON&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Confirm your changes:</p> -<p>Open your document and confirm that the tab name is now <code>PISTON</code>.</p> -<p></br><img src="https://onshape-public.github.io/images/metadata-update-tab-after.png" alt="Onshape document with NEW_PART tab name" width=950></p> -</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata">API Explorer: Metadata</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -</ul>Docs: Response Codeshttps://onshape-public.github.io/docs/api-adv/errors/Wed, 03 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/errors/ -<p>This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we&rsquo;ve provided a brief description of the response and recommended next steps.</p> -<h2 id="success-2xx">Success (2xx)</h2> -<p>The client call was successful.</p> -<h3 id="200---ok">200 - OK</h3> -<p>The client call was successful. No action needed.</p> -<h3 id="204---no-content">204 - No Content</h3> -<p>The client call was successful, and there&rsquo;s nothing to return in the response body. The empty response body cannot be parsed.</p> -<h2 id="redirect-3xx">Redirect (3xx)</h2> -<h3 id="307---temporary-redirect">307 - Temporary Redirect</h3> -<p>The client call was successful, and a redirection URL was returned. Follow the URL provided in the response.</p> -<h2 id="client-error-4xx">Client Error (4xx)</h2> -<p>There’s an error with the client request. Find the error code below, and follow the instructions for resolution.</p> -<h3 id="400---bad-request">400 - Bad Request</h3> -<p>The request cannot be processed by the server due a client-side error. This could be a malformed request syntax or other issue. Check the request parameters (GET and POST) and request body (POST) to determine the cause of the failure.</p> -<h3 id="401---unauthorized">401 - Unauthorized</h3> -<p>The request failed the authentication/authorization checks. This could mean that the client is not logged in, API keys are invalid, OAuth failed, etc. Make sure the client is <a href="https://onshape-public.github.io/docs/auth/">authenticated</a>.</p> -<h3 id="403---forbidden">403 - Forbidden</h3> -<p>The client doesn’t have the correct permissions to perform this operation. Check that the <a href="https://onshape-public.github.io/docs/auth/">API Keys or OAuth authentication</a> have sufficient permissions to perform the operation. For example, POST operations typically require <code>write</code> scope; if the API Key was created with only <code>read</code> scope, the server will return a 403 error.</p> -<p>You might also need to check document and user permissions. For more details, see <a href="https://cad.onshape.com/help/Content/sharedocuments.htm">Share Documents</a> (for everyone) and <a href="https://cad.onshape.com/help/Content/EnterpriseHelp/Content/permission_schemes.htm">Understanding and Administering Project Roles and Permission Schemes</a> (for Enterprise users and administrators).</p> -<h3 id="404---not-found">404 - Not Found</h3> -<p>The server can’t find what the client is looking for. For example, a 404 error will be returned if the client tries to make a GET request for a document that doesn’t exist.</p> -<h3 id="405---method-not-allowed">405 - Method Not Allowed</h3> -<p>Use of that method is not supported. For example, you cannot perform a DELETE request on a document version, because versions are read-only. Only GET requests on document versions are allowed.</p> -<h3 id="406----not-acceptable">406 - Not Acceptable</h3> -<p>The server cannot provide a response for the media type requested. See <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1">https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1</a>.</p> -<h3 id="409---conflict">409 - Conflict</h3> -<p>The client call includes duplicate values, causing a conflict. Modify the request to remove any conflicting values.</p> -<h3 id="415---media-type-not-supported">415 - Media Type Not Supported</h3> -<p>The client call includes unsupported data types or invalid JSON. Review the client code. When performing data imports and exports, follow all <a href="https://onshape-public.github.io/docs/api-adv/translation/">Translation guidelines</a> to ensure all media and file types are supported.</p> -<h3 id="429---too-many-requests">429 - Too Many Requests</h3> -<p>The client sent too many requests to a particular endpoint in a given time window. The number of requests allowed per time window vary and are subject to change. Onshape does not publish this information. If the client receives HTTP 429 responses, delay and then retry, or reduce its request rate.</p> -<h3 id="499---timeout">499 - Timeout</h3> -<p>This call is taking too long. Please try again later.</p> -<h2 id="server-error-5xx">Server Error (5xx)</h2> -<p>There’s an error with the Onshape servers. Find the error code below, and follow the instructions for resolution.</p> -<h3 id="500---internal-server-error">500 - Internal Server Error</h3> -<p>The request resulted in an error. Set a limit for the number of retries, and if the request continues to fail, reach out to <a href="api-support@onshape.com">support</a>.</p> -<h3 id="503---service-unavailable">503 - Service Unavailable</h3> -<p>Something is wrong with the Onshape servers. Retry after the delay specified in the response. Set a limit for the number of retries, and if the request continues to fail, reach out to <a href="api-support@onshape.com">support</a>.</p> \ No newline at end of file +API Guides onhttps://onshape-public.github.io/docs/api-adv/Recent content in API Guides onHugoen-usThu, 15 Aug 2024 00:00:00 +0000Assemblieshttps://onshape-public.github.io/docs/api-adv/assemblies/Tue, 13 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/assemblies/This page describes the APIs Onshape provides for working with assemblies. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2. This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}.Associativityhttps://onshape-public.github.io/docs/api-adv/associativity/Mon, 18 May 2020 20:28:26 -0400https://onshape-public.github.io/docs/api-adv/associativity/Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be: +Read the tessellated model data. Select the face of interest. Store the Face ID and Document Microversion ID for the face.Billinghttps://onshape-public.github.io/docs/api-adv/billing/Mon, 18 May 2020 20:29:36 -0400https://onshape-public.github.io/docs/api-adv/billing/This document describes APIs that will allow partners to interact with the Onshape billing system. +Please address questions to &ldquo;api-support@onshape.com&rdquo; for the fastest response. +Overview All billing is done through &ldquo;plans&rdquo; that are created in the Developer Portal. A “plan” has the following attributes: +Name (also called SKU) A unique (within your company) plan name Description A user-visible description of the plan Amount The cost of the plan (may be one-time or recurring, depending on the type) Type Monthly, One-time or Consumable Onshape defines three kinds of plans:Configurationshttps://onshape-public.github.io/docs/api-adv/configs/Fri, 05 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/configs/This page describes the APIs Onshape provides for working with Configurations. +You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing.Drawingshttps://onshape-public.github.io/docs/api-adv/drawings/Thu, 12 Oct 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/drawings/This page describes the APIs Onshape provides for creating and manipulating Onshape drawings. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Featureshttps://onshape-public.github.io/docs/api-adv/featureaccess/Mon, 18 May 2020 20:37:28 -0400https://onshape-public.github.io/docs/api-adv/featureaccess/This page describes the APIs Onshape provides for creating and manipulating features and the Feature List in a Part Studio. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Evaluating FeatureScripthttps://onshape-public.github.io/docs/api-adv/fs/Thu, 15 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/fs/This page describes some of the APIs Onshape provides for evaluating FeatureScript. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Import & Exporthttps://onshape-public.github.io/docs/api-adv/translation/Wed, 27 Sep 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/translation/This page describes the APIs Onshape provides for importing files to Onshape and exporting files from Onshape into different formats. We refer to the process of importing and exporting files from one format to another as translating the files. +Onshape provides several APIs to support this format translation. These fall into three categories: +Synchronous exports - Export Onshape content to glTF, STL, or Parasolid format. Asynchronous exports - Export Onshape content into a variety of other formats.Metadatahttps://onshape-public.github.io/docs/api-adv/metadata/Wed, 20 Dec 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/metadata/This page describes the APIs Onshape provides for working with document metadata. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Response Codeshttps://onshape-public.github.io/docs/api-adv/errors/Wed, 03 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/errors/This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we&rsquo;ve provided a brief description of the response and recommended next steps. +Success (2xx) The client call was successful. +200 - OK The client call was successful. No action needed. +204 - No Content The client call was successful, and there&rsquo;s nothing to return in the response body. The empty response body cannot be parsed. \ No newline at end of file diff --git a/docs/api-adv/metadata/index.html b/docs/api-adv/metadata/index.html index 67b3617..4214234 100644 --- a/docs/api-adv/metadata/index.html +++ b/docs/api-adv/metadata/index.html @@ -1,15 +1,12 @@ -Metadata | Metadata |

    Metadata

    This page describes the APIs Onshape provides for working with document metadata.

    📘 Notes

    \ No newline at end of file diff --git a/docs/api-adv/translation/index.html b/docs/api-adv/translation/index.html index 6f57691..6477c89 100644 --- a/docs/api-adv/translation/index.html +++ b/docs/api-adv/translation/index.html @@ -1,11 +1,12 @@ -Import & Export | Import & Export |

    Import & Export

    This page describes the APIs Onshape provides for importing files to Onshape and exporting files from Onshape into different formats. We refer to the process of importing and exporting files from one format to another as translating the files.

    Onshape provides several APIs to support this format translation. These fall into three categories:

    📘 Notes

    \ No newline at end of file diff --git a/docs/api-intro/architecture/index.html b/docs/api-intro/architecture/index.html index 1979782..2f31fed 100644 --- a/docs/api-intro/architecture/index.html +++ b/docs/api-intro/architecture/index.html @@ -1,5 +1,5 @@ -Architecture |

    Architecture

    Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also:

    • The API Introduction page for information on how documents, workspaces, and elements are assembled into a URL.
    • The Associativity page for information on how Parts, Assemblies, and Elements relate to each other.

    Elements

    All data in an Onshape document are stored in Elements (represented as tabs in the user interface). Onshape documents contain five kinds of elements:

    • Part Studio: Contains zero or more parts
    • Assembly: Contains zero or more parts or assemblies
    • Blob (Binary Large OBject): Can be provided by a partner or by the end user. For example, the user can upload a PDF file, an image, or a text file. Partner applications can store arbitrary data, but we recommend using the structured storage available in an element for better integration.
    • Application: Presents an iframe to the user. The user interface is managed by a server that can be provided by a third-party. Onshape Drawings are a special case of an application element.
    • Feature Studio: Contains the definition for Onshape Features, which are defined in FeatureScript.

    Workspaces, Versions, and Microversions

    A document is stored in Onshape as a collection of changes.

    • You can think of a workspace as a branch of the document, similar to a branch in a source control system. Documents can be branched to create new workspaces.
    • Each individual change to the document creates a new document microversion. As the document is edited, changes are applied to the active workspace, creating new microversions.
    • Periodically, the user may designate versions of the document. A version is a named snapshot of the entire document at some point in time (that is, at some microversion).

    You cannot change a version or microversion of a document; all changes are applied to a workspace (and create a new microversion). Thus, while in general the GET methods of the API can read from a version, microversion, or workspace, the POST methods generally require a workspace, and create a new microversion when data is written to the document. (An exception is that it is possible to set metadata within a version; this does not create a new microversion).

    The following IDs are used by many of the APIs. Each ID (except for Geometry IDs such as Part, Face and Edge) is a 24-character string that is used internally by Onshape to uniquely identify the resource. The Geometry IDs are variable-length strings used to resolve to a specific geometric entity within a model.

    IDDescription
    User IDIdentifies a single user.
    Document IDIdentifies a document. The logged-in user must have access to the requested document for the API to succeed.
    Workspace IDThe Workspace ID identifies a workspace within the document. Workspaces are used to distinguish between different branches of the document.
    Version IDThe Version ID identifies a specific named version.
    Microversion IDThe Microversion ID identifies an internal revision of the document.
    Element IDThe Element ID identifies an element within the document.
    Part ID
    Face ID
    Edge ID
    The Part ID identifies a part within a part studio. The Part ID should generally not be stored for long-term use, as it is only expected to be valid during the course of a session.

    Note that a Part ID may reference a part that no longer exists if the model is changed, so it is best to specify a Version or Microversion to pick the context for the Part ID. Note that even with the Version or Microversion, internal changes to the Onshape system may also change the Part ID. Onshape provides mechanisms for maintaining persistent references. See the Associativity page for more information. Face and Edge IDs are used in similar ways.

    The following table identifies Onshape concepts and the corresponding Git concepts. Note that this is not a direct mapping, and the implementation of the concepts is very different.

    Onshape conceptGit concept
    DocumentRepository
    ElementFile
    WorkspaceBranch
    VersionTag
    MicroversionCommit

    Linked Documents

    Although a document can contain a complex model tree involving many Part Studio and Assembly elements, it is often more efficient to split the content into multiple documents. Connections between documents always refer to a specific version of the target document. Once a version is used as the target of a linked document, that document version is preserved as long as any document references it, even if the containing document is deleted. Additionally, any user that has access to the referring document will have limited read access to the target document, regardless of what permissions are currently on the target document.

    Configurations

    Onshape Part Studios can be constructed to be configurable using Onshape Configurations. API calls that reference Part Studios (primarily within the Parts and Part Studios APIs) often accept a configuration parameter that identifies what specific configuration of the Part Studios is being referenced. When not specified, the API implementation typically uses the configuration that is currently selected within the Part Studio. An interactive ad-hoc API call might not behave consistently in an application, so be sure to specify the configuration parameter where applicable.

    Onshape Data Model

    Onshape data is stored in replicated databases in the cloud. The Onshape data model is influenced by the Git data model and similar source code repositories.

    Documents contain elements. Elements are presented as tabs in the user interface. With some exceptions, all data in a document is stored within an element. The following table describes what data stored in each Element type:

    Element TypeDescription
    Part StudioEach Part Studio contains exactly one Feature list. The Feature list contains Features such as sketches, planes, extrudes, etc. Each Feature contains one or parameters. Whenever the Feature list changes, the parametric history is evaluated, and the model is regenerated.
    AssemblyEach Assembly contains an assembly tree, which contains parts and/or other assemblies (sub-assemblies), along with mate information. Onshape provides an API call to retrieve the assembly tree definition.
    BlobEach Blob element contains an uninterpreted binary object that has been uploaded to Onshape, typically from a file. Onshape depends on the browser client to display some blob data (e.g., PDF and image data), but does not interpret the data. A blob element can be updated with new data.
    ApplicationEach Application element contains zero or more sub-elements, providing a structured set of transactional data that is defined and managed by an application. Application data can be displayed in the Onshape tab in an iframe; the application is responsible for rendering the data in the iframe from its server.

    Note that Onshape Drawing elements are Application elements managed by Onshape.

    Tessellated data is not stored persistently in Onshape; it is generated on demand for display by the Onshape clients, or in response to application REST API requests. This data may be cached for performance.

    Document data

    All elements, including Assemblies, Part Studios, Drawings, or even apps, are history based. Each change to an element or set of elements represents a unique record in the document’s history, known as a microversion. The document can be restored to that particular state any time in the future.

    Part Studio data

    The Part Studio element is defined by a list of features, some of which (e.g., a sketch), may have a complex internal structure composed of entities. Part Studio features and entities are referenced by unique persistent identifiers. Part Studio features and entities can appear, disappear, and reappear depending on the current microversion of the model.

    Assembly data

    The Assembly element is defined as a list of assembly features and a tree of subassemblies/part instances. Occurrence ID is a unique persistent identifier of an occurrence of a part in the assembly structure.

    External application data

    An external application has complete control over how it manages/stores documents, however, to take advantage of the Onshape data model, there is a set of endpoints they should use to store state. These are collectively known as the AppElement API.

    Model presentation data

    A valid model definition usually corresponds to a real-world manufacturable topology, represented internally as a set of parts, faces, edges, and vertices and the set of relations between them. Each of these has a unique identifier in every state of the model. The identifier represents an encoded index in the model’s history, and its value depends on the structure of the model’s history. The value is not guaranteed to be preserved across model changes, and will almost always change if the model changes in significant ways. The model can be tessellated into a set of geometric primitives, which approximate the shape of the model. Tessellated data can be used for visual representation of the model or other processing related to the shape of the model.

    The following changes in the topological representation can occur between two microversions of the model:

    • New topological entities appear
    • Id of existing topology change
    • Topological entities disappear
    • Existing topological entities are merged into a single entity
    • Existing topological entity are split into multiple entities

    The model microversion and topology ID can be used to identify topological entities across the model changes. Topology ID defined in a specific microversion can be translated into a set of topology IDs in the current microversion of the model. (The Topology ID is sometimes referred to as a Deterministic ID within Onshape, and is exposed in specific API calls as partId, faceId, etc.). See the PartStudio APIs to see what topology IDs are exposed.

    \ No newline at end of file +Architecture |

    Architecture

    Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also:

    • The API Introduction page for information on how documents, workspaces, and elements are assembled into a URL.
    • The Associativity page for information on how Parts, Assemblies, and Elements relate to each other.

    Elements

    All data in an Onshape document are stored in Elements (represented as tabs in the user interface). Onshape documents contain five kinds of elements:

    • Part Studio: Contains zero or more parts
    • Assembly: Contains zero or more parts or assemblies
    • Blob (Binary Large OBject): Can be provided by a partner or by the end user. For example, the user can upload a PDF file, an image, or a text file. Partner applications can store arbitrary data, but we recommend using the structured storage available in an element for better integration.
    • Application: Presents an iframe to the user. The user interface is managed by a server that can be provided by a third-party. Onshape Drawings are a special case of an application element.
    • Feature Studio: Contains the definition for Onshape Features, which are defined in FeatureScript.

    Workspaces, Versions, and Microversions

    A document is stored in Onshape as a collection of changes.

    • You can think of a workspace as a branch of the document, similar to a branch in a source control system. Documents can be branched to create new workspaces.
    • Each individual change to the document creates a new document microversion. As the document is edited, changes are applied to the active workspace, creating new microversions.
    • Periodically, the user may designate versions of the document. A version is a named snapshot of the entire document at some point in time (that is, at some microversion).

    You cannot change a version or microversion of a document; all changes are applied to a workspace (and create a new microversion). Thus, while in general the GET methods of the API can read from a version, microversion, or workspace, the POST methods generally require a workspace, and create a new microversion when data is written to the document. (An exception is that it is possible to set metadata within a version; this does not create a new microversion).

    The following IDs are used by many of the APIs. Each ID (except for Geometry IDs such as Part, Face and Edge) is a 24-character string that is used internally by Onshape to uniquely identify the resource. The Geometry IDs are variable-length strings used to resolve to a specific geometric entity within a model.

    IDDescription
    User IDIdentifies a single user.
    Document IDIdentifies a document. The logged-in user must have access to the requested document for the API to succeed.
    Workspace IDThe Workspace ID identifies a workspace within the document. Workspaces are used to distinguish between different branches of the document.
    Version IDThe Version ID identifies a specific named version.
    Microversion IDThe Microversion ID identifies an internal revision of the document.
    Element IDThe Element ID identifies an element within the document.
    Part ID
    Face ID
    Edge ID
    The Part ID identifies a part within a part studio. The Part ID should generally not be stored for long-term use, as it is only expected to be valid during the course of a session.

    Note that a Part ID may reference a part that no longer exists if the model is changed, so it is best to specify a Version or Microversion to pick the context for the Part ID. Note that even with the Version or Microversion, internal changes to the Onshape system may also change the Part ID. Onshape provides mechanisms for maintaining persistent references. See the Associativity page for more information. Face and Edge IDs are used in similar ways.

    The following table identifies Onshape concepts and the corresponding Git concepts. Note that this is not a direct mapping, and the implementation of the concepts is very different.

    Onshape conceptGit concept
    DocumentRepository
    ElementFile
    WorkspaceBranch
    VersionTag
    MicroversionCommit

    Linked Documents

    Although a document can contain a complex model tree involving many Part Studio and Assembly elements, it is often more efficient to split the content into multiple documents. Connections between documents always refer to a specific version of the target document. Once a version is used as the target of a linked document, that document version is preserved as long as any document references it, even if the containing document is deleted. Additionally, any user that has access to the referring document will have limited read access to the target document, regardless of what permissions are currently on the target document.

    Configurations

    Onshape Part Studios can be constructed to be configurable using Onshape Configurations. API calls that reference Part Studios (primarily within the Parts and Part Studios APIs) often accept a configuration parameter that identifies what specific configuration of the Part Studios is being referenced. When not specified, the API implementation typically uses the configuration that is currently selected within the Part Studio. An interactive ad-hoc API call might not behave consistently in an application, so be sure to specify the configuration parameter where applicable.

    Onshape Data Model

    Onshape data is stored in replicated databases in the cloud. The Onshape data model is influenced by the Git data model and similar source code repositories.

    Documents contain elements. Elements are presented as tabs in the user interface. With some exceptions, all data in a document is stored within an element. The following table describes what data stored in each Element type:

    Element TypeDescription
    Part StudioEach Part Studio contains exactly one Feature list. The Feature list contains Features such as sketches, planes, extrudes, etc. Each Feature contains one or parameters. Whenever the Feature list changes, the parametric history is evaluated, and the model is regenerated.
    AssemblyEach Assembly contains an assembly tree, which contains parts and/or other assemblies (sub-assemblies), along with mate information. Onshape provides an API call to retrieve the assembly tree definition.
    BlobEach Blob element contains an uninterpreted binary object that has been uploaded to Onshape, typically from a file. Onshape depends on the browser client to display some blob data (e.g., PDF and image data), but does not interpret the data. A blob element can be updated with new data.
    ApplicationEach Application element contains zero or more sub-elements, providing a structured set of transactional data that is defined and managed by an application. Application data can be displayed in the Onshape tab in an iframe; the application is responsible for rendering the data in the iframe from its server.

    Note that Onshape Drawing elements are Application elements managed by Onshape.

    Tessellated data is not stored persistently in Onshape; it is generated on demand for display by the Onshape clients, or in response to application REST API requests. This data may be cached for performance.

    Document data

    All elements, including Assemblies, Part Studios, Drawings, or even apps, are history based. Each change to an element or set of elements represents a unique record in the document’s history, known as a microversion. The document can be restored to that particular state any time in the future.

    Part Studio data

    The Part Studio element is defined by a list of features, some of which (e.g., a sketch), may have a complex internal structure composed of entities. Part Studio features and entities are referenced by unique persistent identifiers. Part Studio features and entities can appear, disappear, and reappear depending on the current microversion of the model.

    Assembly data

    The Assembly element is defined as a list of assembly features and a tree of subassemblies/part instances. Occurrence ID is a unique persistent identifier of an occurrence of a part in the assembly structure.

    External application data

    An external application has complete control over how it manages/stores documents, however, to take advantage of the Onshape data model, there is a set of endpoints they should use to store state. These are collectively known as the AppElement API.

    Model presentation data

    A valid model definition usually corresponds to a real-world manufacturable topology, represented internally as a set of parts, faces, edges, and vertices and the set of relations between them. Each of these has a unique identifier in every state of the model. The identifier represents an encoded index in the model’s history, and its value depends on the structure of the model’s history. The value is not guaranteed to be preserved across model changes, and will almost always change if the model changes in significant ways. The model can be tessellated into a set of geometric primitives, which approximate the shape of the model. Tessellated data can be used for visual representation of the model or other processing related to the shape of the model.

    The following changes in the topological representation can occur between two microversions of the model:

    • New topological entities appear
    • Id of existing topology change
    • Topological entities disappear
    • Existing topological entities are merged into a single entity
    • Existing topological entity are split into multiple entities

    The model microversion and topology ID can be used to identify topological entities across the model changes. Topology ID defined in a specific microversion can be translated into a set of topology IDs in the current microversion of the model. (The Topology ID is sometimes referred to as a Deterministic ID within Onshape, and is exposed in specific API calls as partId, faceId, etc.). See the PartStudio APIs to see what topology IDs are exposed.

    \ No newline at end of file diff --git a/docs/api-intro/explorer/index.html b/docs/api-intro/explorer/index.html index 62fe166..c24d1d8 100644 --- a/docs/api-intro/explorer/index.html +++ b/docs/api-intro/explorer/index.html @@ -1,16 +1,15 @@ -API Explorer | API Explorer |

    API Explorer

    We document all available Onshape REST API endpoints in our Glassworks API Explorer:

    https://cad.onshape.com/glassworks/explorer/


    This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below:

    1. Open this public Onshape document in your browser: +Open this public Onshape document in your browser: https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22 Open the API Explorer in a new browser tab: https://cad.">

      API Explorer

      We document all available Onshape REST API endpoints in our Glassworks API Explorer:

      https://cad.onshape.com/glassworks/explorer/


      This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below:

      1. Open this public Onshape document in your browser: https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22
      2. Open the API Explorer in a new browser tab: https://cad.onshape.com/glassworks/explorer/
        • Note: For Enterprise accounts, substitue cad in this URL with your company name.
      3. Scroll down to Document.
      4. Click to expand the getDocument endpoint. (Hint: it appears in the API Ref as GET /documents/{did}).
      5. Go back to the public document you opened in Step 2, and copy the document ID from the Onshape URL (e60c4803eaf2ac8be492c18e). -image
      6. Paste the document ID into the did field in the API Explorer.
        • Note: If you can’t edit the did field, click the Try it out button. This will toggle to a Cancel button when the fields are editable.
      7. Scroll down and click Execute.
        • Note: If you receive a 403 error, see the Authentication section for help.
      8. Scroll to the bottom of the 200 response body. We have correctly returned Onshape API Guide as the document name.

      gif of using glassworks

      IMPORTANT NOTE: The documentation in the API Explorer reflects the supported interface. Some API calls may, for historical reasons, return additional undocumented fields. Unless the return fields are documented in the API Explorer, you should NOT use them, as they may be removed without warning. Your application should always ignore unexpected or undocumented return data. Onshape reserves the right to add, remove or change any undocumented fields.

      Authentication

      You can authenticate in the API Explorer in one of three ways:

      1. Onshape:
        1. Open Onshape in a new tab in your browser.
        2. Sign in with your Onshape credentials. Onshape will pass your credentials to the API Explorer.
      2. API Keys:
        1. Click Authorize in the top-right of the API Explorer page and scroll to the bottom of the dialog.
          Glassworks Authorize button
        2. Provide your API access key in the Username field and your secret key in the Password field. See API Keys for help creating your API Keys. Do NOT enter your Onshape credentials.
          drawing
        3. Click Authorize, and then click Close.
      3. Oauth:
        1. Click Authorize in the top-right of the API Explorer page.
          Glassworks Authorize button
        2. Fill out the OAuth fields. See OAuth for more information on autheneticating with OAuth2.
        3. Click Authorize, and then click Close.

      Use the Auto-fill feature

      1. Expand the endpoint you want to use in the API Explorer.
      2. Paste an entire Onshape URL into the top field.
      3. Click Auto-fill. The document ID, workspace/version/microversion ID, and element ID are pushed from the URL into the correct fields.
      4. Confirm all fields are filled out as expected. Not every parameter can be extracted from an Onshape URL, so there may be more fields to fill out.

      glassworks api explorer auto fill feature

      View response body docs

      1. Expand the endpoint you want to use the in API Explorer.
      2. Scroll down to the Responses section.
      3. Click Schema.
      4. Click the [...] symbols to expand the docs for the response JSON.

      glassworks api explorer response json docs

      View request body docs

      1. Expand the endpoint you want to use the in API Explorer.
      2. Click the Cancel button to make the schema viewable.
      3. Click Schema.
      4. Click the [...] symbols to expand the docs for the response JSON.

      glassworks api explorer response json docs

      Copy a cURL

      1. Expand the endpoint you want to use in the API Explorer.
      2. Fill out the parameter fields.
      3. Click Execute in the API Explorer.
      4. Copy the curl from the Curl field.

      api explorer curl copy

      Troubleshooting

      • If the parameter fields in the API Explorer are grayed out, click the Try it Out! button to toggle it to a Cancel button. The parameter fields should become editable.
      • If you can’t see the request body JSON docs, click the Cancel button to toggle it back to the Try it Out! button.
      • If you see authentication issues, review the Authentication section above.
      \ No newline at end of file +image
    2. Paste the document ID into the did field in the API Explorer.
      • Note: If you can’t edit the did field, click the Try it out button. This will toggle to a Cancel button when the fields are editable.
    3. Scroll down and click Execute.
      • Note: If you receive a 403 error, see the Authentication section for help.
    4. Scroll to the bottom of the 200 response body. We have correctly returned Onshape API Guide as the document name.

    gif of using glassworks

    IMPORTANT NOTE: The documentation in the API Explorer reflects the supported interface. Some API calls may, for historical reasons, return additional undocumented fields. Unless the return fields are documented in the API Explorer, you should NOT use them, as they may be removed without warning. Your application should always ignore unexpected or undocumented return data. Onshape reserves the right to add, remove or change any undocumented fields.

    Authentication

    You can authenticate in the API Explorer in one of three ways:

    1. Onshape:
      1. Open Onshape in a new tab in your browser.
      2. Sign in with your Onshape credentials. Onshape will pass your credentials to the API Explorer.
    2. API Keys:
      1. Click Authorize in the top-right of the API Explorer page and scroll to the bottom of the dialog.
        Glassworks Authorize button
      2. Provide your API access key in the Username field and your secret key in the Password field. See API Keys for help creating your API Keys. Do NOT enter your Onshape credentials.
        drawing
      3. Click Authorize, and then click Close.
    3. Oauth:
      1. Click Authorize in the top-right of the API Explorer page.
        Glassworks Authorize button
      2. Fill out the OAuth fields. See OAuth for more information on autheneticating with OAuth2.
      3. Click Authorize, and then click Close.

    Use the Auto-fill feature

    1. Expand the endpoint you want to use in the API Explorer.
    2. Paste an entire Onshape URL into the top field.
    3. Click Auto-fill. The document ID, workspace/version/microversion ID, and element ID are pushed from the URL into the correct fields.
    4. Confirm all fields are filled out as expected. Not every parameter can be extracted from an Onshape URL, so there may be more fields to fill out.

    glassworks api explorer auto fill feature

    View response body docs

    1. Expand the endpoint you want to use the in API Explorer.
    2. Scroll down to the Responses section.
    3. Click Schema.
    4. Click the [...] symbols to expand the docs for the response JSON.

    glassworks api explorer response json docs

    View request body docs

    1. Expand the endpoint you want to use the in API Explorer.
    2. Click the Cancel button to make the schema viewable.
    3. Click Schema.
    4. Click the [...] symbols to expand the docs for the response JSON.

    glassworks api explorer response json docs

    Copy a cURL

    1. Expand the endpoint you want to use in the API Explorer.
    2. Fill out the parameter fields.
    3. Click Execute in the API Explorer.
    4. Copy the curl from the Curl field.

    api explorer curl copy

    Troubleshooting

    • If the parameter fields in the API Explorer are grayed out, click the Try it Out! button to toggle it to a Cancel button. The parameter fields should become editable.
    • If you can’t see the request body JSON docs, click the Cancel button to toggle it back to the Try it Out! button.
    • If you see authentication issues, review the Authentication section above.
    \ No newline at end of file diff --git a/docs/api-intro/index.html b/docs/api-intro/index.html index 5385f02..d685916 100644 --- a/docs/api-intro/index.html +++ b/docs/api-intro/index.html @@ -1,5 +1,7 @@ -Introduction to the Onshape REST API |

    Introduction to the Onshape REST API

    This page explains the basics of using the Onshape REST API. If you are brand new to using APIs, we suggest you spend some time learning the basics from these free resources:

    Onshape uses REST APIs to communicate with clients and third-party systems. Onshape lives in your browser, which means you call REST APIs like you would any other web page. The API call returns information instead of a web page, and the response is formatted in JSON (JavaScript Object Notation).

    You can use our REST APIs to access the Onshape engine and data in real time. We currently support three REST API requests (following the HTTP standards):

    • GET: Retrieve (read) information from the server (i.e., your Onshape documents). Any arguments included in the URL are sent to the server.
    • POST: Update (write) the server with new information. Required data is included in the request body.
    • DELETE: Delete information from the server.

    A typical REST API call in Onshape includes five major components:

    • Method:
      • GET, POST, or DELETE
      • Every Onshape API endpoint is labeled with its method type.
    • URL:
      • Specifies the API endpoint and part of the document that the API is calling
      • Uses the following format: {base_url}/{fixed_url}.
        • {base_url}: Onshape URL (i.e., https://cad.onshape.com/api or https://companyName.onshape.com/api for Enterprise accounts).
        • {fixed_url}: the URL of the API endpoint (more about this later)
    • Query parameters:
      • Optional parameters for the API call
      • Described in the drop-down content of every endpoint in the API Explorer (you’ll learn about using our API Explorer in a later section).
    • Headers:
      • Defines the associated metadata, which is used by the server to process the request.
      • Usually contains Content-Type and Accept.
        • Content-Type:
          • Usually application/json
          • If the application downloads a file, Content-Type will be application/octet-stream
        • Accept: found under Media type in the API response section on in the API Explorer.
    • Payload body:
      • Only applicable for POST requests
      • Required for some POST requests; optional for others.
      • Body template is available in the API drop-down in the API Explorer.
      • Typically obtained and modified from the response of a related GET request (rather than manually)

    Onshape API Request

    Since Onshape is a web-based solution, it uses a URL to define what is loaded in the browser.

    Example Onshape URL: +Introduction to the Onshape REST API |

    Introduction to the Onshape REST API

    This page explains the basics of using the Onshape REST API. If you are brand new to using APIs, we suggest you spend some time learning the basics from these free resources:

    Onshape uses REST APIs to communicate with clients and third-party systems. Onshape lives in your browser, which means you call REST APIs like you would any other web page. The API call returns information instead of a web page, and the response is formatted in JSON (JavaScript Object Notation).

    You can use our REST APIs to access the Onshape engine and data in real time. We currently support three REST API requests (following the HTTP standards):

    • GET: Retrieve (read) information from the server (i.e., your Onshape documents). Any arguments included in the URL are sent to the server.
    • POST: Update (write) the server with new information. Required data is included in the request body.
    • DELETE: Delete information from the server.

    A typical REST API call in Onshape includes five major components:

    • Method:
      • GET, POST, or DELETE
      • Every Onshape API endpoint is labeled with its method type.
    • URL:
      • Specifies the API endpoint and part of the document that the API is calling
      • Uses the following format: {base_url}/{fixed_url}.
        • {base_url}: Onshape URL (i.e., https://cad.onshape.com/api or https://companyName.onshape.com/api for Enterprise accounts).
        • {fixed_url}: the URL of the API endpoint (more about this later)
    • Query parameters:
      • Optional parameters for the API call
      • Described in the drop-down content of every endpoint in the API Explorer (you’ll learn about using our API Explorer in a later section).
    • Headers:
      • Defines the associated metadata, which is used by the server to process the request.
      • Usually contains Content-Type and Accept.
        • Content-Type:
          • Usually application/json
          • If the application downloads a file, Content-Type will be application/octet-stream
        • Accept: found under Media type in the API response section on in the API Explorer.
    • Payload body:
      • Only applicable for POST requests
      • Required for some POST requests; optional for others.
      • Body template is available in the API drop-down in the API Explorer.
      • Typically obtained and modified from the response of a related GET request (rather than manually)

    Onshape API Request

    Since Onshape is a web-based solution, it uses a URL to define what is loaded in the browser.

    Example Onshape URL: https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22

    • https://cad.onshape.com/api is the base URL of the document.
      • Every Enterprise account has a custom base URL: https://companyName.onshape.com/api
    • documents/ or d/ is followed by a 24-character document ID. The document ID uniquely identifies an Onshape document.
    • Next, w/ is followed by a 24-character workspace ID. The workspace ID uniquely identifies a workspace within the document. By default, a document is started with the Main workspace.
      • To refer to a specific document version, replace w/ with v/, followed by the 24-character version ID.
      • With every edit made in the document, a microversion of every document is automatically created with every edit. To refer to a specific microversion, replace w/ with m/, followed by the 24-character microversion ID.
      • Note: POST requests are always made to a workspace, since versions and microversions are immutable.
    • e/ is followed by a 24-character element ID. The element ID uniquely identifies an element (e.g., a tab that we see and access through the user interface).

    In this documentation, we often refer to the URL template as: {base_URL}/{endpoint}/d/{did}/{wvm}/{wvmid}/e/{eid} or sometimes /{endpoint}/DWVME/ for short.

    When your application is instantiated in a document, it is called with a URL like this:

    https://_your-server.your-domain.com_?documentId=e60c4803eaf2ac8be492c18e&workspaceId=d2558da712764516cc9fec62&elementId=6bed6b43463f6a46a37b4a22&server=https%3A%2F%2Fcad.onshape.com&userId=53da35fbe4b0412c60b5e3b7&access=edit&debug=true
     

    The query parameters passed from Onshape to your application are:

    ParameterDescription
    documentIdCurrent document ID
    workspaceId, versionId, microversionIdCurrent workspace ID OR version ID OR microversion ID
    elementIdCurrent (application) element ID
    serverThe address of the current Onshape server. The server parameter is informational; REST requests should always be sent to cad.onshape.com. Enterprise accounts should be sent to companyName.onshape.com.
    userIdCurrent user ID, which can be found by calling /api/users/current and obtaining the user ID from the id field.
    accessSet to edit if the document should open with edit capabilities.

    Onshape API Response

    The REST API in Onshape communicates data in JSON format. If you are new to working with JSON, we recommend the following resources:

    The example below is the response from calling the getDocument API for this public document. A lot of information is returned, so we’ve truncated the middle of the response below, but if we look at the very end of the resulting JSON, we can see that the response has correctly returned Onshape API Guide as the document name.

      {
         "jsonType": "document",
    @@ -16,4 +18,4 @@
         "id": "e60c4803eaf2ac8be492c18e",
         "href": "https://cad.onshape.com/api/v6/documents/e60c4803eaf2ac8be492c18e"
     }
    -

    The Onshape API response also contains rate limiting information in the x-rate-limit-remaining header.

    Versioning

    All endpoint calls are versioned. The version string is inserted directly after the /api/ path component. For instance, https://cad.onshape.com/api/v6/documents/e60c4803eaf2ac8be492c18e indicates a version 6 request to the Onshape getDocument endpoint.

    Calls within a version are compatible with one another; typically this means that a GET request can be fed back in as a POST at the same version. Versions are incremented whenever Onshape introduces a non-backwards-compatible change. Onshape users should always refer to the latest version in their calls. If no version is specified, the oldest version (v0) will be used.

    API Conventions

    The Onshape API generally uses the following conventions:

    • Onshape generally supports only 3 methods: GET for read-only operations, POST for write operations, and DELETE for deletions. Onshape does not currently support other methods, such as PUT.
    • Strings should be UTF-8 encoded.
    • Query parameters are used for optional parameters. All required parameters are included in the path. For brevity, we use the following upper case letters in path definitions in this document:
      • D Document ID (24-characters)
      • W Workspace ID (24-characters)
      • V Version ID (24-characters)
      • M Microversion ID (24-characters)
      • E Element ID (24-characters)
    • The general form of a path is /resource/context/subresource. When present, the context identifies the document (D), the workspace, version or microversion (WVM), and the element (E). See the Onshape Architecture page for more information on Onshape’s basic API structure.
    • Our intention is to provide Workspace, Version, and Microversion forms for all appropriate GET operations. POST will always be to a Workspace, as Versions and Microversions are immutable. Not all forms of all interfaces are implemented at this time.
    • As of this writing, some API calls return information that is of use only for Onshape clients. You should generally only use the fields that are documented for external use. The internal data may be changed or removed without notice.

    Unit Designators

    The following strings are valid unit designators:

    For length measures:

    • meter, meters, m
    • millimeter, millimeters, mm
    • centimeter, centimeters, cm
    • inch, inches, in
    • foot, feet, ft
    • yard, yards, yd

    For angular measures:

    • degree, degrees, deg
    • radian, radians, rad

    What Now?

    Continue on to our API Explorer page to learn about about navigating the Onshape APIs in our Glassworks API Explorer.

    \ No newline at end of file +

    The Onshape API response also contains rate limiting information in the x-rate-limit-remaining header.

    Versioning

    All endpoint calls are versioned. The version string is inserted directly after the /api/ path component. For instance, https://cad.onshape.com/api/v6/documents/e60c4803eaf2ac8be492c18e indicates a version 6 request to the Onshape getDocument endpoint.

    Calls within a version are compatible with one another; typically this means that a GET request can be fed back in as a POST at the same version. Versions are incremented whenever Onshape introduces a non-backwards-compatible change. Onshape users should always refer to the latest version in their calls. If no version is specified, the oldest version (v0) will be used.

    API Conventions

    The Onshape API generally uses the following conventions:

    • Onshape generally supports only 3 methods: GET for read-only operations, POST for write operations, and DELETE for deletions. Onshape does not currently support other methods, such as PUT.
    • Strings should be UTF-8 encoded.
    • Query parameters are used for optional parameters. All required parameters are included in the path. For brevity, we use the following upper case letters in path definitions in this document:
      • D Document ID (24-characters)
      • W Workspace ID (24-characters)
      • V Version ID (24-characters)
      • M Microversion ID (24-characters)
      • E Element ID (24-characters)
    • The general form of a path is /resource/context/subresource. When present, the context identifies the document (D), the workspace, version or microversion (WVM), and the element (E). See the Onshape Architecture page for more information on Onshape’s basic API structure.
    • Our intention is to provide Workspace, Version, and Microversion forms for all appropriate GET operations. POST will always be to a Workspace, as Versions and Microversions are immutable. Not all forms of all interfaces are implemented at this time.
    • As of this writing, some API calls return information that is of use only for Onshape clients. You should generally only use the fields that are documented for external use. The internal data may be changed or removed without notice.

    Unit Designators

    The following strings are valid unit designators:

    For length measures:

    • meter, meters, m
    • millimeter, millimeters, mm
    • centimeter, centimeters, cm
    • inch, inches, in
    • foot, feet, ft
    • yard, yards, yd

    For angular measures:

    • degree, degrees, deg
    • radian, radians, rad

    What Now?

    Continue on to our API Explorer page to learn about about navigating the Onshape APIs in our Glassworks API Explorer.

    \ No newline at end of file diff --git a/docs/api-intro/index.xml b/docs/api-intro/index.xml index eaddb7f..07053a0 100644 --- a/docs/api-intro/index.xml +++ b/docs/api-intro/index.xml @@ -1,775 +1,7 @@ -– Introduction to the Onshape REST APIhttps://onshape-public.github.io/docs/api-intro/Recent content in Introduction to the Onshape REST API onHugo -- gohugo.ioen-usMon, 18 May 2020 20:39:14 -0400Docs: API Explorerhttps://onshape-public.github.io/docs/api-intro/explorer/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/explorer/ -<p>We document all available Onshape REST API endpoints in our Glassworks API Explorer:</p> -<p><b><font size="5"><a href="https://cad.onshape.com/glassworks/explorer/">https://cad.onshape.com/glassworks/explorer/</a></font></b></p> -<hr> -<p>This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below:</p> -<ol> -<li>Open this public Onshape document in your browser: -<font size="1"><a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22</a></font></li> -<li>Open the API Explorer in a new browser tab: <a href="https://cad.onshape.com/glassworks/explorer/">https://cad.onshape.com/glassworks/explorer/</a> -<ul> -<li>Note: For Enterprise accounts, substitue <code>cad</code> in this URL with your company name.</li> -</ul> -</li> -<li>Scroll down to <a href="https://cad.onshape.com/glassworks/explorer/#/Document">Document</a>.</li> -<li>Click to expand the <a href="https://cad.onshape.com/glassworks/explorer/#/Document/getDocument"><code>getDocument</code></a> endpoint. (Hint: it appears in the API Ref as <code>GET /documents/{did}</code>).</li> -<li>Go back to the public document you opened in Step 2, and copy the document ID from the Onshape URL (<code>e60c4803eaf2ac8be492c18e</code>). -<img src="https://onshape-public.github.io/images/OnshapeAPIGuidePublicDoc.png" alt="image"></li> -<li>Paste the document ID into the <code>did</code> field in the API Explorer. -<ul> -<li>Note: If you can&rsquo;t edit the <code>did</code> field, click the <strong>Try it out</strong> button. This will toggle to a <strong>Cancel</strong> button when the fields are editable.</li> -</ul> -</li> -<li>Scroll down and click <strong>Execute</strong>. -<ul> -<li>Note: If you receive a <code>403</code> error, see the <a href="#authentication">Authentication</a> section for help.</li> -</ul> -</li> -<li>Scroll to the bottom of the 200 response body. We have correctly returned <code>Onshape API Guide</code> as the document name.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/GlassworksAPIExplorerDemo.gif" alt="gif of using glassworks"></p> -<p><strong>IMPORTANT NOTE</strong>: The documentation in the API Explorer reflects the supported interface. Some API calls may, for historical reasons, return additional undocumented fields. Unless the return fields are documented in the API Explorer, you should NOT use them, as they may be removed without warning. Your application should always ignore unexpected or undocumented return data. Onshape reserves the right to add, remove or change any undocumented fields.</p> -<h3 id="authentication">Authentication</h3> -<p>You can authenticate in the API Explorer in one of three ways:</p> -<ol> -<li><strong>Onshape</strong>: -<ol> -<li>Open Onshape in a new tab in your browser.</li> -<li>Sign in with your Onshape credentials. Onshape will pass your credentials to the API Explorer.</li> -</ol> -</li> -<li><strong>API Keys</strong>: -<ol> -<li>Click <strong>Authorize</strong> in the top-right of the API Explorer page and scroll to the bottom of the dialog. -</br><img src="https://onshape-public.github.io/images/glassworks-auth-button.png" alt="Glassworks Authorize button" width=175></li> -<li>Provide your API access key in the Username field and your secret key in the Password field. See <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> for help creating your API Keys. Do NOT enter your Onshape credentials. -</br><img style='border:.7px solid #808080' src="https://onshape-public.github.io/images/ApiExplorerBasicAuth.png" alt="drawing" width="500"/></li> -<li>Click <strong>Authorize</strong>, and then click <strong>Close</strong>.</li> -</ol> -</li> -<li><strong>Oauth</strong>: -<ol> -<li>Click <strong>Authorize</strong> in the top-right of the API Explorer page. -</br><img src="https://onshape-public.github.io/images/glassworks-auth-button.png" alt="Glassworks Authorize button" width=175></li> -<li>Fill out the OAuth fields. See <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth</a> for more information on autheneticating with OAuth2.</li> -<li>Click <strong>Authorize</strong>, and then click <strong>Close</strong>.</li> -</ol> -</li> -</ol> -<h3 id="use-the-auto-fill-feature">Use the Auto-fill feature</h3> -<ol> -<li>Expand the endpoint you want to use in the API Explorer.</li> -<li>Paste an entire Onshape URL into the top field.</li> -<li>Click <strong>Auto-fill</strong>. The document ID, workspace/version/microversion ID, and element ID are pushed from the URL into the correct fields.</li> -<li>Confirm all fields are filled out as expected. Not every parameter can be extracted from an Onshape URL, so there may be more fields to fill out.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/GlassworksAutofill.png" alt="glassworks api explorer auto fill feature"></p> -<h3 id="view-response-body-docs">View response body docs</h3> -<ol> -<li>Expand the endpoint you want to use the in API Explorer.</li> -<li>Scroll down to the Responses section.</li> -<li>Click Schema.</li> -<li>Click the <code>[...]</code> symbols to expand the docs for the response JSON.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerResponseJSON.png" alt="glassworks api explorer response json docs"></p> -<h3 id="view-request-body-docs">View request body docs</h3> -<ol> -<li>Expand the endpoint you want to use the in API Explorer.</li> -<li><strong>Click the <em>Cancel</em> button to make the schema viewable.</strong></li> -<li>Click Schema.</li> -<li>Click the <code>[...]</code> symbols to expand the docs for the response JSON.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerRequestJSON.png" alt="glassworks api explorer response json docs"></p> -<h3 id="copy-a-curl">Copy a cURL</h3> -<ol> -<li>Expand the endpoint you want to use in the API Explorer.</li> -<li>Fill out the parameter fields.</li> -<li>Click Execute in the API Explorer.</li> -<li>Copy the curl from the Curl field.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerCopyCurl.png" alt="api explorer curl copy"></p> -<h3 id="troubleshooting">Troubleshooting</h3> -<ul> -<li>If the parameter fields in the API Explorer are grayed out, click the <strong>Try it Out!</strong> button to toggle it to a <strong>Cancel</strong> button. The parameter fields should become editable.</li> -<li>If you can&rsquo;t see the request body JSON docs, click the <strong>Cancel</strong> button to toggle it back to the <strong>Try it Out!</strong> button.</li> -<li>If you see authentication issues, review the <a href="#authentication">Authentication</a> section above.</li> -</ul>Docs: Architecturehttps://onshape-public.github.io/docs/api-intro/architecture/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/architecture/ -<p>Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also:</p> -<ul> -<li>The <a href="https://onshape-public.github.io/docs/api-intro/">API Introduction</a> page for information on how documents, workspaces, and elements are assembled into a URL.</li> -<li>The <a href="https://onshape-public.github.io/docs/api-adv/associativity">Associativity</a> page for information on how Parts, Assemblies, and Elements relate to each other.</li> -</ul> -<h2 id="elements">Elements</h2> -<p>All data in an Onshape document are stored in Elements (represented as tabs in the user interface). Onshape documents contain five kinds of elements:</p> -<ul> -<li><strong>Part Studio</strong>: Contains zero or more parts</li> -<li><strong>Assembly</strong>: Contains zero or more parts or assemblies</li> -<li><strong>Blob</strong> (Binary Large OBject): Can be provided by a partner or by the end user. For example, the user can upload a PDF file, an image, or a text file. Partner applications can store arbitrary data, but we recommend using the <a href="https://onshape-public.github.io/docs/app-dev/structuredstorage">structured storage</a> available in an element for better integration.</li> -<li><strong>Application</strong>: Presents an iframe to the user. The user interface is managed by a server that can be provided by a third-party. Onshape Drawings are a special case of an application element.</li> -<li><strong>Feature Studio</strong>: Contains the definition for Onshape Features, which are defined in FeatureScript.</li> -</ul> -<h2 id="workspaces-versions-and-microversions">Workspaces, Versions, and Microversions</h2> -<p>A document is stored in Onshape as a collection of changes.</p> -<ul> -<li>You can think of a <strong>workspace</strong> as a branch of the document, similar to a branch in a source control system. Documents can be branched to create new workspaces.</li> -<li>Each individual change to the document creates a new document <strong>microversion</strong>. As the document is edited, changes are applied to the active workspace, creating new microversions.</li> -<li>Periodically, the user may designate versions of the document. A <strong>version</strong> is a named snapshot of the entire document at some point in time (that is, at some microversion).</li> -</ul> -<p>You cannot change a version or microversion of a document; all changes are applied to a workspace (and create a new microversion). Thus, while in general the <code>GET</code> methods of the API can read from a version, microversion, or workspace, the <code>POST</code> methods generally require a workspace, and create a new microversion when data is written to the document. (An exception is that it is possible to set metadata within a version; this does not create a new microversion).</p> -<p>The following IDs are used by many of the APIs. Each ID (except for Geometry IDs such as Part, Face and Edge) is a 24-character string that is used internally by Onshape to uniquely identify the resource. The Geometry IDs are variable-length strings used to resolve to a specific geometric entity within a model.</p> -<table> -<thead> -<tr> -<th>ID</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td><strong>User ID</strong></td> -<td>Identifies a single user.</td> -</tr> -<tr> -<td><strong>Document ID</strong></td> -<td>Identifies a document. The logged-in user must have access to the requested document for the API to succeed.</td> -</tr> -<tr> -<td><strong>Workspace ID</strong></td> -<td>The Workspace ID identifies a workspace within the document. Workspaces are used to distinguish between different branches of the document.</td> -</tr> -<tr> -<td><strong>Version ID</strong></td> -<td>The Version ID identifies a specific named version.</td> -</tr> -<tr> -<td><strong>Microversion ID</strong></td> -<td>The Microversion ID identifies an internal revision of the document.</td> -</tr> -<tr> -<td><strong>Element ID</strong></td> -<td>The Element ID identifies an element within the document.</td> -</tr> -<tr> -<td><strong>Part ID </br> Face ID </br> Edge ID</strong></td> -<td>The Part ID identifies a part within a part studio. The Part ID should generally not be stored for long-term use, as it is only expected to be valid during the course of a session.</td> -</tr> -</tbody> -</table> -<p>Note that a Part ID may reference a part that no longer exists if the model is changed, so it is best to specify a Version or Microversion to pick the context for the Part ID. Note that even with the Version or Microversion, internal changes to the Onshape system may also change the Part ID. Onshape provides mechanisms for maintaining persistent references. See the <a href="https://onshape-public.github.io/docs/api-adv/associativity">Associativity</a> page for more information. Face and Edge IDs are used in similar ways.</p> -<p>The following table identifies Onshape concepts and the corresponding Git concepts. Note that this is not a direct mapping, and the implementation of the concepts is very different.</p> -<table> -<thead> -<tr> -<th>Onshape concept</th> -<th>Git concept</th> -</tr> -</thead> -<tbody> -<tr> -<td>Document</td> -<td>Repository</td> -</tr> -<tr> -<td>Element</td> -<td>File</td> -</tr> -<tr> -<td>Workspace</td> -<td>Branch</td> -</tr> -<tr> -<td>Version</td> -<td>Tag</td> -</tr> -<tr> -<td>Microversion</td> -<td>Commit</td> -</tr> -</tbody> -</table> -<h2 id="linked-documents">Linked Documents</h2> -<p>Although a document can contain a complex model tree involving many Part Studio and Assembly elements, it is often more efficient to split the content into multiple documents. Connections between documents always refer to a specific version of the target document. <em>Once a version is used as the target of a linked document, that document version is preserved as long as any document references it, even if the containing document is deleted.</em> Additionally, any user that has access to the referring document will have limited read access to the target document, regardless of what permissions are currently on the target document.</p> -<h2 id="configurations">Configurations</h2> -<p>Onshape Part Studios can be constructed to be configurable using Onshape Configurations. API calls that reference Part Studios (primarily within the <a href="https://cad.onshape.com/glassworks/explorer/#/Part">Parts</a> and <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">Part Studios</a> APIs) often accept a <code>configuration</code> parameter that identifies what specific configuration of the Part Studios is being referenced. When not specified, the API implementation typically uses the configuration that is currently selected within the Part Studio. An interactive ad-hoc API call might not behave consistently in an application, so be sure to specify the configuration parameter where applicable.</p> -<h2 id="onshape-data-model">Onshape Data Model</h2> -<p>Onshape data is stored in replicated databases in the cloud. The Onshape data model is influenced by the Git data model and similar source code repositories.</p> -<p>Documents contain <strong>elements</strong>. Elements are presented as tabs in the user interface. With some exceptions, all data in a document is stored within an element. The following table describes what data stored in each Element type:</p> -<table> -<thead> -<tr> -<th>Element Type</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td><strong>Part Studio</strong></td> -<td>Each Part Studio contains exactly one Feature list. The Feature list contains Features such as sketches, planes, extrudes, etc. Each Feature contains one or parameters. Whenever the Feature list changes, the parametric history is evaluated, and the model is regenerated.</td> -</tr> -<tr> -<td><strong>Assembly</strong></td> -<td>Each Assembly contains an assembly tree, which contains parts and/or other assemblies (sub-assemblies), along with mate information. Onshape provides an API call to retrieve the assembly tree definition.</td> -</tr> -<tr> -<td><strong>Blob</strong></td> -<td>Each Blob element contains an uninterpreted binary object that has been uploaded to Onshape, typically from a file. Onshape depends on the browser client to display some blob data (e.g., PDF and image data), but does not interpret the data. A blob element can be updated with new data.</td> -</tr> -<tr> -<td><strong>Application</strong></td> -<td>Each Application element contains zero or more sub-elements, providing a structured set of transactional data that is defined and managed by an application. Application data can be displayed in the Onshape tab in an iframe; the application is responsible for rendering the data in the iframe from its server.</td> -</tr> -</tbody> -</table> -<p>Note that Onshape Drawing elements are Application elements managed by Onshape.</p> -<p>Tessellated data is not stored persistently in Onshape; it is generated on demand for display by the Onshape clients, or in response to application REST API requests. This data may be cached for performance.</p> -<h3 id="document-data">Document data</h3> -<p>All elements, including Assemblies, Part Studios, Drawings, or even apps, are history based. Each change to an element or set of elements represents a unique record in the document’s history, known as a microversion. The document can be restored to that particular state any time in the future.</p> -<h3 id="part-studio-data">Part Studio data</h3> -<p>The Part Studio element is defined by a list of features, some of which (e.g., a sketch), may have a complex internal structure composed of entities. Part Studio features and entities are referenced by unique persistent identifiers. Part Studio features and entities can appear, disappear, and reappear depending on the current microversion of the model.</p> -<h3 id="assembly-data">Assembly data</h3> -<p>The Assembly element is defined as a list of assembly features and a tree of subassemblies/part instances. Occurrence ID is a unique persistent identifier of an occurrence of a part in the assembly structure.</p> -<h3 id="external-application-data">External application data</h3> -<p>An external application has complete control over how it manages/stores documents, however, to take advantage of the Onshape data model, there is a set of endpoints they should use to store state. These are collectively known as the AppElement API.</p> -<h3 id="model-presentation-data">Model presentation data</h3> -<p>A valid model definition usually corresponds to a real-world manufacturable topology, represented internally as a set of parts, faces, edges, and vertices and the set of relations between them. Each of these has a unique identifier in every state of the model. The identifier represents an encoded index in the model’s history, and its value depends on the structure of the model’s history. The value is not guaranteed to be preserved across model changes, and will almost always change if the model changes in significant ways. The model can be tessellated into a set of geometric primitives, which approximate the shape of the model. Tessellated data can be used for visual representation of the model or other processing related to the shape of the model.</p> -<p>The following changes in the topological representation can occur between two microversions of the model:</p> -<ul> -<li>New topological entities appear</li> -<li>Id of existing topology change</li> -<li>Topological entities disappear</li> -<li>Existing topological entities are merged into a single entity</li> -<li>Existing topological entity are split into multiple entities</li> -</ul> -<p>The model microversion and topology ID can be used to identify topological entities across the model changes. Topology ID defined in a specific microversion can be translated into a set of topology IDs in the current microversion of the model. (The Topology ID is sometimes referred to as a Deterministic ID within Onshape, and is exposed in specific API calls as partId, faceId, etc.). See the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">PartStudio APIs</a> to see what topology IDs are exposed.</p>Docs: Quick Starthttps://onshape-public.github.io/docs/api-intro/quickstart/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/quickstart/ -<p>In this example, we will call an Onshape REST API endpoint to send a document name to our console. Please note that the sample shown on this page is only designed to be used as a quick start guide and does not represent a full Onshape application.</p> -<h2 id="system-requirements">System Requirements</h2> -<ul> -<li>You must be signed in to your Onshape account at <a href="https://cad.onshape.com">https://cad.onshape.com</a> (or <a href="https://companyName.onshape.com">https://companyName.onshape.com</a> for Enterprise accounts).</li> -<li>This example is coded in Python. The equivalent code is provided in other languages at the end of the example. To follow along with this tutorial, you can download and install Python here: <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a>.</li> -</ul> -<h2 id="review-the-api-endpoint">Review the API Endpoint</h2> -<ol> -<li>Go to the <a href="https://cad.onshape.com/glassworks/explorer">API Explorer</a> and scroll to <code>Document</code>.</li> -<li>Expand the <code>GET /documents/{did}</code> endpoint. Note that in the URL, the name of this API is <code>getDocument</code>.</li> -<li>Make a note of the URL structure and the parameters required to make this request. This will become the fixed URL part of our API call. </br> -<img src="https://onshape-public.github.io/images/Glassworks_getDocument.png" alt="image"> </br> -For this endpoint, we only need to get the document ID from the document URL.</li> -<li>Scroll down and make a note of the <code>Media Type</code> that we’ll need to include in our header. </br> -<img src="https://onshape-public.github.io/images/Glassworks_MediaType.png" alt="image"></li> -</ol> -<h2 id="review-the-document">Review the Document</h2> -<p>Navigate to <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a>, and make a note of the document ID in the URL (<code>e60c4803eaf2ac8be492c18e</code>). </br> -<img src="https://onshape-public.github.io/images/OnshapeAPIGuidePublicDoc.png" alt="image"></p> -<h2 id="create-your-api-keys">Create your API Keys</h2> -<ol> -<li>Go to <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</li> -<li>In the left pane, click <code>API keys</code>.</li> -<li>Click the <code>Create new API key</code> button.</li> -<li>Select the following permissions for your app: -<ul> -<li><code>Application can read your documents.</code></li> -<li><code>Application can write to your documents.</code></li> -</ul> -</li> -<li>Click the <code>Create API key</code> button. </br> -<img src="https://onshape-public.github.io/images/CreateNewAPIKey.png" alt="image"></li> -<li>Copy both the <strong>access key</strong> and <strong>secret key</strong> from the pop-up window, save them somewhere, then click the <code>Close</code> button. -</br><strong>IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!</strong></br> -<img src="https://onshape-public.github.io/images/APIKeySecretKey.png" alt="image"></li> -<li>The details for your application appear. </br> -<img src="https://onshape-public.github.io/images/DevPortalKeys.png" alt="image"></li> -<li>Open your terminal and run the following command, replacing <code>ACCESS_KEY</code> and <code>SECRET_KEY</code> with the <strong>access key</strong> and <strong>secret key</strong> you created above. Remember to include the colon (<code>:</code>) between the keys. -<ul> -<li><strong>MacOS</strong>: -<pre tabindex="0"><code>printf ACCESS_KEY:SECRET_KEY | base64 -</code></pre></li> -<li><strong>Windows</strong>: -<pre tabindex="0"><code>powershell &#34;[convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\&#34;ACCESS_KEY:SECRET_KEY\&#34;))&#34; -</code></pre></li> -</ul> -</li> -<li>You will receive a long, base-64-encoded string. You will need this string later, so keep it somewhere safe. We&rsquo;ll refer to it as our <code>CREDENTIALS</code>.</li> -</ol> -<h2 id="write-your-code">Write Your Code</h2> -<ol> -<li>Create a new file called <code>hello.py</code>.</li> -<li>Start your file by importing the necessary libraries.</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span></code></pre></div><ol start="3"> -<li>Next, define the URL for the API call:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;ASSEMBLED_URL&#34;</span> -</span></span></code></pre></div><ol start="4"> -<li>Replace <code>ASSEMBLED_URL</code> with the fully formed API. This is where we’ll put together everything we’ve learned so far: -<ol> -<li>The base URL: -<ul> -<li><code>https://cad.onshape.com/api</code></li> -<li><code>https://companyName.onshape.com/api</code> for Enterprise accounts</li> -</ul> -</li> -<li>The fixed URL is specified in the <a href="https://cad.onshape.com/glassworks/explorer/#/Document/getDocument"><code>getDocument</code></a> API in Glassworks: <code>/documents/{did}</code></li> -<li>The document ID parameter from the public document URL to include in the fixed URL: <code>{did}: e60c4803eaf2ac8be492c18e</code></li> -<li>Together, this makes the URL for our API request: -<code>https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e</code> </br></li> -</ol> -</li> -<li>We don&rsquo;t need to send any optional parameters with our request, so we can define them as an empty object:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span></code></pre></div><ol start="6"> -<li>Now, define your API keys: </br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span></code></pre></div><ol start="7"> -<li>Replace <code>CREDENTIALS</code> with the string you created in the last section.</li> -<li>Next, define your headers:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;MEDIA_TYPE&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span></code></pre></div><ol start="9"> -<li>Replace <code>MEDIA_TYPE</code> with the Media type we obtained from the API Explorer during the Review the API section above:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>application/json;charset=UTF-<span style="color:#099">8</span>;qs=<span style="color:#099">0.09</span> -</span></span></code></pre></div><ol start="10"> -<li>Put all the variables you just defined together into the request:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Put everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span></code></pre></div><ol start="11"> -<li>And finally, print the name value from the response:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div><ol start="12"> -<li>Make sure your file matches the full example below:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Putting everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div><h2 id="run-your-code">Run Your Code</h2> -<ol> -<li>Open your terminal and navigate into the folder where you saved your <code>hello.py</code> file: <code>cd ~/&lt;your-file-path&gt;</code></li> -<li>Install the necessary modules:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 -m pip install requests -</span></span><span style="display:flex;"><span>python3 -m pip install jsons -</span></span></code></pre></div><ol start="3"> -<li>Run your code:</br><code>python3 hello.py</code></li> -<li>Confirm that your console displays:</br><code>&quot;Onshape API Guide&quot;</code></li> -</ol> -<h2 id="other-language-examples">Other Language Examples</h2> -<p>Remember to replace <code>CREDENTIALS</code> with your credentials.</p> -<h3 id="curl">cURL</h3> -<p>Returns the entire response json. Scroll to the bottom to the see <code>name</code> field.</p> -<pre tabindex="0"><code class="language-curl" data-lang="curl">curl -X &#39;GET&#39; \ -https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39; \ --H &#39;Content-Type: application/json&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre><h3 id="javascript">JavaScript</h3> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#00a">import</span> fetch from <span style="color:#a50">&#39;node-fetch&#39;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">async</span> <span style="color:#00a">function</span> getDocument(url=<span style="color:#a50">&#39;&#39;</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> response = <span style="color:#00a">await</span> fetch(url, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;GET&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>, -</span></span><span style="display:flex;"><span> Accept: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> Authorization: <span style="color:#a50">`Basic </span><span style="color:#a50">${</span>btoa(<span style="color:#a50">&#39;CREDENTIALS&#39;</span>)<span style="color:#a50">}</span><span style="color:#a50">`</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> response.json(); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>getDocument(<span style="color:#a50">&#39;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39;</span> -</span></span><span style="display:flex;"><span>).then((data) =&gt; { -</span></span><span style="display:flex;"><span> console.log(data.name); -</span></span><span style="display:flex;"><span>}); -</span></span></code></pre></div><h3 id="c">C++</h3> -<p>Returns the entire response json. Scroll to the bottom to the see <code>name</code> field.</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;iostream&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;string&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;stdio.h&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317"></span><span style="color:#00a">using</span> <span style="color:#00a">namespace</span> std; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">int</span> <span style="color:#0a0">main</span>() { -</span></span><span style="display:flex;"><span> string url = <span style="color:#a50">&#34;curl &#34;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-X &#39;GET&#39; &#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;&#39;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39;&#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; &#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-H &#39;Authorization: Basic CREDENTIALS&#39;&#34;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> system(url.c_str()); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#099">0</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h3 id="python">Python</h3> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Putting everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div>Docs: Why Onshape?https://onshape-public.github.io/docs/api-intro/whyonshape/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/whyonshape/ -<h2 id="why-onshape">Why Onshape?</h2> -<p>As long as there have been applications that manage organizational data -into a database, there has been a need to share that data between -different departments and therefore, usually, different systems. In a -typical design/manufacturing organization, there could be at least four -or five mission-critical databases that manage the data for different -departments and for different stages in the product’s lifecycle.</p> -<p>Initially, these systems provide the capabilities required by their -consumers (i.e., the departments that use these systems). For instance, -the Finance might use QuickBooks, Manufacturing -might use a manufacturing planning and execution system (MES), -Engineering might use a Product Data management System (PDM), and so on for each -group in the organization.</p> -<p>This often leads to disparate silos of data and knowledge. -The departments in an organization do not work in a vacuum; each is -dependent on information generated by other groups. For -instance, Manufacturing can’t produce accurate assembly instructions -without input from engineering on the designs and the bill of -materials. Finance can’t price the product without understanding its -contents and which parts are manufactured in-house or -purchased.</p> -<p>Therefore, the need to integrate these systems becomes critical for the -organization to function optimally. Initially, connecting one system to -another can be a straightforward process. This usually involves -some services to get the systems to talk to each other, however it -isn&rsquo;t too painful as long as the requirements are clearly -defined.</p> -<p>Anyone who has implemented integrations between PLM (Product -Lifecycle Management) systems or ERP (Enterprise Resource Planning) systems will tell -you of the nightmare scenarios they encountered. Often this is the -result of poorly scoped and defined requirements, conflicting -requirements coming from multiple departments, and the many integration -points required between systems. The result is that the organization is -not getting what it wants or needs, the customer is paying for services -that do not provide the promised solution, and usually the project is -long overdue. All this equals an unhappy customer and often the software -vendor’s solutions are blamed for the disaster.</p> -<p>Over the years, many technologies have appeared (and some of them, just as -quickly disappeared) to enable integration without the need -to write thousands of lines of custom code that needs to be re-written -for every software upgrade. Several technologies provide “codeless” integration between SaaS -products (<a href="wwww.zapier.com">Zapier</a>, for example). These solutions -are particularly good for generic use cases for data exchange between -systems, but can be limited when it comes to custom modifications to the -data being sent that might be required by a specific customer. In -addition, they have the overhead of requiring a subscription to their -service. Sending -corporate IP through another third-party can also cause data security issues.</p> -<p>Therefore, we can understand that in most organizations integration -between systems is a necessary evil that must be tackled, either with -an out-of-the-box solution or through some custom coding.</p> -<p>Early on, Onshape understood that as an engineering system, it cannot -exist in a vacuum; it must be able to communicate with other systems. -For this reason, the REST API was developed.</p> -<p>An API, or <em>application -programming interface</em>, is a set of rules that define how applications -or devices can connect to and communicate with each other. A REST API is -an API that conforms to the design principles of the REST, -or <em>representational state transfer <em>architectural style. For this -reason, REST APIs are sometimes referred to RESTful APIs</em>.</em></p> -<h2 id="onshape-saas">Onshape SaaS</h2> -<p>Onshape was built from the ground up as a true SaaS-based system; Onshape had no investment in legacy code and was able to develop an application that truly runs as a multi-tenant -SaaS solution from the first line of code. Many companies claim to run -cloud-based solutions, but since they have such a large investment -in their legacy code, that they can’t just discard and start again from -scratch. Instead, they tend to try and port that code to the web.</p> -<p>More often than not, porting existing code to the web and calling it a -SaaS solution is no more than a marketing ploy; it isn’t a true SaaS -solution if it wasn’t written as one. These are generally known as cloud-hosted solutions. This means that a typical three-tier data management -solution (which could have previously been installed on a set of servers), -has now been modified to be hosted on the web.</p> -<h3 id="traditional-three-tier-architecture">Traditional three-tier architecture</h3> -<p>Traditional PLM systems typically use a three-tier architecture, mainly -consisting of an application server, a database server, and a client (either a web client or a thick client installed on the client -hardware).</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage10.png" -style="width:4.91807in;height:3.27083in" -alt="The 3-tier architecture | Download Scientific Diagram" /></p> -<p><em>Typical three-tier architecture</em></p> -<p>To connect to and integrate with this architecture, APIs are usually exposed on -the application or web server. If this -architecture is ported to the web, it cannot make -customizations through the API, since it would modify the behavior of -the program for everyone connected to that application server.</p> -<h3 id="single--vs-multiple-tenant-architectures">Single- vs multiple-tenant architectures</h3> -<p>The three-tier architecture is typical of most -PLM solutions on the market today, which is fine -if you want the solution to be installed on company servers and be -accessible to people within the company only.</p> -<p>When this type of solution is ported to the web, software -vendors typically must create a single-tenant application where an -application server and a database server are provisioned for each new -customer.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage11.png" -style="width:5.4311in;height:4.35417in" -alt="Enterprise SaaS Architecture - The Why | Frontegg" /></p> -<p><em>Single-tenant architecture</em></p> -<p>In this case, the vendor must use expensive -hardware to host more customers, which is not a -sustainable model.</p> -<p>Modern 21<sup>st</sup> century software solutions use multi-tenant -solutions that can be hosted on services such as Amazon cloud, Azure, etc. There are many benefits to this architecture, including that servers can be provisioned and -decommissioned on the fly to provide ultimate performance whenever -required. Since servers cost money, decommissioning servers when they -are not required is a key benefit to a true SaaS solution.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage12.png" style="width:6.5in;height:4.65417in" -alt="Saas Solutions - Multi-tenant vs multi-instance architectures" /></p> -<p><em>Multi-tenant architecture</em></p> -<p>Since each application is separate in this architecture, we can enable customizations that can’t be implemented in a single-tenant architecture. For example, we can provide access to the REST -APIs that are required for Onshape integration. In the single-tenant -architecture, if you provide API access to the application server, one -customer will be modifying that application for all customers who are -registered on that tenant.</p> -<h2 id="the-onshape-difference">The Onshape Difference</h2> -<p>Onshape does not work like other legacy CAD systems. Onshape was built from scratch for the cloud and as a modern -CAD system, so many of the failings of legacy CAD -systems were excluded.</p> -<p>There are many differences -and benefits to Onshape, which are well-documented in the Onshape Help -and training materials.</p> -<p>The information in this section is specific to integrations, since Onshape does not behave like a traditional file-based -systems. When writing an integration for Onshape, it is -critical to understand the nuances in Onshape’s design practices and how -data is organized in Onshape.</p> -<h3 id="data-drivenfileless">Data-driven/fileless</h3> -<p>Most traditional PDM/PLM systems integrated with CAD systems -enable this integration on a per-file basis. This means that you have an -object in the PDM/PLM system that corresponds directly to a file in the -CAD system. In this way, the PDM/PLM system can manage access to the -files, build assemblies from the files, view the CAD data, and much more.</p> -<p>Onshape, however, does not work this way.</p> -<p>Being data-driven means that Onshape has no files, just data, so an integration into Onshape is going to look -different from any integration to a CAD system that you might have done -previously.</p> -<p>In traditional CAD, a single file represents a snapshot of what the -design looked like at a specific moment in time. Unless it’s changed, it will remain in that state forever. PDM -systems manage these files, and once a designer decides to make a -revision or a release, the file is locked, and a new file can be created -to represent any further updated versions or releases of the design. -PDM/PLM systems are very good at managing this data in an up-to-date -structure, but it does have the drawbacks. They generate many file -copies of a specific design, and once a file is taken out from the system (for instance, to share with a supplier), it is no longer managed and -tracked.</p> -<p>Onshape uses data instead of files. The data is always up-to-date and -can be collaborated on in real-time without the need to send file copies -back and forth. This means that Onshape views versions and releases differently -than those traditional systems do. When integrating with Onshape, we must design for data rather than files.</p> -<p>Files can be generated from -the Onshape data. For example, you can generate a PDF of a -drawing upon release or of a STEP file that can be used by other downstream systems.</p> -<p>A key benefit of a data-driven system is the ability to retrieve detailed, real-time -analytics. Onshape has comprehensive analytics; including who can view or edit a design, when and exactly what edits are made, which commands were used, and how long was spent modifying the design.</p> -<h3 id="built-in-pdm">Built in PDM</h3> -<p>Up until now, CAD was one software program, and PDM/PLM was another -program that had to be integrated with the CAD. In many cases, both -programs could be sold by the same software vendor (even though there -are many PLM systems available that are sold by independent vendors who -have no CAD system). Regardless, a PDM/PLM system always had to be an added solution to the CAD system.</p> -<p>No matter how deep the integration between a CAD system and a PLM -system, there is always the need to sync data between the two. This is usually a weak point in any solution that is prone to errors.</p> -<p>Being data-driven, Onshape already has PDM built in as part of the CAD -system. This is unique in the industry: CAD and PDM as part -of the same solution with no additional piece of software required.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage14.png" -style="width:4.49202in;height:4.1652in" -alt="A picture containing graphical user interface Description automatically generated" /></p> -<p><em>Onshape’s revision and part number schema definition interface</em></p> -<p>For instance:</p> -<ul> -<li> -<p>Since the <strong>data is always up-to-date</strong>, the correct state of any design -is always represented in real-time with no delay for syncing between -systems.</p> -</li> -<li> -<p>Unlike file-based systems, <strong>the data is never locked</strong>; it -is always available and always changing.</p> -</li> -<li> -<p>PDM system <strong>data management aspects are fully integrated</strong> into every aspect of -the CAD system.</p> -</li> -<li> -<p>True <strong>real-time collaboration/co-design</strong> on both design and data is -enabled.</p> -</li> -</ul> -<p>So, what does this mean when it comes to integrating Onshape with -another PLM system? First and foremost, we must understand that there -are many things that a PLM system does that Onshape’s PDM capabilities -can’t do. Integrating Onshape to a PLM system should augment the -powerful capabilities already available inside Onshape, not -necessarily replace them. Similarly, Onshape does not replace PLM-native capabilities. Instead, depending on the business case, we can use the best-in-class capabilities of each system to augment the -other.</p> -<p>The Onshape release process is an example of the augmentation of each system&rsquo;s capabilities. Onshape has a specific way of managing the release of data that is -different from traditional PDM systems. This capability is inherently -suited to a data-driven approach and provides a lot of value to the -update of design data in Onshape. At the same time, PLM systems provide -enterprise release processes that may include many people and different -departments that extend beyond the engineering domain. Such PLM -processes can be highly customized and suited to the organizations -established business processes.</p> -<p>In this scenario, it doesn&rsquo;t make sense to avoid the enterprise release -processes in the PLM system. However, also omitting Onshape’s release -capabilities could put data between Onshape and the PLM system out of -sync and prevent Onshape from updating data (e.g., watermarks and -title blocks on drawings, icons related the visualizing the state of -data, etc.).</p> -<p>In this case, we want to use the best-in-class features of each software -solution without compromising the capability provided by each solution. -If we plan our integration correctly, this can be achieved by initiating -the release of the data in Onshape, transferring the release data to the -PLM system where the release process will be triggered, and finally -automating the release in Onshape once the process has been completed in -the PLM system.</p> -<h3 id="multi-part-part-studios">Multi-part Part Studios</h3> -<p>In traditional CAD systems, one file typically equals -one part. While design-in-context is available in most CAD systems, and -multiple solid bodies can be created, each part is self-contained in a separate file. For PLM systems, this -makes it easy to associate an object in the PDM/PLM database with a -specific CAD file. <em>This is not the case in Onshape.</em></p> -<p>In Onshape, parts are designed in what’s called a <em>Part Studio.</em> Within -a Part Studio, the designer is free to create as many parts as they want. -The general rule is that the parts should be related to each other in a -system, thereby making it easier to design one part from another, however -there is a lot of flexibility in how the designer wishes to work.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage15.png" -style="width:4.45764in;height:4.12141in" -alt="A picture containing text Description automatically generated" /></p> -<p><em>An example of a multi-part Part Studio in Onshape</em></p> -<p>The structure of the Onshape document is discussed in detail in the <a href="https://onshape-public.github.io/docs/api-intro/architecture">Onshape Architecture</a> page. The Part Studio is included in an Onshape document.</p> -<p>We can already begin to understand that the traditional CAD/PDM paradigm -of &ldquo;one file per object&rdquo; will not work with Onshape; the designer would be forced by the -PDM/PLM system to only create one part per Part Studio. This would -therefore limit the designer’s freedom for creativity in Onshape and -seriously reduce the powerful functionality available for the designer -to use.</p> -<p>Therefore, we need to re-think how we integrate with Onshape versus how we -integrate with traditional CAD systems. Fortunately, Onshape’s REST API -supports the multi-part Part Studio scenario. Instead of associating a -file with an object in the PDM/PLM database, we now use the REST API to -associate a Part with its corresponding object.</p> -<h3 id="versions-and-releases">Versions and releases</h3> -<p>Traditional PDM/PLM systems provide design release support by locking a -CAD file for access. The access controls are defined in the database and -the definition of a part/assembly/drawing as released is controlled by -the database. When a new revision of the part is required, a file copy -is made, and the database provides access to the new copy. Generally, -the old copy representing the previous release persists in the file -store and can be referenced by the database. <em>This is not how Onshape works.</em></p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage16.png" -style="width:2.66865in;height:3.09375in" />Since there are no files in -Onshape (just data) no file locking or copy mechanisms are -available. Instead, Onshape looks at the data as a continuous timeline -that is always moving forward and always changing as the design evolves. -The data is never locked; it is always available.</p> -<p>In place of file copies that represent versions and releases of the -design, Onshape provides the ability to create <em>versions</em> as bookmarks -in the timeline. When creating a version, Onshape places a bookmark in -the timeline that represents the state of the design at that specific -moment in time. Releases work in a similar way, but they are defined -as official, company-approved processes and have special meaning.</p> -<p>In addition to creating versions and releases, Onshape can create <em>branches</em>, which can be defined as alternative timelines. A -designer might want to experiment with alternate design ideas without -modifying the existing design that others are working on. By -creating a branch from any point in the timeline, the designer is -free to experiment with alternate ideas. If the ideas work, they can be -merged into the current timeline at any point.</p> -<p>From an integration perspective, we need to take into -consideration how Onshape works with versions and releases. Since a release represents a company-approved design, Onshape provides processes for the approval of -a release and the change of state of a design. Onshape also provides -APIs and triggers (events) that enable integration points throughout the -release process. It is through the triggers and the APIs that -integration of any third-party system that wishes to manage the release -process is enabled.</p> -<h3 id="workflows">Workflows</h3> -<p>Release and obsoletion workflows are included with Onshape and can be customized to meet company standards.</p> -<p>For details on how to implement and customize Onshape’s workflows, -please review these online help topics:</p> -<ul> -<li><a href="https://cad.onshape.com/help/Content/relmgmt_custom.htm">How to design release management processes</a></li> -<li><a href="https://cad.onshape.com/help/Content/custom_workflow.htm">How to create a customized release workflow</a></li> -</ul> -<p>Most PDM/PLM systems can model a company’s -business processes in a workflow. These can be highly automated -processes that move data and file references through a process of -reviews and approvals. Onshape also has this capability, which is -currently used for release and obsoletion processes.</p> -<p>There are no files or file references in Onshape that are moved -through the process. Onshape only has data. Therefore, it is the data -that is referenced at each stage of the process. Traditional PDM systems -might make file copies and lock files as they move through a release -process. If the process is rejected at any stage, those -files must be discarded, the previous version of the files unlocked and -all states updated. In short, it system must rewind back to the state of the files and -the data when the workflow was initiated. This is a lot of complex -actions that must occur when a process is rejected for any reason. <em>Onshape doesn’t work this way.</em></p> -<p>A release process can be started on data (such as assemblies, parts, -drawings, etc.). For example, if the state of a referenced part is updated to -“Pending,” and the process is rejected at any stage, there -is no rewinding of files and data; the data just reverts to the -original “In Progress” state, and the workflow is discarded. Since the -workflow didn’t complete, nothing related to the data has actually -changed. When you are used to traditional PDM systems, this feels like -an anti-climax, and we often receive the question, “But where’s my -process? Where’s the data that was attached to the process?”. Well, the -answer is: nothing changed. Until the process is completed, nothing -actually changes, so the data is in the same state it was prior to the -initialization of the release process.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage17.png" -style="width:3.39863in;height:2.61034in" -alt="A picture containing chart Description automatically generated" /></p> -<p><em>A custom release process in Onshape</em></p> \ No newline at end of file +Introduction to the Onshape REST API onhttps://onshape-public.github.io/docs/api-intro/Recent content in Introduction to the Onshape REST API onHugoen-usMon, 18 May 2020 20:39:14 -0400API Explorerhttps://onshape-public.github.io/docs/api-intro/explorer/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/explorer/We document all available Onshape REST API endpoints in our Glassworks API Explorer: +https://cad.onshape.com/glassworks/explorer/ +This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below: +Open this public Onshape document in your browser: https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22 Open the API Explorer in a new browser tab: https://cad.Architecturehttps://onshape-public.github.io/docs/api-intro/architecture/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/architecture/Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also: +The API Introduction page for information on how documents, workspaces, and elements are assembled into a URL.Quick Starthttps://onshape-public.github.io/docs/api-intro/quickstart/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/quickstart/In this example, we will call an Onshape REST API endpoint to send a document name to our console. Please note that the sample shown on this page is only designed to be used as a quick start guide and does not represent a full Onshape application. +System Requirements You must be signed in to your Onshape account at https://cad.onshape.com (or https://companyName.onshape.com for Enterprise accounts). This example is coded in Python.Why Onshape?https://onshape-public.github.io/docs/api-intro/whyonshape/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/whyonshape/Why Onshape? As long as there have been applications that manage organizational data into a database, there has been a need to share that data between different departments and therefore, usually, different systems. In a typical design/manufacturing organization, there could be at least four or five mission-critical databases that manage the data for different departments and for different stages in the product’s lifecycle. +Initially, these systems provide the capabilities required by their consumers (i. \ No newline at end of file diff --git a/docs/api-intro/quickstart/index.html b/docs/api-intro/quickstart/index.html index 3a379f5..67c6085 100644 --- a/docs/api-intro/quickstart/index.html +++ b/docs/api-intro/quickstart/index.html @@ -1,8 +1,8 @@ -Quick Start |

    Quick Start

    In this example, we will call an Onshape REST API endpoint to send a document name to our console. Please note that the sample shown on this page is only designed to be used as a quick start guide and does not represent a full Onshape application.

    System Requirements

    Review the API Endpoint

    1. Go to the API Explorer and scroll to Document.
    2. Expand the GET /documents/{did} endpoint. Note that in the URL, the name of this API is getDocument.
    3. Make a note of the URL structure and the parameters required to make this request. This will become the fixed URL part of our API call.
      image
      For this endpoint, we only need to get the document ID from the document URL.
    4. Scroll down and make a note of the Media Type that we’ll need to include in our header.
      image

    Review the Document

    Navigate to this public document, and make a note of the document ID in the URL (e60c4803eaf2ac8be492c18e).
    image

    Create your API Keys

    1. Go to https://dev-portal.onshape.com.
    2. In the left pane, click API keys.
    3. Click the Create new API key button.
    4. Select the following permissions for your app:
      • Application can read your documents.
      • Application can write to your documents.
    5. Click the Create API key button.
      image
    6. Copy both the access key and secret key from the pop-up window, save them somewhere, then click the Close button.
      IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!
      image
    7. The details for your application appear.
      image
    8. Open your terminal and run the following command, replacing ACCESS_KEY and SECRET_KEY with the access key and secret key you created above. Remember to include the colon (:) between the keys.
    \ No newline at end of file diff --git a/docs/api-intro/whyonshape/index.html b/docs/api-intro/whyonshape/index.html index b445369..83aa404 100644 --- a/docs/api-intro/whyonshape/index.html +++ b/docs/api-intro/whyonshape/index.html @@ -1,10 +1,8 @@ -Why Onshape? |

    Why Onshape?

    Why Onshape?

    As long as there have been applications that manage organizational data +Why Onshape? |

    Why Onshape?

    Why Onshape?

    As long as there have been applications that manage organizational data into a database, there has been a need to share that data between different departments and therefore, usually, different systems. In a typical design/manufacturing organization, there could be at least four @@ -214,4 +212,4 @@ process? Where’s the data that was attached to the process?”. Well, the answer is: nothing changed. Until the process is completed, nothing actually changes, so the data is in the same state it was prior to the -initialization of the release process.

    A picture containing chart Description automatically generated

    A custom release process in Onshape

    \ No newline at end of file +initialization of the release process.

    A picture containing chart Description automatically generated

    A custom release process in Onshape

    \ No newline at end of file diff --git a/docs/app-dev/clientmessaging/index.html b/docs/app-dev/clientmessaging/index.html index 56be674..6aa67e4 100644 --- a/docs/app-dev/clientmessaging/index.html +++ b/docs/app-dev/clientmessaging/index.html @@ -1,14 +1,16 @@ -Client Messaging | Client Messaging |

    Client Messaging

    Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message.

    image alt text

    Onshape Client Messaging examples can be split into those that are initiated from the application extension and those that are initiated from the Onshape client.

    Messages from the Extension

    These Client Messaging examples can be initiated from the application extension:

    • Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.) and dropdown menus (profile dropdown menu, document menu) to close. Without this, flyouts and menus might remain open over the application extension.
    • Shortcut keyboard events: Shortcut keys (such as ?, which opens the Onshape Help dialog), can be handled by the application extension by posting a message to the Onshape client to open the dialog.
    • keepAlive: Notify the Onshape client that the user is actively working in the application extension, which triggers the Onshape client to send a message to the server to keep the browser session alive. Without this, the Onshape browser session will timeout and ask the user to sign in again.
    • Standard Onshape dialogs: Request from the application extension to the Onshape client to open one of the Onshape standard dialogs and send the user’s choices back to the application extension. For example, if the application extension needs the user to choose a part or assembly to be operated on, the application extension can post a message to the Onshape client requesting that dialog be opened and the selected part or assembly information sent back to the application extension.
    • UI customization": Request from the application extension to the Onshape client to customize the Onshape UI (e.g., add commands to menus, add buttons to the toolbars, etc). When these commands or toolbar buttons are clicked, the Onshape client posts a message to the application extension with the available context.
      • Note: This is limited to cases where the application extension is made active by the user; application extensions are not automatically loaded when a document is opened. Most UI customizations should be done when you register the application with Onshape, as those change the Onshape client automatically without needing to load the application extension first.
    • Content/material insertion: Request from the application extension to insert content into the Onshape document. For example, insert a part into a new or existing Part Studio, apply a material to a part, add a material to a material library, etc.

    Messages from Onshape

    The following examples can be initiated from the Onshape client:

    • User action notification: The Onshape client can notify an application extension when various user actions occur. For example, the Onshape client might notify when the user has made the application extension active or inactive (when the user clicks on document tabs). When an application extension is made inactive, it is moved off the edges of the browser, so it cannot be seen, but is still active, preserving its state.
    • Printing: The Onshape client can notify an application extension when the user has chosen the Print command from the main Onshape document menu, enabling the application extension to perform a print operation.

    Security Considerations

    To ensure security, an application extension must:

    • Parse for document, workspace, and element IDs: Parse for the documentId, workspaceId, and elementId that were passed as query parameters within the application extension’s iframe src URL. You must post these back in each POST message.
    • Parse for the server: Parse for the server that was passed as a query parameter within the application extension’s iframe src URL. You must use this to validate messages received.
      • If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.
    • Not redirect to another base URL: The browser tells the Onshape client the origin base URL from which a POST message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframe src URL. It is extremely important to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframe src (i.e., if (server === e.origin)). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframe src server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored.
    • Post a message on startup: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A keepAlive message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.

    POST messages submitted by application extensions to Onshape will be ignored if any of the following are true:

    • The documentId, workspaceId, or elementId are missing or not valid.
    • The message name is missing or not recognized.
    • The origin of the POST message does not match the original iframe src URL.

    Element Tab

    Messages may be sent and received by element tab application extensions.

    The following messages can be sent by Element tab application extensions:

    messageName +Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.">

    Client Messaging

    Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message.

    image alt text

    Onshape Client Messaging examples can be split into those that are initiated from the application extension and those that are initiated from the Onshape client.

    Messages from the Extension

    These Client Messaging examples can be initiated from the application extension:

    • Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.) and dropdown menus (profile dropdown menu, document menu) to close. Without this, flyouts and menus might remain open over the application extension.
    • Shortcut keyboard events: Shortcut keys (such as ?, which opens the Onshape Help dialog), can be handled by the application extension by posting a message to the Onshape client to open the dialog.
    • keepAlive: Notify the Onshape client that the user is actively working in the application extension, which triggers the Onshape client to send a message to the server to keep the browser session alive. Without this, the Onshape browser session will timeout and ask the user to sign in again.
    • Standard Onshape dialogs: Request from the application extension to the Onshape client to open one of the Onshape standard dialogs and send the user’s choices back to the application extension. For example, if the application extension needs the user to choose a part or assembly to be operated on, the application extension can post a message to the Onshape client requesting that dialog be opened and the selected part or assembly information sent back to the application extension.
    • UI customization": Request from the application extension to the Onshape client to customize the Onshape UI (e.g., add commands to menus, add buttons to the toolbars, etc). When these commands or toolbar buttons are clicked, the Onshape client posts a message to the application extension with the available context.
      • Note: This is limited to cases where the application extension is made active by the user; application extensions are not automatically loaded when a document is opened. Most UI customizations should be done when you register the application with Onshape, as those change the Onshape client automatically without needing to load the application extension first.
    • Content/material insertion: Request from the application extension to insert content into the Onshape document. For example, insert a part into a new or existing Part Studio, apply a material to a part, add a material to a material library, etc.

    Messages from Onshape

    The following examples can be initiated from the Onshape client:

    • User action notification: The Onshape client can notify an application extension when various user actions occur. For example, the Onshape client might notify when the user has made the application extension active or inactive (when the user clicks on document tabs). When an application extension is made inactive, it is moved off the edges of the browser, so it cannot be seen, but is still active, preserving its state.
    • Printing: The Onshape client can notify an application extension when the user has chosen the Print command from the main Onshape document menu, enabling the application extension to perform a print operation.

    Security Considerations

    To ensure security, an application extension must:

    • Parse for document, workspace, and element IDs: Parse for the documentId, workspaceId, and elementId that were passed as query parameters within the application extension’s iframe src URL. You must post these back in each POST message.
    • Parse for the server: Parse for the server that was passed as a query parameter within the application extension’s iframe src URL. You must use this to validate messages received.
      • If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.
    • Not redirect to another base URL: The browser tells the Onshape client the origin base URL from which a POST message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframe src URL. It is extremely important to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframe src (i.e., if (server === e.origin)). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframe src server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored.
    • Post a message on startup: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A keepAlive message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.

    POST messages submitted by application extensions to Onshape will be ignored if any of the following are true:

    • The documentId, workspaceId, or elementId are missing or not valid.
    • The message name is missing or not recognized.
    • The origin of the POST message does not match the original iframe src URL.

    Element Tab

    Messages may be sent and received by element tab application extensions.

    The following messages can be sent by Element tab application extensions:

    messageName (case sensitive)other message properties?comment
    applicationInityes
    notifyWhenSaveRequired: whether Onshape should send a notification to save pending changes during certain operations
     (default is false)
     
    Send once on application startup.
    closeFlyoutsAndMenusnoSend when a mouse click or other event happens in the application extension. Closes Onshape flyouts and dropdown menus.
    closeSelectItemDialognoCloses the select item dialog.
    connectionLostnoDisplays the standard Onshape connection lost message in a message bubble, forcing the user to either reload the document or return to the documents page.
    errorReloadyes
    message: your message
    @@ -165,7 +167,7 @@
     };
     
     window.parent.postMessage(initMessage, '*');
    -

    Right panel interaction sequence

    The sequence diagram below illustrates the interaction between an Element right panel application extension and the Onshape client:

    %%{
    +

    Right panel interaction sequence

    The sequence diagram below illustrates the interaction between an Element right panel application extension and the Onshape client:

    %%{
       init: {
         "theme": "default",
         "sequence": {
    @@ -184,9 +186,9 @@
       actor user
       participant OSC AS Onshape Client
       participant AE AS Application Extension
    -  user->>+OSC: start element right panel extension
    +  user->>+OSC: start element right panel extension
       Note right of user: via configured button
    -  OSC->>+AE: invoke action url (with query params)
    +  OSC->>+AE: invoke action url (with query params)
       AE->>OSC: postMessage(messageName: 'applicationInit')
       loop selection interactions
         user->>OSC: select
    @@ -196,8 +198,7 @@
         Note right of user: via configured button
       deactivate AE
       OSC-XAE: destroy
    -  deactivate OSC
    -

    Right panel message exchange

    The following messages are exchanged for application extensions located in the element right panel and configured for Part Studio, Assembly, or Document contexts.

    The first message with messageName attribute set to applicationInit is sent to the Onshape client by an application extension once it is loaded and ready to receive and process incoming messages:

        {
    +  deactivate OSC

    Right panel message exchange

    The following messages are exchanged for application extensions located in the element right panel and configured for Part Studio, Assembly, or Document contexts.

    The first message with messageName attribute set to applicationInit is sent to the Onshape client by an application extension once it is loaded and ready to receive and process incoming messages:

        {
             documentId: '<document id>',
             workspaceId: '<workspace id>',
             elementId: '<element id>',
    @@ -226,4 +227,59 @@
             }
         ]
     }
    -

    Notes

    Keyboard focus

    Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a show message from Onshape. Shortcut keys will work immediately when the application is shown.

    Future work

    • New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.
    • Mobile client support is unclear at this time.
    • Onshape is considering using promises to wrap POST messages, which would make the application extension’s JavaScript simpler and enable chaining POSTs with other operations. Promises would make some interactions with multiple responses difficult (e.g., when you open a dialog, like the Select Item dialog, and want to receive multiple POST messages back due to the user clicking on multiple items in the dialog).
    \ No newline at end of file +

    Notes

    Keyboard focus

    Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a show message from Onshape. Shortcut keys will work immediately when the application is shown.

    Future work

    • New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.
    • Mobile client support is unclear at this time.
    • Onshape is considering using promises to wrap POST messages, which would make the application extension’s JavaScript simpler and enable chaining POSTs with other operations. Promises would make some interactions with multiple responses difficult (e.g., when you open a dialog, like the Select Item dialog, and want to receive multiple POST messages back due to the user clicking on multiple items in the dialog).
    \ No newline at end of file diff --git a/docs/app-dev/extensions/index.html b/docs/app-dev/extensions/index.html index 8d57557..1750583 100644 --- a/docs/app-dev/extensions/index.html +++ b/docs/app-dev/extensions/index.html @@ -1,6 +1,4 @@ -Extensions |

    Extensions

    This page provides information for some of the more common options for +Extensions |

    Extensions

    This page provides information for some of the more common options for embedding a third-party application into the Onshape interface. Onshape provides many options for embedding commands in various menus, fly-out panels, and elements. In this example, you will embed a custom web page inside a document’s right side fly-out panel. This interface will receive information from Onshape and push information from the panel back to Onshape, providing a complete, bi-directional integration scenario.

    Please see also:

    Extension Types

    We can classify extensions into two high-level types. The first type embeds a UI from the application into the Onshape UI. The embedded UI is an HTTPS page displayed in an iFrame in the Onshape UI. The UI is served from the application, and can choose to make API calls to Onshape for additional information. This is exactly like the traditional tab-based applications in Onshape, except that such extensions exist at different UI locations.

    The second type of extension embeds an action that calls a REST API exposed by the application from the Onshape UI (e.g., context menu actions and toolbar actions). These types of extensions rely on External OAuth information to authenticate and make a call where Onshape acts as a client, and the application acts as a server.

    Extension Attributes

    Each extension exists at a specific place in the Onshape UI and works with a specific context or selection. The attributes of an extension are:

    1. Name: This should be short and explicit. It will appear in the Onshape UI as a menu item, a toolbar tooltip, a collapsed panel icon tooltip, or a panel icon. It might be truncated in the UI if it is too long.
    2. Description: This is where the developer can record a detailed description of the extension. It does not appear in the Onshape UI, but could appear in the grant process.
    3. Location: This describes where the extension exists in the Onshape UI. Over time, this will cover various panels in the UI, context menus, toolbars, actions in dialogs, etc. You can see the list of currently supported locations here.
      • Please note that you can create only one element tab extension per application.
    4. Context (selection): Some locations will work in the context of a selection. Let’s say the application developer wants to show some information from a third-party system, pertinent only to parts (not assemblies or drawings). In this scenario, the developer would choose a location like ‘Document list info panel’, and the context as ‘Selected part’. If the user searches for something in the document list, some documents, Part Studios, parts, and Assemblies would be returned. This extension will show up in the Info panel only if the selected entity is a part. Using context enables application developers to control when the extension is displayed. Check the list of contexts available for different locations here.
    5. Action URL: Locations that embed a UI use the action URL to define the address of the page to display. The action URL is used to specify the REST endpoint if the location is an action (context menu, toolbar item, action in dialog etc.) and the action type is GET or POST. If the location is an action and the action is ‘Open in new window’, the action URL is the URL to open in the new window.
      The action URL can be parameterized to pass information from Onshape to the application. The action URL replaces attributes in the format {$attribute} with the appropriate value. These attributes can be used to identify the selected entity and/or make calls back to Onshape via the API. The currently supported attributes are:
      • {$documentId} - The Onshape ID for the current or selected document.
      • {$workspaceOrVersion} - This will be either w or v for workspace or version respectively depending on current opened document state or selection.
      • {$workspaceOrVersionId} - The Onshape ID for the current or selected workspace or version.
      • {$workspaceId} - Use {$workspaceOrVersionId} instead.
      • {$versionId} - Use {$workspaceOrVersionId} instead.
      • {$microversionId} - The Onshape ID for the current or select document microversion.
      • {tabElementId} - The Onshape ID for the current tab.
      • {$elementId} - The Onshape ID for the current or selected element.
      • Note: In most cases, tabElementId and elementId will be the same. However, when creating an extension with the Selected instance context, tabElementId indicates the current tab (i.e., the target element), and elementId indicates the tab from which the instance/subassembly was inserted (i.e., the source element).
      • {$partId} - The Onshape ID for the current or selected part.
      • {$partNumber} - The Part number property for the current or selected part, assembly or drawing.
      • {$revision} - The Revision property for the current or selected part, assembly or drawing.
      • {$companyId} - The ID for the company that owns the document.
      • {$mimeType} - The mime type if the current or selected element is a blob.
      • {$featureId} - In case of feature selected in the Feature list in a Part Studio.
      • {$nodeId} - In case of mate or mate feature selected in the Assembly list.
      • {$occurrencePath} - In case of part instances, mates, mate connectors and sub assemblies.
      • {$configuration} - In case of extensions inside the document, this attribute will be replaced by current element active configuration.

    The attributes can exist as path parameters or query parameters or attributes in the POST body. For example:

    [https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId={$documentId}&workspaceOrVersion={workspaceOrVersion}&workspaceOrVersionId={$workspaceOrVersionId}&elementId={$elementId}&partId={$partId}&server=https://cad.onshape.com&companyId=cad&userId=5f1eba76c14a434817d9c588&locale=en-US](https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId=%7B$documentId%7D&workspaceId=%7B$workspaceId%7D&elementId=%7B$elementId%7D&partId=%7B$partId) 
     

    or

    [https://cad.onshape.com/api/partstudios/d/{$documentId}/{$workspaceOrVersion}/{$workspaceOrVersionId}/e/{$elementId}/stl?server=https://cad.onshape.com&companyId=cad&userId=5f1eba76c14a434817d9c588&locale=en-US](https://cad.onshape.com/api/partstudios/d/%7B$documentId%7D/w/%7B$workspaceId%7D/e/%7B$elementId%7D/stl) 
    @@ -29,4 +27,4 @@
                "partNumber" : <next part number generated by third party numbering scheme>
        }
      ]
    -

    Third-party applications can simply fill the "partNumber" attribute with the part number generated by the custom numbering scheme and send it as a response. However, the response should at least contain "id" and "partNumber" as highlighted above; other attributes are optional.

    Custom numbering schemes for part generation, once set in the Release management page, can be invoked from all the places where we set part numbers, including the Release candidate dialog shown below:

    image alt text

    Sample code

    We have provided a sample application that supports the features described in this document.

    The source code for this Inventory management application can be found in our public GitHub repository.

    The instructions to install and the application are available in the README.md file in the repository.

    The application is built on the Passport node module. It is based on this article. Please read the article before proceeding with this section.

    Some structural information about the application:

    • The dependencies are defined in package.json
    • The routing for inbound calls is defined in server.js. This includes routing for OAuth2 calls as well as calls for the rest APIs we expose that Onshape can call via the extensions.
    • The OAuth2 calls are routed to controllers/oauth2.js. These include calls to authenticate as calls to get the bearer token.
    • controllers/oauth2.js uses controllers/auth.js to interact with Passport to manage the authentication and storage.
    • Other API calls to get part number, etc, route to the appropriate controller in the controllers directory.
    • The controllers use the model defined in the model directory.

    The application is defined in the Developer Portal with extensions that use the exposed APIs.

    The following screenshots define the base configuration of the application and some of the sample extensions.

    \ No newline at end of file +

    Third-party applications can simply fill the "partNumber" attribute with the part number generated by the custom numbering scheme and send it as a response. However, the response should at least contain "id" and "partNumber" as highlighted above; other attributes are optional.

    Custom numbering schemes for part generation, once set in the Release management page, can be invoked from all the places where we set part numbers, including the Release candidate dialog shown below:

    image alt text

    Sample code

    We have provided a sample application that supports the features described in this document.

    The source code for this Inventory management application can be found in our public GitHub repository.

    The instructions to install and the application are available in the README.md file in the repository.

    The application is built on the Passport node module. It is based on this article. Please read the article before proceeding with this section.

    Some structural information about the application:

    • The dependencies are defined in package.json
    • The routing for inbound calls is defined in server.js. This includes routing for OAuth2 calls as well as calls for the rest APIs we expose that Onshape can call via the extensions.
    • The OAuth2 calls are routed to controllers/oauth2.js. These include calls to authenticate as calls to get the bearer token.
    • controllers/oauth2.js uses controllers/auth.js to interact with Passport to manage the authentication and storage.
    • Other API calls to get part number, etc, route to the appropriate controller in the controllers directory.
    • The controllers use the model defined in the model directory.

    The application is defined in the Developer Portal with extensions that use the exposed APIs.

    The following screenshots define the base configuration of the application and some of the sample extensions.

    \ No newline at end of file diff --git a/docs/app-dev/index.html b/docs/app-dev/index.html index 5e620ba..82cd4f8 100644 --- a/docs/app-dev/index.html +++ b/docs/app-dev/index.html @@ -1,5 +1,10 @@ -App Development |

    App Development

    The primary APIs provided by Onshape are REST interfaces that can be accessed over HTTPS. The client can be a web server or a desktop application (including command line tools, such as curl). Onshape does not support use of the APIs directly from a browser client due to cross-domain scripting concerns.

    Partner applications typically interact with Onshape in three ways:

    • File Exchange: Onshape provides extensive import and export translation capabilities to interact with applications that can read or write a variety of file formats.
    • Live Link Integration: Desktop or server applications can use REST calls to read information from the Onshape servers and store information back. These applications can gain “cloud value” by using Onshape data management capabilities for sharing, versioning, and durability.
    • In-Tab Integration: Web server applications can create a tightly integrated experience within Onshape by using a combination of REST and client-side APIs to build a seamless interaction by interacting with users inside an Onshape tab.

    The following diagram illustrates basic desktop integration and cloud integration architecture:

    images

    The Onshape Server Stack consists of several cooperating servers that provide the underlying support for the Onshape CAD experience. The Onshape servers are built with a variety of technologies, including Java and C++, database and message services, geometry and constraint management systems, and much more.

    Partner cloud applications can be written in any web framework. Onshape provides a set of sample apps in Github, as well as text tutorials.

    You may notice that the above diagram does not illustrate the Onshape mobile clients for iOS and Android devices; the development of 3rd-party mobile applications for Onshape is beyond the scope of this document.

    Integration Considerations

    There is much to Onshape that is different from +App Development |

    App Development

    The primary APIs provided by Onshape are REST interfaces that can be accessed over HTTPS. The client can be a web server or a desktop application (including command line tools, such as curl). Onshape does not support use of the APIs directly from a browser client due to cross-domain scripting concerns.

    Partner applications typically interact with Onshape in three ways:

    • File Exchange: Onshape provides extensive import and export translation capabilities to interact with applications that can read or write a variety of file formats.
    • Live Link Integration: Desktop or server applications can use REST calls to read information from the Onshape servers and store information back. These applications can gain “cloud value” by using Onshape data management capabilities for sharing, versioning, and durability.
    • In-Tab Integration: Web server applications can create a tightly integrated experience within Onshape by using a combination of REST and client-side APIs to build a seamless interaction by interacting with users inside an Onshape tab.

    The following diagram illustrates basic desktop integration and cloud integration architecture:

    images

    The Onshape Server Stack consists of several cooperating servers that provide the underlying support for the Onshape CAD experience. The Onshape servers are built with a variety of technologies, including Java and C++, database and message services, geometry and constraint management systems, and much more.

    Partner cloud applications can be written in any web framework. Onshape provides a set of sample apps in Github, as well as text tutorials.

    You may notice that the above diagram does not illustrate the Onshape mobile clients for iOS and Android devices; the development of 3rd-party mobile applications for Onshape is beyond the scope of this document.

    Integration Considerations

    There is much to Onshape that is different from traditional CAD and PDM systems. For system integrators who have previous experience with these types of systems, the instinct is to try and apply the concepts developed for those integrations to an Onshape @@ -24,4 +29,4 @@ to develop a successful integration if the requirements aren’t clearly stated. The business process(es) that you manage through the integration should be mapped out, along with the systems -involved and which system is responsible for which function.

  • Use standards and Published APIs: Developers hate when thousands of lines of code and days of work are thrown away because of an upgrade of a piece of software. By using industry standards and published APIs, you will protect yourself from such a disaster.
  • Create an Application

    To create an application that interacts with Onshape:

    1. Follow the steps on the OAuth page to register your application in the Onshape Developer Portal and set up authentication.
      • Onshape uses industry standards for establishing a secure connection between itself and a third-party application. To access Onshape’s resources, any application requesting those resources must be authenticated by Onshape. Likewise, if Onshape needs to access resources from a third-party application, Onshape must be correctly authenticated by the third party prior to access being granted.
    2. Use the Onshape APIs to create your application.
    3. Review the other pages in the App Development section of the Developer Documentation for information on app development best practices and methodologies.
    4. Follow the steps on the Onshape App Store page to submit your application to the Onshape App Store.

    Resources

    \ No newline at end of file +involved and which system is responsible for which function.
  • Use standards and Published APIs: Developers hate when thousands of lines of code and days of work are thrown away because of an upgrade of a piece of software. By using industry standards and published APIs, you will protect yourself from such a disaster.
  • Create an Application

    To create an application that interacts with Onshape:

    1. Follow the steps on the OAuth page to register your application in the Onshape Developer Portal and set up authentication.
      • Onshape uses industry standards for establishing a secure connection between itself and a third-party application. To access Onshape’s resources, any application requesting those resources must be authenticated by Onshape. Likewise, if Onshape needs to access resources from a third-party application, Onshape must be correctly authenticated by the third party prior to access being granted.
    2. Use the Onshape APIs to create your application.
    3. Review the other pages in the App Development section of the Developer Documentation for information on app development best practices and methodologies.
    4. Follow the steps on the Onshape App Store page to submit your application to the Onshape App Store.

    Resources

    \ No newline at end of file diff --git a/docs/app-dev/index.xml b/docs/app-dev/index.xml index d472573..eba1979 100644 --- a/docs/app-dev/index.xml +++ b/docs/app-dev/index.xml @@ -1,1331 +1,7 @@ -– App Developmenthttps://onshape-public.github.io/docs/app-dev/Recent content in App Development onHugo -- gohugo.ioen-usMon, 18 May 2020 20:44:05 -0400Docs: Extensionshttps://onshape-public.github.io/docs/app-dev/extensions/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/extensions/ -<p>This page provides information for some of the more common options for -embedding a third-party application into the Onshape interface. Onshape provides many options for embedding commands in various menus, fly-out panels, and elements. In this example, you will embed a custom web page inside a document’s right side fly-out panel. This interface will receive information from Onshape and push information from the panel back to Onshape, providing a complete, bi-directional integration scenario.</p> -<p>Please see also:</p> -<ul> -<li><a href="https://onshape-public.github.io/docs/tutorials/createextension/">Create an Extension tutorial</a>: A step-by-step walkthrough of creating an extension.</li> -<li>Create an Extension Video Sample: -<a href="https://onshape.wistia.com/medias/0ivxxngkjz?embedType=async&seo=false&videoFoam=true&videoWidth=640&wvideo=0ivxxngkjz)"><img src="https://onshape-public.github.io/images/ExtensionsVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></li> -</ul> -<h2 id="extension-types">Extension Types</h2> -<p>We can classify extensions into two high-level types. The first type embeds a UI <em>from</em> the application <em>into</em> the Onshape UI. The embedded UI is an HTTPS page displayed in an iFrame in the Onshape UI. The UI is served from the application, and can choose to make API calls to Onshape for additional information. This is exactly like the traditional tab-based applications in Onshape, except that such extensions exist at different UI locations.</p> -<p>The second type of extension embeds an action that calls a REST API <em>exposed by</em> the application <em>from</em> the Onshape UI (e.g., context menu actions and toolbar actions). These types of extensions rely on External OAuth information to authenticate and make a call where Onshape acts as a client, and the application acts as a server.</p> -<h2 id="extension-attributes">Extension Attributes</h2> -<p>Each extension exists at a specific place in the Onshape UI and works with a specific context or selection. The attributes of an extension are:</p> -<ol> -<li><strong>Name</strong>: This should be short and explicit. It will appear in the Onshape UI as a menu item, a toolbar tooltip, a collapsed panel icon tooltip, or a panel icon. It might be truncated in the UI if it is too long.</li> -<li><strong>Description</strong>: This is where the developer can record a detailed description of the extension. It does not appear in the Onshape UI, but could appear in the grant process.</li> -<li><strong>Location</strong>: This describes where the extension exists in the Onshape UI. Over time, this will cover various panels in the UI, context menus, toolbars, actions in dialogs, etc. You can see the list of currently supported locations <a href="#supported-locations-and-contexts">here</a>. -<ul> -<li>Please note that you can create only one element tab extension per application.</li> -</ul> -</li> -<li><strong>Context</strong> (selection): Some locations will work in the context of a selection. Let’s say the application developer wants to show some information from a third-party system, pertinent only to parts (not assemblies or drawings). In this scenario, the developer would choose a location like ‘Document list info panel’, and the context as ‘Selected part’. If the user searches for something in the document list, some documents, Part Studios, parts, and Assemblies would be returned. This extension will show up in the Info panel only if the selected entity is a part. Using context enables application developers to control when the extension is displayed. Check the list of contexts available for different locations <a href="#supported-locations-and-contexts">here</a>.</li> -<li><strong>Action URL</strong>: Locations that embed a UI use the action URL to define the address of the page to display. The action URL is used to specify the REST endpoint if the location is an action (context menu, toolbar item, action in dialog etc.) and the action type is GET or POST. If the location is an action and the action is ‘Open in new window’, the action URL is the URL to open in the new window.<br> -The action URL can be parameterized to pass information from Onshape to the application. The action URL replaces attributes in the format {$attribute} with the appropriate value. These attributes can be used to identify the selected entity and/or make calls back to Onshape via the API. The currently supported attributes are: -<ul> -<li><code>{$documentId}</code> - The Onshape ID for the current or selected document.</li> -<li><code>{$workspaceOrVersion}</code> - This will be either <code>w</code> or <code>v</code> for workspace or version respectively depending on current opened document state or selection.</li> -<li><code>{$workspaceOrVersionId}</code> - The Onshape ID for the current or selected workspace or version.</li> -<li><code>{$workspaceId}</code> - Use <code>{$workspaceOrVersionId}</code> instead.</li> -<li><code>{$versionId}</code> - Use <code>{$workspaceOrVersionId}</code> instead.</li> -<li><code>{$microversionId}</code> - The Onshape ID for the current or select document microversion.</li> -<li><code>{tabElementId}</code> - The Onshape ID for the current tab.</li> -<li><code>{$elementId}</code> - The Onshape ID for the current or selected element.</li> -<li><strong>Note</strong>: In most cases, <code>tabElementId</code> and <code>elementId</code> will be the same. However, when creating an extension with the <code>Selected instance</code> context, <code>tabElementId</code> indicates the current tab (i.e., the target element), and <code>elementId</code> indicates the tab from which the instance/subassembly was inserted (i.e., the source element).</li> -<li><code>{$partId}</code> - The Onshape ID for the current or selected part.</li> -<li><code>{$partNumber}</code> - The Part number property for the current or selected part, assembly or drawing.</li> -<li><code>{$revision}</code> - The Revision property for the current or selected part, assembly or drawing.</li> -<li><code>{$companyId}</code> - The ID for the company that owns the document.</li> -<li><code>{$mimeType}</code> - The mime type if the current or selected element is a blob.</li> -<li><code>{$featureId}</code> - In case of feature selected in the Feature list in a Part Studio.</li> -<li><code>{$nodeId}</code> - In case of mate or mate feature selected in the Assembly list.</li> -<li><code>{$occurrencePath}</code> - In case of part instances, mates, mate connectors and sub assemblies.</li> -<li><code>{$configuration}</code> - In case of extensions inside the document, this attribute will be replaced by current element active configuration.</li> -</ul> -</li> -</ol> -<p>The attributes can exist as path parameters or query parameters or attributes in the POST body. For example:</p> -<pre tabindex="0"><code>[https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId={$documentId}&amp;workspaceOrVersion={workspaceOrVersion}&amp;workspaceOrVersionId={$workspaceOrVersionId}&amp;elementId={$elementId}&amp;partId={$partId}&amp;server=https://cad.onshape.com&amp;companyId=cad&amp;userId=5f1eba76c14a434817d9c588&amp;locale=en-US](https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId=%7B$documentId%7D&amp;workspaceId=%7B$workspaceId%7D&amp;elementId=%7B$elementId%7D&amp;partId=%7B$partId) -</code></pre><p>or</p> -<pre tabindex="0"><code>[https://cad.onshape.com/api/partstudios/d/{$documentId}/{$workspaceOrVersion}/{$workspaceOrVersionId}/e/{$elementId}/stl?server=https://cad.onshape.com&amp;companyId=cad&amp;userId=5f1eba76c14a434817d9c588&amp;locale=en-US](https://cad.onshape.com/api/partstudios/d/%7B$documentId%7D/w/%7B$workspaceId%7D/e/%7B$elementId%7D/stl) -</code></pre><p>The attributes available for replacement differ by location and context selection. You can see the available attributes for each location <a href="#supported-locations-and-contexts">here</a>.</p> -<p>The <strong>timeout</strong> for <code>action_url</code> of type <code>GET</code> or <code>POST</code> is <strong>180 seconds</strong>.</p> -<ol start="6"> -<li> -<p><strong>Action type</strong>: The action type is only applicable for locations that act as actions and not for locations that embed UIs. Check if action type is valid for a location <a href="#supported-locations-and-contexts">here</a>. The supported action types are:</p> -<ul> -<li><code>GET</code> - This makes a GET API call using the action URL. Parameter replacement is done on the action URL.</li> -<li><code>POST</code> - This makes a POST API call using the action URL and the action body as the post body. Parameter replacement is done on both the action URL and the action body.</li> -<li><code>Open in new window</code> - This opens the action URL in a new browser window. Parameter replacement is done on the action URL.</li> -</ul> -</li> -<li> -<p><strong>Action body</strong>: This is only applicable if the action type is POST. The action body is passed in a POST API call and must be in a valid json format.</p> -</li> -<li> -<p><strong>Show response</strong>: This is only applicable if the action type is GET or POST. If this is checked, the UI will wait for a response and show the response in a dialog in the UI. The response must be in a valid json format.</p> -</li> -<li> -<p><strong>Icon</strong>: The icon will be shown where the extension exists. This can be an icon in an Info panel, context menu action, toolbar button, action button in a dialog, or other supported locations.</p> -</li> -</ol> -<h2 id="supported-locations-and-contexts">Supported Locations and Contexts</h2> -<p>This is the list of supported locations, their valid contexts, and whether they support action types.</p> -<h3 id="element-context-menu">Element context menu</h3> -<p>This is the context menu for elements.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage04.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacements:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$mimeType}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="tree-context-menu">Tree context menu</h3> -<p>This is the context menu for the part tree, assembly tree and feature tree in part studios.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage05.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Sub assembly</code></li> -<li><code>Feature</code></li> -<li><code>Mate</code></li> -<li><code>Mate feature</code></li> -<li><code>Instance</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$featureId}</code></li> -<li><code>{$nodeId}</code></li> -<li><code>{$occurrencePath}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="document-list-context-menu">Document list context menu</h3> -<p>This the context menu available on items in the document list. This is normally documents but can be multiple types based on search results.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage06.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="document-list-info-panel">Document list info panel</h3> -<p>This is the Info panel to the right in the document list. The document list normally contains documents, but can contain other entities as the result of a search.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage07.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partId}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location does NOT support action types.</p> -<h3 id="element-right-panel">Element right panel</h3> -<p>This is the panel inside a document. It currently houses the BOM, configurations, etc. Applications can use this extension location to add items in this panel.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage08.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Sub assembly</code></li> -<li><code>Feature</code></li> -<li><code>Mate</code></li> -<li><code>Mate feature</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$featureId}</code></li> -<li><code>{$nodeId}</code></li> -<li><code>{$occurrencePath}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location does NOT support action types.</p> -<h3 id="new-element-tab">New Element tab</h3> -<p>This is the menu option for <code>+ menu -&gt; Add application</code> inside a document . After menu click, a new tab will be created with the action url associated with this extension.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage09.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li>There are no supported contexts.</li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li>Parameter replacement not supported.</li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>documentId</code></li> -<li><code>workspaceId</code></li> -<li><code>versionId</code></li> -<li><code>elementId</code></li> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="part-number-generator">Part number generator</h3> -<p>This extension helps partners to embed their own custom part number generation scheme in Onshape. Each application can have only one extension of this type. Once defined, these extensions are listed as one of the part numbering schemes in the release management configuration in Company settings.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage10.png" alt="image alt text"></p> -<p>In the above screen shot, ‘Part number generation scheme’ is the user-defined name of the extension.</p> -<p>Supported contexts:</p> -<ul> -<li>There are no supported contexts.</li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li>Parameter replacement is not supported.</li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li>No default query parameters</li> -</ul> -<p>Action URL defined by the user is assumed to be a POST API. This API should consume a predefined request body as shown below. This definition may have additional attributes in future.</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;id&#34;</span> : &lt;internal part number id&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;documentId&#34;</span> : &lt;documentId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementId&#34;</span> : &lt;elementId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;workspaceId&#34;</span> : &lt;workspaceId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementType&#34;</span> : &lt;elementType&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partId&#34;</span> : &lt;partId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;companyId&#34;</span> : &lt;companyId&gt;, <span style="color:#aaa;font-style:italic">// Id of the company that owns the document, else the text “cad” -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#a50">&#34;partNumber&#34;</span> : &lt;current part number&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;configuration&#34;</span> : &lt;configuration string&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;categories&#34;</span> : &lt;array <span style="color:#00a">of</span> category ids and names&gt; <span style="color:#aaa;font-style:italic">// [ { &#34;id&#34;: &lt;String&gt;, &#34;name&#34;: &lt;string&gt; } ] -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span> ] -</span></span></code></pre></div><p><strong>Note</strong>: Categories are only passed from the Release dialog and properties dialogs for now. They are empty when part number generation is called from the BOM table or configuration table.</p> -<p>Expected response sent to Onshape is as follows:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;id&#34;</span> : &lt;internal part number id&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;documentId&#34;</span> : &lt;documentId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementId&#34;</span> : &lt;elementId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;workspaceId&#34;</span> : &lt;workspaceId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementType&#34;</span> : &lt;elementType&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partId&#34;</span> : &lt;partId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partNumber&#34;</span> : &lt;next part number generated by third party numbering scheme&gt; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> ] -</span></span></code></pre></div><p>Third-party applications can simply fill the <code>&quot;partNumber&quot;</code> attribute with the part number generated by the custom numbering scheme and send it as a response. However, the response should at least contain <code>&quot;id&quot;</code> and <code>&quot;partNumber&quot;</code> as highlighted above; other attributes are optional.</p> -<p>Custom numbering schemes for part generation, once set in the Release management page, can be invoked from all the places where we set part numbers, including the Release candidate dialog shown below:</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage11.png" alt="image alt text"></p> -<h2 id="sample-code">Sample code</h2> -<p>We have provided a sample application that supports the features described in this document.</p> -<p>The source code for this <code>Inventory management</code> application can be found <a href="https://github.com/onshape-public/inventory-oauth2-app">in our public GitHub repository</a>.</p> -<p>The instructions to install and the application are available in the <code>README.md</code> file in the repository.</p> -<p>The application is built on the Passport node module. It is based on this <a href="http://scottksmith.com/blog/2014/05/02/building-restful-apis-with-node/">article</a>. Please read the article before proceeding with this section.</p> -<p>Some structural information about the application:</p> -<ul> -<li>The dependencies are defined in <code>package.json</code></li> -<li>The routing for inbound calls is defined in <code>server.js</code>. This includes routing for OAuth2 calls as well as calls for the rest APIs we expose that Onshape can call via the extensions.</li> -<li>The OAuth2 calls are routed to <code>controllers/oauth2.js</code>. These include calls to authenticate as calls to get the bearer token.</li> -<li><code>controllers/oauth2.js</code> uses <code>controllers/auth.js</code> to interact with Passport to manage the authentication and storage.</li> -<li>Other API calls to get part number, etc, route to the appropriate controller in the controllers directory.</li> -<li>The controllers use the model defined in the model directory.</li> -</ul> -<p>The application is defined in the Developer Portal with extensions that use the exposed APIs.</p> -<p>The following screenshots define the base configuration of the application and some of the sample extensions.</p>Docs: Client Messaginghttps://onshape-public.github.io/docs/app-dev/clientmessaging/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/clientmessaging/ -<p>Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message.</p> -<p><img src="https://onshape-public.github.io/images/javascriptpostmessageimage00.png" alt="image alt text"></p> -<p>Onshape Client Messaging examples can be split into those that are initiated from the <em>application extension</em> and those that are initiated from the <em>Onshape client</em>.</p> -<h2 id="messages-from-the-extension">Messages from the Extension</h2> -<p>These Client Messaging examples can be initiated from the application extension:</p> -<ul> -<li><strong>Click/close flyouts events</strong>: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.) and dropdown menus (profile dropdown menu, document menu) to close. Without this, flyouts and menus might remain open over the application extension.</li> -<li><strong>Shortcut keyboard events</strong>: Shortcut keys (such as <code>?</code>, which opens the Onshape Help dialog), can be handled by the application extension by posting a message to the Onshape client to open the dialog.</li> -<li><strong>keepAlive</strong>: Notify the Onshape client that the user is actively working in the application extension, which triggers the Onshape client to send a message to the server to keep the browser session alive. Without this, the Onshape browser session will timeout and ask the user to sign in again.</li> -<li><strong>Standard Onshape dialogs</strong>: Request from the application extension to the Onshape client to open one of the Onshape standard dialogs and send the user’s choices back to the application extension. For example, if the application extension needs the user to choose a part or assembly to be operated on, the application extension can post a message to the Onshape client requesting that dialog be opened and the selected part or assembly information sent back to the application extension.</li> -<li><strong>UI customization</strong>&quot;: Request from the application extension to the Onshape client to customize the Onshape UI (e.g., add commands to menus, add buttons to the toolbars, etc). When these commands or toolbar buttons are clicked, the Onshape client posts a message to the application extension with the available context. -<ul> -<li><strong>Note</strong>: This is limited to cases where the application extension is made active by the user; application extensions are not automatically loaded when a document is opened. Most UI customizations should be done when you register the application with Onshape, as those change the Onshape client automatically without needing to load the application extension first.</li> -</ul> -</li> -<li><strong>Content/material insertion</strong>: Request from the application extension to insert content into the Onshape document. For example, insert a part into a new or existing Part Studio, apply a material to a part, add a material to a material library, etc.</li> -</ul> -<h2 id="messages-from-onshape">Messages from Onshape</h2> -<p>The following examples can be initiated from the Onshape client:</p> -<ul> -<li><strong>User action notification</strong>: The Onshape client can notify an application extension when various user actions occur. For example, the Onshape client might notify when the user has made the application extension active or inactive (when the user clicks on document tabs). When an application extension is made inactive, it is moved off the edges of the browser, so it cannot be seen, but is still active, preserving its state.</li> -<li><strong>Printing</strong>: The Onshape client can notify an application extension when the user has chosen the <strong>Print</strong> command from the main Onshape document menu, enabling the application extension to perform a print operation.</li> -</ul> -<h2 id="security-considerations">Security Considerations</h2> -<p>To ensure security, an application extension must:</p> -<ul> -<li><strong>Parse for document, workspace, and element IDs</strong>: Parse for the <code>documentId</code>, <code>workspaceId</code>, and <code>elementId</code> that were passed as query parameters within the application extension’s iframe <code>src</code> URL. You must post these back in each <code>POST</code> message.</li> -<li><strong>Parse for the server</strong>: Parse for the <code>server</code> that was passed as a query parameter within the application extension’s iframe <code>src</code> URL. You must use this to validate messages received. -<ul> -<li>If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.</li> -</ul> -</li> -<li><strong>Not redirect to another base URL</strong>: The browser tells the Onshape client the origin base URL from which a <code>POST</code> message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframe <code>src</code> URL. It is <em>extremely important</em> to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframe <code>src</code> (i.e., <code>if (server === e.origin)</code>). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframe <code>src</code> server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored.</li> -<li><strong>Post a message on startup</strong>: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A <code>keepAlive</code> message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.</li> -</ul> -<p><code>POST</code> messages submitted by application extensions to Onshape will be ignored if any of the following are true:</p> -<ul> -<li>The documentId, workspaceId, or elementId are missing or not valid.</li> -<li>The message name is missing or not recognized.</li> -<li>The origin of the <code>POST</code> message does not match the original iframe <code>src</code> URL.</li> -</ul> -<h2 id="element-tab">Element Tab</h2> -<p>Messages may be sent and received by element tab application extensions.</p> -<p>The following messages can be <strong>sent</strong> by Element tab application extensions:</p> -<table> -<tr> -<td>messageName -(case sensitive)</td> -<td>other message properties?</td> -<td>comment</td> -</tr> -<tr> -<td>applicationInit</td> -<td>yes -<pre><code>notifyWhenSaveRequired: whether Onshape should send a notification to save pending changes during certain operations -(default is false) -</code></pre> -</td> -<td>Send once on application startup.</td> -</tr> -<tr> -<td>closeFlyoutsAndMenus</td> -<td>no</td> -<td>Send when a mouse click or other event happens in the application extension. Closes Onshape flyouts and dropdown menus.</td> -</tr> -<tr> -<td>closeSelectItemDialog</td> -<td>no</td> -<td>Closes the select item dialog.</td> -</tr> -<tr> -<td>connectionLost</td> -<td>no</td> -<td>Displays the standard Onshape connection lost message in a message bubble, forcing the user to either reload the document or return to the documents page.</td> -</tr> -<tr> -<td>errorReload</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Similar to the connectionLost message, but enables an application to specify the first part of the message, which will be used instead of "Onshape is not connected." The user must reload the document or return to the documents page.</td> -</tr> -<tr> -<td>finishedSaving</td> -<td>yes -<pre><code>messageId: the id sent in the corresponding 'saveChanges' message -</code></pre> -</td> -<td>Response to a 'saveChanges' message sent from Onshape. Should be sent after application has cleaned up any pending edits.</td> -</tr> -<tr> -<td>keepAlive</td> -<td>no</td> -<td>Send periodically while while the user is actively working to avoid the session from timing out.</td> -</tr> -<tr> -<td>saveAVersion</td> -<td>no</td> -<td>Send when the user types “Shift-S” in the application extension, the keyboard shortcut for save a version.</td> -</tr> -<tr> -<td>showKeyboardShortcutsHelp</td> -<td>no</td> -<td>Send when the user types “?” (Shift-? on most keyboards) in the application extension, the keyboard shortcut for the keyboard shortcuts help dialog.</td> -</tr> -<tr> -<td>showMessageBubble</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Send when you want to show a string in the blue message bubble at the top of the Onshape app.</td> -</tr> -<tr> -<td>startLoadingSpinner</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Send to start a large spinner in the middle of the browser window with your message underneath it.</td> -</tr> -<tr> -<td>stopLoadingSpinner</td> -<td>no</td> -<td>Send to stop the large spinner.</td> -</tr> -<tr> -<td>startWorkingSpinner</td> -<td>no</td> -<td>Send to start a small spinner in the middle bottom of the browser window.</td> -</tr> -<tr> -<td>stopWorkingSpinner</td> -<td>no</td> -<td>Send to stop the small spinner.</td> -</tr> -<tr> -<td>openSelectItemDialog</td> -<td>yes -<pre><code>dialogTitle: your dialog title -(default is no title), -selectBlobs: true or false -(default is false), -selectParts: true or false -(default is false), -selectPartStudios: true or false -(default is false), -selectAssemblies: true or false -(default is false), -selectMultiple: true or false -(default is false), -selectBlobMimeTypes: ‘comma-delimited string of blob mime types to show in dialog (e.g. “application/dwt,application/dwg”)’ -(default is an empty string) -showBrowseDocuments: true or false - controls whether ‘Other documents’ choice should be available -(default is true) -showStandardContent: true or false - controls whether ‘Standard content’ choice should be available -(default is false) -</code></pre> -</td> -<td>Send when your application wants to open a dialog in which the user will select one or multiple items - blobs, parts, part studios or assemblies. -</td> -</tr> -<tr> -<td>requestCameraProperties</td> -<td>yes -<pre><code>graphicsElementId: string , Element ID of the part studio or assembly -</code></pre> -</td> -<td> -Send to request camera properties of a specific part studio or assembly element. Note: The element should have been opened at least once in the current session. The messageName of the response is cameraProperties -</td> -</tr> -</table> -<p>The following messages can be <strong>received</strong> by Element tab application extensions:</p> -<table> -<tr> -<td>messageName -(case sensitive)</td> -<td>other message properties?</td> -<td>comment</td> -</tr> -<tr> -<td>show</td> -<td>no</td> -<td>Sent when an element tab application extension is shown (made active) within the Onshape client. This message is NOT sent when the element tab application extension is created.</td> -</tr> -<tr> -<td>hide</td> -<td>no</td> -<td>Sent when an element tab application extension is made inactive within the Onshape client. This message is NOT sent when an element tab application extension is deleted.</td> -</tr> -<tr> -<td>itemSelectedInSelectItemDialog</td> -<td>yes -<pre><code>documentId: id of selected item’s document, -workspaceId: id of selected item’s workspace, empty if versionId not empty, -versionId: id of selected item’s version, empty if workspaceId not empty, -elementId: id of element selected or containing the selected part, -elementName: name of element selected or containing the selected part, -elementType: type of element selected or containing the selected part - ‘partstudio’, ‘assembly’ or ‘blob’, -elementMicroversionId: microversion id of the element, -itemType: type of item selected: ‘part’,‘partStudio’ or ‘assembly’, -partName: name of part selected, empty if itemType is not ‘part’, -idTag: id of part, empty if no part selected -</code></pre> -</td> -<td>Sent when the user selects an item (blob, part, part studio or assembly) in the select item dialog that was opened due to an openSelectItemDialog message sent earlier. -When a part is not selected, the partXxx message properties will be empty strings.</td> -</tr> -<tr> -<td>print</td> -<td>no</td> -<td>Sent when the user chooses the Print command while the application is the active element. The application can choose to handle this as either a print or an export to a PDF or other format.</td> -</tr> -<tr> -<td>selectItemDialogClosed</td> -<td>no</td> -<td>Sent when the select item dialog closes, either because the user selected an item and selectMultiple is false, or the user changed the active element or the user closed the dialog with the "X" button.</td> -</tr> -<tr> -<td>startFirstViewCommand</td> -<td>yes -<pre><code>documentId: id of selected item’s document, -workspaceId: id of selected item’s workspace, empty if versionId not empty, -versionId: id of selected item’s version, empty if workspaceId not empty, -elementId: id of element selected or containing the selected part, -elementName: name of element selected or containing the selected part, -elementType: type of element selected or containing the selected part - ‘partstudio’, ‘assembly’ or ‘blob’, -elementMicroversionId: microversion id of the element, -itemType: type of item selected: ‘part’,‘partstudio’ or ‘assembly’, -partName: name of part selected, empty if itemType is not ‘part’, -idTag: id of part -</code></pre> -</td> -<td>Sent to a drawings application extension when the drawing is created with zero views. -<p>If other types of applications need a message posted to them with creation context, contact Onshape and we can discuss using this sort of message for your application also.</td></p> -</tr> -<tr> -<td>export</td> -<td>yes -<pre><code>fileExtension: the file extension of the export type the user chose - “.dwg”, “.dxf” are the types currently supported. -baseFileName: the base portion of the expected output file. This is currently set to “&lt;document name&gt; - &lt;element name&gt;” -</code></pre> -</td> -<td>Sent when the user chooses a command to export the contents of the application to a file.</td> -</tr> -<tr> -<td>cameraProperties</td> -<td>yes -<pre><code>graphicsElementId: string , Element ID of the part studio or assembly -isValid: boolean, Indicates if the properties are valid or not. false if element ID is invalid or element has not been open in the current session -projectionType: string, Denotes the projection method. Values are ‘orthographic’, ‘perspective’ . Empty string ‘’ if isValid is false -viewMatrix: 16 element numeric matrix with elements at index 13, 14, 15 corresponding to position of the camera -projectionMatrix: 16 element numeric matrix -verticalFieldOfView: number, 0 in case of orthographic projection -viewportHeight: number, eight of the viewport -viewportWidth: number, width of the viewport -</code></pre> -</td> -<td>Sent when application posts a requestCameraProperties message</td> -</tr> -<tr> -<td>takeFocus</td> -<td>no</td> -<td>Sent when the Onshape client sets focus on the content window of the element tab application extension.</td> -</tr> -<tr> -<td>saveChanges</td> -<td>yes -<pre><code>messageId: a unique identifier for this message. Should be passed back in the 'finishedSaving' message. -</code></pre> -</td> -<td>Sent if the application specified 'notifyWhenSaveRequired' in the 'applicationInit' message. Indicates that the application should cleanup any pending edits before an Onshape process continues (i.e. version save).</td> -</tr> -</table> -<h2 id="element-right-panel">Element Right Panel</h2> -<p>Most client messaging functionality had been limited to that occurring between the Onshape client and application elements (the <strong>Element tab</strong> location). Limited functionality in now also available for client messaging to work with application extensions in the <strong>Element right panel</strong> location.</p> -<p>Enabled messaging to Element right panel extensions includes the communication of selections that the user makes for the following application extension contexts:</p> -<ul> -<li>Part Studio</li> -<li>Assembly</li> -<li>Document</li> -</ul> -<p>All <a href="#security-considerations">Security Considerations</a> above apply to both Element tab and Element right panel extensions, with the following notes:</p> -<ul> -<li>Initial message from the application extension to the Onshape client, in the form of an <code>applicationInit</code> message (or one of any other messages supported by the element right panel extensions), is required to ensure the Onshape client does not send messages to the extension until it is ready.</li> -<li>Once a valid <code>applicationInit</code> message is received by the Onshape client, it will start sending messages with the <code>messageName</code> value <code>SELECTION</code> upon user selection interactions.</li> -<li>Prior to accepting <em>any</em> message from the Onshape client as secure, the <code>origin</code> attribute value included in incoming messages must be validated as equal to the original <code>server</code> query parameter value used to load the application extension.</li> -</ul> -<h2 id="code-snippets">Code Snippets</h2> -<h3 id="parse-query-parameters">Parse query parameters</h3> -<p>This JavaScript code parses the iframe <code>src</code> query parameters and uses them to post a message:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> <span style="color:#00a">var</span> documentId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> workspaceId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> elementId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> server; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Parse query parameters -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">var</span> queryParameters = <span style="color:#0aa">decodeURIComponent</span>(<span style="color:#0aa">window</span>.location.search.substr(<span style="color:#099">1</span>)); -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> queryParametersArray = queryParameters.split(<span style="color:#a50">&#39;&amp;&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">for</span> (<span style="color:#00a">var</span> i = <span style="color:#099">0</span>; i &lt; queryParametersArray.length; i++) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> parameterArray = queryParametersArray[i].split(<span style="color:#a50">&#39;=&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (parameterArray.length === <span style="color:#099">2</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">switch</span> (parameterArray[<span style="color:#099">0</span>]) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;documentId&#39;</span>: -</span></span><span style="display:flex;"><span> documentId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;workspaceId&#39;</span>: -</span></span><span style="display:flex;"><span> workspaceId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;elementId&#39;</span>: -</span></span><span style="display:flex;"><span> elementId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;server&#39;</span>: -</span></span><span style="display:flex;"><span> server = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Listen for clicks and post a message to the Onshape client -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#0aa">document</span>.getElementById(<span style="color:#a50">&#39;&lt;id of your topmost element&gt;&#39;</span>). -</span></span><span style="display:flex;"><span> addEventListener(<span style="color:#a50">&#39;click&#39;</span>, <span style="color:#00a">function</span>() { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> message = {documentId: documentId, -</span></span><span style="display:flex;"><span> workspaceId: workspaceId, -</span></span><span style="display:flex;"><span> elementId: elementId, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;closeFlyoutsAndMenus&#39;</span>}; -</span></span><span style="display:flex;"><span> <span style="color:#0aa">window</span>.parent.postMessage(message, <span style="color:#a50">&#39;*&#39;</span>); -</span></span><span style="display:flex;"><span> }, <span style="color:#00a">true</span>); -</span></span></code></pre></div><h3 id="create-a-message-object">Create a message object</h3> -<p>The message object posted to the Onshape client is of the form:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> documentId: documentId, -</span></span><span style="display:flex;"><span> workspaceId: workspaceId, -</span></span><span style="display:flex;"><span> elementId: elementId, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;&lt;message name&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// … other properties as needed for other message types … -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>} -</span></span></code></pre></div><p>The message data object posted to the application extension is of the form:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;&lt;message name&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// … other properties as needed for other message types … -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>} -</span></span></code></pre></div><p>The message will always have a <code>messageName</code> property.</p> -<h3 id="listen-for-messages">Listen for messages</h3> -<p>To listen for messages from the Onshape client:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// server is one of the iframe src query parameters - see above -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> handlePostMessage = <span style="color:#00a">function</span>(e) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Post message received in application extension.&#34;</span>); -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;e.origin = &#34;</span> + e.origin); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Verify the origin matches the server iframe src query parameter -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">if</span> (server === e.origin) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message safe and can be handled as it is from origin &#39;&#34;</span> -</span></span><span style="display:flex;"><span> + e.origin + -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;&#39;, which matches server query parameter &#39;&#34;</span> -</span></span><span style="display:flex;"><span> + server + <span style="color:#a50">&#34;&#39;.&#34;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (e.data &amp;&amp; e.data.messageName) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message name = &#39;&#34;</span> + e.data.messageName + <span style="color:#a50">&#34;&#39;&#34;</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message name not found. Ignoring message.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message NOT safe and should be ignored.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#0aa">window</span>.addEventListener(<span style="color:#a50">&#39;message&#39;</span>, handlePostMessage, <span style="color:#00a">false</span>); -</span></span></code></pre></div><h3 id="send-and-handle-messages">Send and handle messages</h3> -<p>The following is an example of how one might send an initialization message to, and handle post messages from, the Onshape client.</p> -<blockquote> -<p><em><strong>Note:</strong></em> Proper clean-up of event listeners is not included in the snippet</p> -</blockquote> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#00a">function</span> handlePostMessage(event) { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// ensure that the event data is from a legit source: -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">if</span>(theServerStringFromActionUrl !== event.origin) { -</span></span><span style="display:flex;"><span> console.error(<span style="color:#a50">&#39;origin of message is not legitimate&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// branch based on messageName attribute -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">switch</span>(event.data.messageName) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;SELECTION&#39;</span>: -</span></span><span style="display:flex;"><span> console.debug(<span style="color:#a50">&#39;SELECTION event data: %o&#39;</span>, event.data); -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">default</span>: -</span></span><span style="display:flex;"><span> console.debug(<span style="color:#a50">`</span><span style="color:#a50">${</span>event.data.messageName<span style="color:#a50">}</span><span style="color:#a50"> not handled`</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">window</span>.addEventListener(<span style="color:#a50">&#39;message&#39;</span>, handlePostMessage); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> initMessage = { -</span></span><span style="display:flex;"><span> documentId: theDocumentId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> workspaceId: theWorkspaceId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> elementId: theElementId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> messageName: <span style="color:#a50">&#39;applicationInit&#39;</span> <span style="color:#aaa;font-style:italic">// required -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>}; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">window</span>.parent.postMessage(initMessage, <span style="color:#a50">&#39;*&#39;</span>); -</span></span></code></pre></div><h3 id="right-panel-interaction-sequence">Right panel interaction sequence</h3> -<p>The sequence diagram below illustrates the interaction between an Element right panel application extension and the Onshape client:</p> -<pre tabindex="0"><code class="language-mermaid" data-lang="mermaid">%%{ -init: { -&#34;theme&#34;: &#34;default&#34;, -&#34;sequence&#34;: { -&#34;mirrorActors&#34;: false, -&#34;showSequenceNumbers&#34;: false, -&#34;width&#34;: 75, -&#34;height&#34;: 60, -&#34;actorMargin&#34;: 25, -&#34;messageFontSize&#34;: 13, -&#34;messageFontFamily&#34;: &#34;monospace&#34;, -&#34;messageFontWeight&#34;: 2 -} -} -}%% -sequenceDiagram -actor user -participant OSC AS Onshape Client -participant AE AS Application Extension -user-&gt;&gt;+OSC: start element right panel extension -Note right of user: via configured button -OSC-&gt;&gt;+AE: invoke action url (with query params) -AE-&gt;&gt;OSC: postMessage(messageName: &#39;applicationInit&#39;) -loop selection interactions -user-&gt;&gt;OSC: select -OSC-&gt;&gt;AE: postMessage(messageName: &#39;SELECTION&#39;) -end -user-&gt;&gt;OSC: stop element right panel extension -Note right of user: via configured button -deactivate AE -OSC-XAE: destroy -deactivate OSC -</code></pre><h3 id="right-panel-message-exchange">Right panel message exchange</h3> -<p>The following messages are exchanged for application extensions located in the element right panel and configured for Part Studio, Assembly, or Document contexts.</p> -<p>The first message with <code>messageName</code> attribute set to <code>applicationInit</code> is sent to the Onshape client by an application extension once it is loaded and ready to receive and process incoming messages:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> documentId: <span style="color:#a50">&#39;&lt;document id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> workspaceId: <span style="color:#a50">&#39;&lt;workspace id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> elementId: <span style="color:#a50">&#39;&lt;element id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;applicationInit&#39;</span> -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><p>The values <code>&lt;document id&gt;</code>, <code>&lt;workspace id&gt;</code>, <code>&lt;element id&gt;</code>, and <code>&lt;server id&gt;</code>:</p> -<ul> -<li>Are originally included as query parameters in the action URL used to request the content of the application extension</li> -<li>Must be included in messages sent to the Onshape client</li> -</ul> -<p>While initialization is the specific intent of the <code>applicationInit</code> message, other supported <code>messageName</code> attributes have the same initialization effect upon their first receipt by the Onshape client.</p> -<p>Next, as the user interacts with Onshape by selecting various parts of the model, messages with the <code>messageName</code> attribute set to <code>SELECTION</code> are sent to the application extension:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;SELECTION&#39;</span>, -</span></span><span style="display:flex;"><span> selections: [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> selectionType: <span style="color:#a50">&#39;ENTITY&#39;</span>, -</span></span><span style="display:flex;"><span> selectionId: <span style="color:#a50">&#39;KRiB&#39;</span>, -</span></span><span style="display:flex;"><span> entityType: <span style="color:#a50">&#39;FACE&#39;</span>, -</span></span><span style="display:flex;"><span> occurrencePath: [ -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;MfOieM8xKIDGHe37c&#39;</span> -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> workspaceMicroversionId: <span style="color:#a50">&#39;a781c53fbd1095e3462d2b70&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> selectionType: <span style="color:#a50">&#39;ENTITY&#39;</span>, -</span></span><span style="display:flex;"><span> selectionId: <span style="color:#a50">&#39;KRdC&#39;</span>, -</span></span><span style="display:flex;"><span> entityType: <span style="color:#a50">&#39;EDGE&#39;</span>, -</span></span><span style="display:flex;"><span> occurrencePath: [ -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;MfOieM8xKIDGHe37c&#39;</span> -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> workspaceMicroversionId: <span style="color:#a50">&#39;a781c53fbd1095e3462d2b70&#39;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> ] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h2 id="notes">Notes</h2> -<h3 id="keyboard-focus">Keyboard focus</h3> -<p>Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a <code>show</code> message from Onshape. Shortcut keys will work immediately when the application is shown.</p> -<h3 id="future-work">Future work</h3> -<ul> -<li>New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.</li> -<li>Mobile client support is unclear at this time.</li> -<li>Onshape is considering using promises to wrap <code>POST</code> messages, which would make the application extension&rsquo;s JavaScript simpler and enable chaining <code>POST</code>s with other operations. Promises would make some interactions with multiple responses difficult (e.g., when you open a dialog, like the Select Item dialog, and want to receive multiple <code>POST</code> messages back due to the user clicking on multiple items in the dialog).</li> -</ul>Docs: Structured Storagehttps://onshape-public.github.io/docs/app-dev/structuredstorage/Mon, 18 May 2020 20:40:16 -0400https://onshape-public.github.io/docs/app-dev/structuredstorage/ -<h2 id="sub-elements">Sub Elements</h2> -<p>Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements.</p> -<p>The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.</p> -<p>An application may need to perform multiple versionable actions in the course of performing a user-level action, and we want to allow the individual actions to be collected into a single action from the perspective of document history. We do this by providing support for creation of a private transaction and support for atomically committing the transaction to the document workspace as a single user-visible action.</p> -<p>Onshape does not assume any knowledge about the semantics of application deltas. All merging of deltas into a consolidated form is done by the application. Applications should typically send checkpoint state for a sub-element if many delta changes have been made since the last checkpoint.</p> -<p>Document content and changes are logically an array of bytes, but since they are transmitted through JSON, then are expected to be presented a Base-64 encoding of the array into string form.</p> -<p>We use some terminology in this document that is new.</p> -<ul> -<li> -<p><strong>changeId</strong> - an opaque identifier for the state of an application element. Each change to the application element results in a new changeId</p> -</li> -<li> -<p><strong>transaction</strong> - a private workspace within a document workspace for composing modifications to an application element. These changes are not visible to the user until committed.</p> -</li> -<li> -<p><strong>transaction commit</strong> - an operation that moves the changes performed within a transaction to the application element workspace as a single user-visible action.</p> -</li> -</ul> -<p><strong>Concurrent access by multiple users</strong></p> -<p>If the element is being concurrently accessed by multiple sessions, updates may encounter conflicts during update. If the application has a mechanism that ensures that all accesses to the element are mediated by a single process, as is done with our part studio and assemblies, this can be addressed directly by the application. However, if the application is not able to mediate access in this way, updates by one session may invalidate state held by another session. We address this by notifying updaters when an update cannot be directly applied because their state is out of date and allowing them to refresh their state before re-applying the change.</p> -<p>This policy of requiring the application have current state when posting updates could be overly conservative in some cases. Detecting conflict at the sub-element level might provide for better concurrent access performance, but there probably are cases where this fails, so it probably would need some level of application control.</p> -<h2 id="json-tree">JSON Tree</h2> -<p>In contrast with sub elements, JSON tree storage is a more managed data storage mechanism that Onshape itself can merge and diff. At the root of it, the data structure is a single JSON object per Application Element. The user submits incremental changes that are then applied by Onshape to the JSON tree. Onshape stores these &lsquo;diffs&rsquo; in a new microversion created as a result of the update request, or during a subsequent transaction commit request. When the user then performs a merge or restore operation, Onshape can sum and apply the requisite incremental changes. By storing diffs, Onshape provides to the user a storage mechanism that is more robust to race conditions, since multiple simultaneous edits can be optionally merged by Onshape. All of these qualities make JSON tree a preferred way to store application element data in an Onshape-native manner.</p> -<h3 id="json-tree-edit-semantics">JSON Tree Edit Semantics</h3> -<h5 id="btjedit-encoding">BTJEdit Encoding</h5> -<p>A JSON tree edit represents an incremental change to an application element&rsquo;s JSON tree. The edit is a <code>BTJEdit</code> class, which is encoded as one of the following:</p> -<ul> -<li>Deletion:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span> } -</span></span></code></pre></div><ul> -<li>Insertion:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span> : <span style="color:#a50">&#34;newValue&#34;</span> } -</span></span></code></pre></div><ul> -<li>Change:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span> : <span style="color:#a50">&#34;newValue&#34;</span> } -</span></span></code></pre></div><ul> -<li>Move:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditMove-3245&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;sourcePath&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;destinationPath&#34;</span> : <span style="color:#a50">&#34;path&#34;</span> } -</span></span></code></pre></div><ul> -<li>List (where edit1, edit2, etc. are zero or more edits.):</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditList-2707&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;edits&#34;</span> : [ <span style="color:#a50">&#34;edit1&#34;</span>, <span style="color:#a50">&#34;edit2&#34;</span>, <span style="color:#a50">&#34;...&#34;</span>] } -</span></span></code></pre></div><p>Within the above encoding, <code>newValue</code> is a stand in for any valid JSON, and <code>path</code> is a stand in for an object representing a path to the node at which to perform the edit.</p> -<h5 id="btjpath-encoding">BTJPath Encoding</h5> -<p>The BTJPath object describes a path through the JSON tree to a particular node, and is encoded as follows:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span> : <span style="color:#a50">&#34;startNode&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : [ <span style="color:#a50">&#34;pathElement1&#34;</span>, <span style="color:#a50">&#34;pathElement2&#34;</span>, <span style="color:#a50">&#34;...&#34;</span>] } -</span></span></code></pre></div><p>where startNode is a string that is either empty to specify the root node or a nodeId of a node in the tree. The pathElement is one of:</p> -<ul> -<li>Key:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span> : <span style="color:#a50">&#34;string&#34;</span> } -</span></span></code></pre></div><ul> -<li>Index:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span> : <span style="color:#a50">&#34;integer&#34;</span> } -</span></span></code></pre></div><p>In the insertion and move type edits the path elements can describe a path that doesn&rsquo;t currently exist. Onshape will generate the proper keys and values as needed to place the node value in the proper location.</p> -<h3 id="json-tree-examples">JSON Tree Examples</h3> -<p>Below are some examples that show the body required to perform the particular edit on a JSON tree.</p> -<h4 id="deletion-example">Deletion Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>and a delete edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}} -</span></span></code></pre></div><p>then the resulting JSON is the result of deleting the node specified by <code>path</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><h4 id="insert-example">Insert Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><p>and the insertion edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;insertedKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>then the resulting JSON is the result of inserting the node described by <code>value</code> at the node specified by <code>path</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;insertedKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><h4 id="change-example">Change Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>and the change edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><p>then the resulting JSON is the result of changing the node specified by <code>path</code> to the node described by <code>value</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><h4 id="move-example">Move Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;myOtherKey&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><p>and the move edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditMove-3245&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;sourcePath&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;destinationPath&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;keyCreatedFromMove&#34;</span>}]}} -</span></span></code></pre></div><p>then the resulting JSON is the result of moving the node from the specified <code>sourcePath</code> to the <code>destinationPath</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;keyCreatedFromMove&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><h4 id="list-example">List Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><p>and the list edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditList-2707&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;edits&#34;</span>: [ -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span>: <span style="color:#099">1</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span>: <span style="color:#099">2</span>}]}} -</span></span><span style="display:flex;"><span> ]} -</span></span></code></pre></div><p>then the resulting JSON is the result of applying all the given edits in order:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>]} -</span></span></code></pre></div><p>The intermediate steps were:</p> -<ol> -<li>Insertion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div></li> -<li>Change: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]} -</span></span></code></pre></div></li> -<li>List insertion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]} -</span></span></code></pre></div></li> -<li>List deletion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>]} -</span></span></code></pre></div></li> -</ol> -<p>All the examples above were tested and validated using the Python client <a href="https://github.com/onshape-public/onshape-clients/blob/next/python/test/test_app_element_json_tree.py">here</a>.</p>Docs: Webhookshttps://onshape-public.github.io/docs/app-dev/webhook/Mon, 18 May 2020 20:44:05 -0400https://onshape-public.github.io/docs/app-dev/webhook/ -<p>This page describes the Webhook APIs Onshape provides for working with notifications.</p> -<p>Notifications are delivered to an application as an HTTP <code>POST</code> with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message.</p> -<p>Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.</p> -<p>An application may register for notifications to a URL that uses either HTTP or HTTPS. If HTTPS is specified by the URL template, the notification server must supply a certificate that is signed by a certificate authority (CA) recognized by Onshape. Self-signed certificates (as well as certificates signed by unrecognized CAs) will be rejected, causing notification delivery to fail.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Sometimes, this page will use a stand-in string to represent these IDs (<code>000000000000000000000000</code>). Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="events">Events</h2> -<p>Each type of event that an application may receive notifications for has a unique identifier known as the event type. Event types are grouped into Event Groups. Each group shares specification requirements.</p> -<p>Event types are categorized into several different groups based on the dominant user resource of the event. The group that a given event is part of defines the required parameters needed in the registration process to identify the resource or group of resources to watch. For instance, if registering for an event in the <code>document</code> event group, the application must identify either a specific document&rsquo;s id or a specific company&rsquo;s id. If registered for a company, the event will be registered for all present and future documents owned by the company.</p> -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>You can see the full list of available events in the Glassworks API Explorer. Expand the <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">createWebhook</a> endpoint, then click <strong>Callbacks</strong>.</p> -<img src="https://onshape-public.github.io/images/webhooks-callbacks.png" alt="callbacks in the Glassworks Webhook > createWebhook > Callback page" width=80%> -</blockquote> -<h3 id="application-group">Application Group</h3> -<p>Monitor changes to applications.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.user.lifecycle.updateappsettings</code> - Occurs when user application settings are modified</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li><code>clientId</code> - Must be specified in the registration body</li> -<li><code>event</code> - Must be set to <code>onshape.user.lifecycle.updateappsettings</code></li> -<li><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></li> -<li><code>url</code> - Must be provided to receive the webhook notifications</li> -</ul> -<pre tabindex="0"><code>{ -&#34;clientId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.user.lifecycle.updateappsettings&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="document-group">Document Group</h3> -<p>Monitor various aspects of document changes.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.model.lifecycle.changed</code> - Occurs when a change to a model is made</li> -<li><code>onshape.model.translation.complete</code> - Occurs when a translation request is complete</li> -<li><code>onshape.model.lifecycle.metadata</code> - Occurs when Part or element metadata is modified</li> -<li><code>onshape.model.lifecycle.createversion</code> - Occurs when a new version of a document is created</li> -<li><code>onshape.model.lifecycle.createworkspace</code> - Occurs when a new workspace is created</li> -<li><code>onshape.model.lifecycle.createelement</code> - Occurs when a new element is created</li> -<li><code>onshape.model.lifecycle.deleteelement</code> - Occurs when an element is deleted</li> -<li><code>onshape.document.lifecycle.statechange</code> - Occurs when a document changes state</li> -<li><code>onshape.model.lifecycle.changed.externalreferences</code> - Occurs when an external reference changes</li> -<li><code>onshape.document.lifecycle.created</code> - Occurs when a document is created</li> -<li><code>onshape.revision.created</code> - Occurs when a revision is created</li> -<li><code>onshape.comment.create</code> - Occurs when a comment is created in a document</li> -<li><code>onshape.comment.update</code> - Occurs when a comment is updated in a document</li> -<li><code>onshape.comment.delete</code> - Occurs when a comment is deleted in a document</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li> -<p><code>documentId</code> OR <code>companyId</code> must be specified in the registration body</p> -<ul> -<li>Only <code>documentId</code> is valid for the <code>onshape.document.lifecycle.statechange</code></li> -</ul> -</li> -<li> -<p><code>event</code> - Must be set to one of the supported event types listed above</p> -<ul> -<li>May be set to <code>false</code> if the application is always listening to webhook notifications and <code>companyId</code> is specified.</li> -<li>If <code>false</code>, unregister the webhook when it is no longer needed.</li> -</ul> -</li> -<li> -<p><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></p> -</li> -<li> -<p><code>url</code> - Must be provided to receive the webhook notifications</p> -</li> -</ul> -<pre tabindex="0"><code>{ -&#34;documentId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.user.lifecycle.updateappsettings&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="workflow-group">Workflow Group</h3> -<p>Monitor release management actions.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.workflow.transition</code> - Occurs when a revision or release package transitions through workflow states</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li><code>companyId</code> - Must be specified in the registration body</li> -<li><code>event</code> - Must be set to <code>onshape.workflow.transition</code> -<ul> -<li>May be set to <code>false</code> if the application is always listening to webhook notifications.</li> -<li>If <code>false</code>, unregister the webhook when it is no longer needed.</li> -</ul> -</li> -<li><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></li> -<li><code>url</code> - Must be provided to receive the webhook notifications</li> -</ul> -<pre tabindex="0"><code>{ -&#34;companyId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.workflow.transition&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="lifecycle-group">Lifecycle Group</h3> -<p>Monitor webhook changes. You do not need to register for these events; they are sent automatically when a webhook for another event type is registered, unregistered, or pinged.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>webhook.register</code> - Occurs in response to a notification registration API call</li> -<li><code>webhook.unregister</code> - Occurs in response to a notification deregistation API call</li> -<li><code>webhook.ping</code> - Occurs either: -<ul> -<li>In response to a request by an application to call the <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/pingWebhook">pingWebook</a> endpoint.</li> -<li>As a post-registration validation initiated by Onshape</li> -</ul> -</li> -</ul> -<h2 id="example-notifications">Example Notifications</h2> -<p><strong>webhook.register</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.register&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>webhook.ping</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.ping&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.model.lifecycle.changed</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.model.lifecycle.changed&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.document.lifecycle.statechange</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.document.lifecycle.statechange&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentState&#34;</span>: <span style="color:#a50">&#34;TRASH&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Possible values of <code>documentState</code> are:</p> -<ul> -<li><code>ACTIVE</code> - Document is in a normal, usable state.</li> -<li><code>TRASH</code> - Document has been moved to the trash; user can move document back to <code>ACTIVE</code> state.</li> -<li><code>DELETED</code> - Document has been deleted; user cannot access document.</li> -</ul> -<p><strong>onshape.user.lifecycle.updateappsettings</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.user.lifecycle.updateappsettings&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;userId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;clientId&#34;</span>:<span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.model.translation.complete</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.model.translation.complete&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;userId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;translationId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.comment.create</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.comment.create&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;commentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h2 id="endpoints">Endpoints</h2> -<p>Webhook notifications allow an application to register to receive notifications of certain events that occur within the Onshape environment. To receive a notification, an application must expose an endpoint that Onshape can call.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhooks">Webhook/getWebhooks</a> -<pre tabindex="0"><code> curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks?user={uid}&amp;offset=0&amp;limit=20&#39; \ --H &#39;aAccept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">Webhook/createWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;events&#34;: [ -&#34;eventType&#34; // See the [Events](#events) section above for valid event types. -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: true | false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -//Other parameters may be required. See the [Events](#events) section above. -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhook">Webhook/getWebhook</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/webhookId&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/updateWebhook">Webhook/updateWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/webhookId&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;id&#34;: &#34;webhookId&#34;, -&#34;options&#34;: { -&#34;collapseEvents&#34;: true | false -} -}&#39; -</code></pre><ul> -<li>Note that the webhook <code>id</code> must be sent in both the URL and the request body.</li> -</ul> -</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/unregisterWebhook">Webhook/unregisterWebhook</a> -<pre tabindex="0"><code> curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/{webhookId}?blockNotification=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/pingWebhook">Webhook/pingWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/{webhookId}/ping&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="create-a-webhook">Create a webhook</h3> -<p>An application registers for event notification by:</p> -<ol> -<li>Making a REST call to the Onshape web service</li> -<li>Providing a URL to notify</li> -<li>Providing the required parameters for the event types to be registered</li> -</ol> -<p>If the registration request is well-formed, the registration API call returns information about the registration, including a unique <code>id</code> string that identifies the webhook registration. This corresponds to the <code>webhookId</code> field in other endpoints. No de-duplication of notification registrations is performed by the API. Each registration call will yield a new <code>registrationId</code>, even if the parameters are identical to those passed in a prior call.</p> -<p>Shortly after an application calls the notification registration API, Onshape will make make an asynchronous trial notification call to the URL generated from the URL template with an event type of <code>webhook.register</code> to test if the application notification server is accessible. If the trial notification delivery fails to return an HTTP <code>200</code> status code, the notification registration is cancelled. The trial notification is usually delivered after the notification registration has been received by the application. However, variations in network delays may result in the trial notification occurring before the response is received and processed by the application, so the notification handler should be ready to process notifications before the registration call is made.</p> -<p>In this example, we use a webhook to send information from Onshape to another server. You need a URL for Onshape to send notifications to, and a way to view the messages sent with those notifications.</p> -<ol> -<li>Open an Onshape document, or create a new one.</li> -<li>In this example, we want to receive a notification from Onshape any time a new version is created in the specified document. For this, we’ll use <code>onshape.model.lifecycle.createversion</code> as our <code>event</code>.</li> -<li>The event type requires one parameter. We’ll use our <code>documentId</code> for this field (shown as <code>000000000000000000000000</code> in the example below).</li> -<li>All event types require specifying <code>true</code> or <code>false</code> for the <code>options.collapseEvents</code> field. In this case, set the field to <code>false</code>.</li> -<li>Next, we need the URL to send the notification to. You must provide your own URL to receive notifications here.</li> -<li>Confirm your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">createWebhook</a> call looks like this (substitute your own authorization credentials, document ID, and URL), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;documentId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.model.lifecycle.createversion&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -}&#39; -</code></pre><ol start="7"> -<li>In your application, confirm that you received the <code>webhook.register</code> event from Onshape.</li> -<li>In Onshape, create a new version in your document.</li> -<li>In your application, confirm that you received the <code>onshape.model.lifecycle.createversion</code> event from Onshape. Make note of the <code>id</code> in the response; use this as your <code>webhookId</code> in subsequent examples.</li> -</ol> -<h3 id="get-webhook-info">Get webhook info</h3> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhook">getWebhook</a> call. substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><ol start="3"> -<li>Confirm that the <code>event</code> in the response is <code>onshape.model.lifecycle.createversion</code>.</li> -</ol> -<h3 id="update-a-webhook">Update a webhook</h3> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>. Note that in the same response, the webhook <code>description</code> is <code>null</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/updateWebhook">updateWebhook</a> call. In this example, ww update the webhook&rsquo;s <code>description</code>. Substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below in both the URL and request body). Then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;id&#34;: &#34;000000000000000000000000&#34;, -&#34;description&#34;: &#34;Send a notification each time a document version is created.&#34;, -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -} -}&#39; -</code></pre><ol start="3"> -<li>Confirm in the response that the webhook <code>description</code> is set to <code>Send a notification each time a document version is created.</code></li> -</ol> -<h3 id="delete-a-webhook">Delete a webhook</h3> -<p>When an application no longer needs to be notified of changes specified by a particular notification registration, it should normally deregister the notification request. Deregistration is performed by making an HTTP that specifies the hook to deregister. Onshape will attempt to call the deregistered hook with an event type of <code>webhook.unregister</code> as validation that the deregistration is complete. If the application does not deregister the webhook, Onshape will continue delivering notifications until the the application either returns an error in response to a notification for the webhook or fails to respond at all for an extended period of time.</p> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/deleteWebhook">deleteWebhook</a> call. substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS=&#39; \ -</code></pre><ol start="3"> -<li>In your application, confirm that you received the <code>webhook.unregister</code> event from Onshape.</li> -<li>In Onshape, create a new version in your document.</li> -<li>In your application, confirm that no new events have been received.</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">Onshape Help: Webhooks</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">API Explorer: Webhooks</a></li> -<li><a href="https://github.com/onshape-public/onshape-clients/blob/master/python/test/test_webhooks.py#L126">Sample Code: Python Webhooks</a></li> -</ul> \ No newline at end of file +App Development onhttps://onshape-public.github.io/docs/app-dev/Recent content in App Development onHugoen-usMon, 18 May 2020 20:44:05 -0400Extensionshttps://onshape-public.github.io/docs/app-dev/extensions/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/extensions/This page provides information for some of the more common options for embedding a third-party application into the Onshape interface. Onshape provides many options for embedding commands in various menus, fly-out panels, and elements. In this example, you will embed a custom web page inside a document’s right side fly-out panel. This interface will receive information from Onshape and push information from the panel back to Onshape, providing a complete, bi-directional integration scenario.Client Messaginghttps://onshape-public.github.io/docs/app-dev/clientmessaging/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/clientmessaging/Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message. +Onshape Client Messaging examples can be split into those that are initiated from the application extension and those that are initiated from the Onshape client. +Messages from the Extension These Client Messaging examples can be initiated from the application extension: +Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.Structured Storagehttps://onshape-public.github.io/docs/app-dev/structuredstorage/Mon, 18 May 2020 20:40:16 -0400https://onshape-public.github.io/docs/app-dev/structuredstorage/Sub Elements Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements. +The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.Webhookshttps://onshape-public.github.io/docs/app-dev/webhook/Mon, 18 May 2020 20:44:05 -0400https://onshape-public.github.io/docs/app-dev/webhook/This page describes the Webhook APIs Onshape provides for working with notifications. +Notifications are delivered to an application as an HTTP POST with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message. +Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs. \ No newline at end of file diff --git a/docs/app-dev/structuredstorage/index.html b/docs/app-dev/structuredstorage/index.html index 18ac360..df6e79d 100644 --- a/docs/app-dev/structuredstorage/index.html +++ b/docs/app-dev/structuredstorage/index.html @@ -1,9 +1,8 @@ -Structured Storage |

    Structured Storage

    Sub Elements

    Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements.

    The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.

    An application may need to perform multiple versionable actions in the course of performing a user-level action, and we want to allow the individual actions to be collected into a single action from the perspective of document history. We do this by providing support for creation of a private transaction and support for atomically committing the transaction to the document workspace as a single user-visible action.

    Onshape does not assume any knowledge about the semantics of application deltas. All merging of deltas into a consolidated form is done by the application. Applications should typically send checkpoint state for a sub-element if many delta changes have been made since the last checkpoint.

    Document content and changes are logically an array of bytes, but since they are transmitted through JSON, then are expected to be presented a Base-64 encoding of the array into string form.

    We use some terminology in this document that is new.

    • changeId - an opaque identifier for the state of an application element. Each change to the application element results in a new changeId

    • transaction - a private workspace within a document workspace for composing modifications to an application element. These changes are not visible to the user until committed.

    • transaction commit - an operation that moves the changes performed within a transaction to the application element workspace as a single user-visible action.

    Concurrent access by multiple users

    If the element is being concurrently accessed by multiple sessions, updates may encounter conflicts during update. If the application has a mechanism that ensures that all accesses to the element are mediated by a single process, as is done with our part studio and assemblies, this can be addressed directly by the application. However, if the application is not able to mediate access in this way, updates by one session may invalidate state held by another session. We address this by notifying updaters when an update cannot be directly applied because their state is out of date and allowing them to refresh their state before re-applying the change.

    This policy of requiring the application have current state when posting updates could be overly conservative in some cases. Detecting conflict at the sub-element level might provide for better concurrent access performance, but there probably are cases where this fails, so it probably would need some level of application control.

    JSON Tree

    In contrast with sub elements, JSON tree storage is a more managed data storage mechanism that Onshape itself can merge and diff. At the root of it, the data structure is a single JSON object per Application Element. The user submits incremental changes that are then applied by Onshape to the JSON tree. Onshape stores these ‘diffs’ in a new microversion created as a result of the update request, or during a subsequent transaction commit request. When the user then performs a merge or restore operation, Onshape can sum and apply the requisite incremental changes. By storing diffs, Onshape provides to the user a storage mechanism that is more robust to race conditions, since multiple simultaneous edits can be optionally merged by Onshape. All of these qualities make JSON tree a preferred way to store application element data in an Onshape-native manner.

    JSON Tree Edit Semantics

    BTJEdit Encoding

    A JSON tree edit represents an incremental change to an application element’s JSON tree. The edit is a BTJEdit class, which is encoded as one of the following:

    • Deletion:
    { "btType" : "BTJEditDelete-1992", "path" : "path" }
    +Structured Storage | 

    Structured Storage

    Sub Elements

    Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements.

    The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.

    An application may need to perform multiple versionable actions in the course of performing a user-level action, and we want to allow the individual actions to be collected into a single action from the perspective of document history. We do this by providing support for creation of a private transaction and support for atomically committing the transaction to the document workspace as a single user-visible action.

    Onshape does not assume any knowledge about the semantics of application deltas. All merging of deltas into a consolidated form is done by the application. Applications should typically send checkpoint state for a sub-element if many delta changes have been made since the last checkpoint.

    Document content and changes are logically an array of bytes, but since they are transmitted through JSON, then are expected to be presented a Base-64 encoding of the array into string form.

    We use some terminology in this document that is new.

    • changeId - an opaque identifier for the state of an application element. Each change to the application element results in a new changeId

    • transaction - a private workspace within a document workspace for composing modifications to an application element. These changes are not visible to the user until committed.

    • transaction commit - an operation that moves the changes performed within a transaction to the application element workspace as a single user-visible action.

    Concurrent access by multiple users

    If the element is being concurrently accessed by multiple sessions, updates may encounter conflicts during update. If the application has a mechanism that ensures that all accesses to the element are mediated by a single process, as is done with our part studio and assemblies, this can be addressed directly by the application. However, if the application is not able to mediate access in this way, updates by one session may invalidate state held by another session. We address this by notifying updaters when an update cannot be directly applied because their state is out of date and allowing them to refresh their state before re-applying the change.

    This policy of requiring the application have current state when posting updates could be overly conservative in some cases. Detecting conflict at the sub-element level might provide for better concurrent access performance, but there probably are cases where this fails, so it probably would need some level of application control.

    JSON Tree

    In contrast with sub elements, JSON tree storage is a more managed data storage mechanism that Onshape itself can merge and diff. At the root of it, the data structure is a single JSON object per Application Element. The user submits incremental changes that are then applied by Onshape to the JSON tree. Onshape stores these ‘diffs’ in a new microversion created as a result of the update request, or during a subsequent transaction commit request. When the user then performs a merge or restore operation, Onshape can sum and apply the requisite incremental changes. By storing diffs, Onshape provides to the user a storage mechanism that is more robust to race conditions, since multiple simultaneous edits can be optionally merged by Onshape. All of these qualities make JSON tree a preferred way to store application element data in an Onshape-native manner.

    JSON Tree Edit Semantics

    BTJEdit Encoding

    A JSON tree edit represents an incremental change to an application element’s JSON tree. The edit is a BTJEdit class, which is encoded as one of the following:

    • Deletion:
    { "btType" : "BTJEditDelete-1992", "path" : "path" }
     
    • Insertion:
    { "btType" : "BTJEditInsert-2523", "path" : "path", "value" : "newValue" }
     
    • Change:
    { "btType" : "BTJEditChange-2636", "path" : "path", "value" : "newValue" }
     
    • Move:
    { "btType" : "BTJEditMove-3245", "sourcePath" : "path", "destinationPath" : "path" }
    @@ -51,4 +50,4 @@
     
  • Change:
       {"myKey": ["firstValue", "secondValue"]}
     
  • List insertion:
       {"myKey": ["firstValue", "myBetterSecondValue", "secondValue"]}
     
  • List deletion:
       {"myKey": ["firstValue", "myBetterSecondValue"]}
    -
  • All the examples above were tested and validated using the Python client here.

    \ No newline at end of file +

    All the examples above were tested and validated using the Python client here.

    \ No newline at end of file diff --git a/docs/app-dev/webhook/index.html b/docs/app-dev/webhook/index.html index 8a97a12..1183594 100644 --- a/docs/app-dev/webhook/index.html +++ b/docs/app-dev/webhook/index.html @@ -1,12 +1,12 @@ -Webhooks | Webhooks |

    Webhooks

    This page describes the Webhook APIs Onshape provides for working with notifications.

    Notifications are delivered to an application as an HTTP POST with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message.

    Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.

    An application may register for notifications to a URL that uses either HTTP or HTTPS. If HTTPS is specified by the URL template, the notification server must supply a certificate that is signed by a certificate authority (CA) recognized by Onshape. Self-signed certificates (as well as certificates signed by unrecognized CAs) will be rejected, causing notification delivery to fail.

    📘 Notes

    • This page provides sample code as curls. See the curl documentation for more information.
    • All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.
    • This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as DWVEM Please see API Guide: API Intro for information on what these IDs mean and how to obtain them from your documents. Sometimes, this page will use a stand-in string to represent these IDs (000000000000000000000000). Never include the curly braces ({}) in your API calls.
    • For Enterprise accounts, replace cad in all Onshape URLs with your company domain. +Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.">

      Webhooks

      This page describes the Webhook APIs Onshape provides for working with notifications.

      Notifications are delivered to an application as an HTTP POST with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message.

      Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.

      An application may register for notifications to a URL that uses either HTTP or HTTPS. If HTTPS is specified by the URL template, the notification server must supply a certificate that is signed by a certificate authority (CA) recognized by Onshape. Self-signed certificates (as well as certificates signed by unrecognized CAs) will be rejected, causing notification delivery to fail.

      📘 Notes

      • This page provides sample code as curls. See the curl documentation for more information.
      • All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.
      • This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as DWVEM Please see API Guide: API Intro for information on what these IDs mean and how to obtain them from your documents. Sometimes, this page will use a stand-in string to represent these IDs (000000000000000000000000). Never include the curly braces ({}) in your API calls.
      • For Enterprise accounts, replace cad in all Onshape URLs with your company domain. https://cad.onshape.com > https://companyName.onshape.com

      Events

      Each type of event that an application may receive notifications for has a unique identifier known as the event type. Event types are grouped into Event Groups. Each group shares specification requirements.

      Event types are categorized into several different groups based on the dominant user resource of the event. The group that a given event is part of defines the required parameters needed in the registration process to identify the resource or group of resources to watch. For instance, if registering for an event in the document event group, the application must identify either a specific document’s id or a specific company’s id. If registered for a company, the event will be registered for all present and future documents owned by the company.

      📘 Note

      You can see the full list of available events in the Glassworks API Explorer. Expand the createWebhook endpoint, then click Callbacks.

      callbacks in the Glassworks Webhook > createWebhook > Callback page

      Application Group

      Monitor changes to applications.

      Supported Event Types

      • onshape.user.lifecycle.updateappsettings - Occurs when user application settings are modified

      Registration Requirements

      • clientId - Must be specified in the registration body
      • event - Must be set to onshape.user.lifecycle.updateappsettings
      • options.collapseEvents - Must be set to true or false
      • url - Must be provided to receive the webhook notifications
      {
         "clientId": "000000000000000000000000",
         "events": [
      @@ -194,4 +194,4 @@
           'https://cad.onshape.com/api/v6/webhooks/000000000000000000000000' \
           -H 'Accept: application/json;charset=UTF-8; qs=0.09' \
           -H 'Authorization: Basic CREDENTIALS=' \
      -
      1. In your application, confirm that you received the webhook.unregister event from Onshape.
      2. In Onshape, create a new version in your document.
      3. In your application, confirm that no new events have been received.

      Additional Resources

      \ No newline at end of file +
      1. In your application, confirm that you received the webhook.unregister event from Onshape.
      2. In Onshape, create a new version in your document.
      3. In your application, confirm that no new events have been received.

      Additional Resources

    \ No newline at end of file diff --git a/docs/app-store/checklist/index.html b/docs/app-store/checklist/index.html index fc2c664..7cf2492 100644 --- a/docs/app-store/checklist/index.html +++ b/docs/app-store/checklist/index.html @@ -1,5 +1,5 @@ -Launch Checklist |

    Launch Checklist

    This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion.

    1. Understand quality expectations

    These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the Quality Considerations page, and reach out to the Developer Relations team with any questions.

    2. Sign in to your developer account

    Sign in to your developer account at dev-portal.onshape.com, and ensure your developer account details are accurate. Contact our API Support team if you need assistance.

    3. Authenticate your app

    Please refer to the OAuth documentation for information on authenticating your app with OAuth2.

    4. Build your app

    While building your app, use the resources in our Onshape Developer Documentation, including this API Guide and our API Explorer. We recommend familiarizing yourself with the following pages:

    5. Prepare your store entry

    Prepare the descriptions, promotional graphics, screenshots, and videos you’ll add to your store entry. Make sure you include a link to if required. Watch this video for more details.

    See the video below for a walkthrough:

    OAuth app creation video

    6. Run beta tests

    During the beta period, try to enlist at least 5 active testers to get feedback before making your app available to the general public.

    1. To find beta testers, contact our Developer Relations team, and recruit via the Onshape forum.
    2. To give beta users early visibility, first create a team, then ensure your app is shared with that team in the Developer Portal. See the Create a Team in Onshape video for a walkthrough.

    7. Determine your app’s price

    Once you’ve determined your monetization model, set up your price, billing, and other details. Billing should be tested, and to do so a staging environment is available. See the Billing API page for more details.

    8. Sign and return the developer agreement

    Email to the Developer Relations team to obtain yours.

    9. Submit your app for final testing

    Once you’ve returned the developer agreement, you can submit your app to the Developer Relations team for final testing. This is a comprehensive functionality and design test. During this testing period (expect up to a week, depending on complexity), changes to code are prohibited unless requested. At the conclusion of the test, you will receive one of the following notifications from our Developer Relations team:

    • Approved for release
    • Approved for release with feedback
    • Changes required before another round of testing

    10. Integrate your support systems

    Whether you use Zendesk, Jira, or email support, we’ll help you determine and set up this integration. Contact the Developer Relations team to explore these options. This is the channel we will use to test your app and provide feedback.

    11. Connect via Slack

    Connecting directly with our Support, Tech, and Sales teams has proven to be valuable to app developers. This dedicated channel is simple to implement if you already have a paid Slack account. If not (or if you want to use the free version of Slack), we can add members of your team as guests to our account. Please contact Aaron Magnin to establish this connection.

    12. Final check and publish

    First, double-check you’ve done everything on this list. Now you’re ready to publish your app to the production channel! Send an email detailing when you’d like this to happen to the Developer Relations team.

    13. Promote your app

    Start promoting your app with the Onshape badge and by presenting it to our internal teams in one of the following ways:

    • To the Onshape Tech and Sales teams in a small meeting (~1 hour, Wednesdays at noon Eastern Time)
    • To the entire Onshape organization in a company-wide meeting (~5-10 minutes, Thursdays at 11am Eastern Time).

    14. Encourage reviews from users

    The value of reviews is not to be underestimated. Reviews give users an opportunity to provide feedback, and can also signal to others that your app is worth investigating.

    15. Maintain your app

    Continually fix stability and performance issues. Improving the user experience will result in more engaged users, higher ratings, and in turn, more success.

    Failure to respond to customer tickets in a reasonable time will lead to the removal of your app from the Onshape App Store.

    16. Increase engagement and retention

    Aim to increase user engagement, retain and grow your audience, and earn more revenue by:

    • Encouraging repeat visits with a nurture stream and training materials
    • Integrating more features from user requests
    • Interacting with and understanding your audience via the Onshape forum, social media, etc.

    17. Address app security

    At some point, a prospect or user will enquire about your app’s security controls. To address this, we recommend that you understand SOC 2 Compliance requirements, and consider filling out the Consensus Assessment Initiative Questionnaire (CAIQ). Onshape/PTC cannot and will not attest to your compliance. More on SOC Compliance can be found at the following links:

    \ No newline at end of file +Launch Checklist |

    Launch Checklist

    This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion.

    1. Understand quality expectations

    These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the Quality Considerations page, and reach out to the Developer Relations team with any questions.

    2. Sign in to your developer account

    Sign in to your developer account at dev-portal.onshape.com, and ensure your developer account details are accurate. Contact our API Support team if you need assistance.

    3. Authenticate your app

    Please refer to the OAuth documentation for information on authenticating your app with OAuth2.

    4. Build your app

    While building your app, use the resources in our Onshape Developer Documentation, including this API Guide and our API Explorer. We recommend familiarizing yourself with the following pages:

    5. Prepare your store entry

    Prepare the descriptions, promotional graphics, screenshots, and videos you’ll add to your store entry. Make sure you include a link to if required. Watch this video for more details.

    See the video below for a walkthrough:

    OAuth app creation video

    6. Run beta tests

    During the beta period, try to enlist at least 5 active testers to get feedback before making your app available to the general public.

    1. To find beta testers, contact our Developer Relations team, and recruit via the Onshape forum.
    2. To give beta users early visibility, first create a team, then ensure your app is shared with that team in the Developer Portal. See the Create a Team in Onshape video for a walkthrough.

    7. Determine your app’s price

    Once you’ve determined your monetization model, set up your price, billing, and other details. Billing should be tested, and to do so a staging environment is available. See the Billing API page for more details.

    8. Sign and return the developer agreement

    Email to the Developer Relations team to obtain yours.

    9. Submit your app for final testing

    Once you’ve returned the developer agreement, you can submit your app to the Developer Relations team for final testing. This is a comprehensive functionality and design test. During this testing period (expect up to a week, depending on complexity), changes to code are prohibited unless requested. At the conclusion of the test, you will receive one of the following notifications from our Developer Relations team:

    • Approved for release
    • Approved for release with feedback
    • Changes required before another round of testing

    10. Integrate your support systems

    Whether you use Zendesk, Jira, or email support, we’ll help you determine and set up this integration. Contact the Developer Relations team to explore these options. This is the channel we will use to test your app and provide feedback.

    11. Connect via Slack

    Connecting directly with our Support, Tech, and Sales teams has proven to be valuable to app developers. This dedicated channel is simple to implement if you already have a paid Slack account. If not (or if you want to use the free version of Slack), we can add members of your team as guests to our account. Please contact Aaron Magnin to establish this connection.

    12. Final check and publish

    First, double-check you’ve done everything on this list. Now you’re ready to publish your app to the production channel! Send an email detailing when you’d like this to happen to the Developer Relations team.

    13. Promote your app

    Start promoting your app with the Onshape badge and by presenting it to our internal teams in one of the following ways:

    • To the Onshape Tech and Sales teams in a small meeting (~1 hour, Wednesdays at noon Eastern Time)
    • To the entire Onshape organization in a company-wide meeting (~5-10 minutes, Thursdays at 11am Eastern Time).

    14. Encourage reviews from users

    The value of reviews is not to be underestimated. Reviews give users an opportunity to provide feedback, and can also signal to others that your app is worth investigating.

    15. Maintain your app

    Continually fix stability and performance issues. Improving the user experience will result in more engaged users, higher ratings, and in turn, more success.

    Failure to respond to customer tickets in a reasonable time will lead to the removal of your app from the Onshape App Store.

    16. Increase engagement and retention

    Aim to increase user engagement, retain and grow your audience, and earn more revenue by:

    • Encouraging repeat visits with a nurture stream and training materials
    • Integrating more features from user requests
    • Interacting with and understanding your audience via the Onshape forum, social media, etc.

    17. Address app security

    At some point, a prospect or user will enquire about your app’s security controls. To address this, we recommend that you understand SOC 2 Compliance requirements, and consider filling out the Consensus Assessment Initiative Questionnaire (CAIQ). Onshape/PTC cannot and will not attest to your compliance. More on SOC Compliance can be found at the following links:

    \ No newline at end of file diff --git a/docs/app-store/index.html b/docs/app-store/index.html index 13e041c..bbcf5d5 100644 --- a/docs/app-store/index.html +++ b/docs/app-store/index.html @@ -1,2 +1,7 @@ -Onshape App Store |

    Onshape App Store

    Onshape makes applications available through the Onshape App Store. The App Store is actively promoted to users, making it easy for users to find, purchase, and use third-party applications.

    To submit an application to the Onshape App Store, complete the Launch Checklist, which provides a step-by-step guide that you can follow to make your app public.

    End User Experience

    Users can browse the Onshape App Store and install third-party applications:

    Onshape App Store video

    When a user registers an application, there are several possible integration points to expose the application within the Onshape user experience. At this time, applications that provide a UI in an Onshape tab will be added to the + button menu on the Onshape tab bar. See the Extensions page for more information on supported app locations and contexts.

    image

    Mobile Clients

    Onshape expects to enable applications tabs in iOS and Android environments in the future.

    Feedback

    Your comments, questions, and concerns are always welcome!

    \ No newline at end of file +Onshape App Store |

    Onshape App Store

    Onshape makes applications available through the Onshape App Store. The App Store is actively promoted to users, making it easy for users to find, purchase, and use third-party applications.

    To submit an application to the Onshape App Store, complete the Launch Checklist, which provides a step-by-step guide that you can follow to make your app public.

    End User Experience

    Users can browse the Onshape App Store and install third-party applications:

    Onshape App Store video

    When a user registers an application, there are several possible integration points to expose the application within the Onshape user experience. At this time, applications that provide a UI in an Onshape tab will be added to the + button menu on the Onshape tab bar. See the Extensions page for more information on supported app locations and contexts.

    image

    Mobile Clients

    Onshape expects to enable applications tabs in iOS and Android environments in the future.

    Feedback

    Your comments, questions, and concerns are always welcome!

    \ No newline at end of file diff --git a/docs/app-store/index.xml b/docs/app-store/index.xml index 2fb8752..07e548d 100644 --- a/docs/app-store/index.xml +++ b/docs/app-store/index.xml @@ -1,303 +1,6 @@ -– Onshape App Storehttps://onshape-public.github.io/docs/app-store/Recent content in Onshape App Store onHugo -- gohugo.ioen-usDocs: Launch Checklisthttps://onshape-public.github.io/docs/app-store/checklist/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/checklist/ -<p>This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion.</p> -<h3 id="1-understand-quality-expectations">1. Understand quality expectations</h3> -<p>These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the <a href="https://onshape-public.github.io/docs/app-store/quality">Quality Considerations</a> page, and reach out to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> with any questions.</p> -<h3 id="2-sign-in-to-your-developer-account">2. Sign in to your developer account</h3> -<p>Sign in to your developer account at <a href="https://dev-portal.onshape.com">dev-portal.onshape.com</a>, and ensure your developer account details are accurate. Contact our <a href="mailto:api-support@onshape.com">API Support team</a> if you need assistance.</p> -<h3 id="3-authenticate-your-app">3. Authenticate your app</h3> -<p>Please refer to the <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth documentation</a> for information on authenticating your app with OAuth2.</p> -<h3 id="4-build-your-app">4. Build your app</h3> -<p>While building your app, use the resources in our Onshape Developer Documentation, including this API Guide and our API Explorer. We recommend familiarizing yourself with the following pages:</p> -<ul> -<li><a href="https://onshape-public.github.io/docs/api-intro/">Introduction to the Onshape REST API</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/architecture">Onshape Architecture</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/">Onshape App Development</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/extensions">Extensions</a> <!-- Susan move the videos to their pages --></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/clientmessaging">Client Messaging</a></li> -<li><a href="https://onshape-public.github.io/docs/app-store">Onshape App Store</a></li> -</ul> -<h3 id="5-prepare-your-store-entry">5. Prepare your store entry</h3> -<p>Prepare the descriptions, promotional graphics, screenshots, and videos you&rsquo;ll add to your store entry. Make sure you include a link to if required. Watch this video for more details.</p> -<p>See the video below for a walkthrough:</p> -<p><a href="https://onshape.wistia.com/medias/tuhuzfi7we"><img src="https://onshape-public.github.io/images/AppStoreEntryVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></p> -<h3 id="6-run-beta-tests">6. Run beta tests</h3> -<p>During the beta period, try to enlist at least 5 active testers to get feedback before making your app available to the general public.</p> -<ol> -<li>To find beta testers, contact our <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a>, and recruit via the <a href="https://forum.onshape.com/categories/developer-community">Onshape forum</a>.</li> -<li>To give beta users early visibility, first <a href="https://cad.onshape.com/help/Content/teams-enterprise.htm">create a team</a>, then ensure your app is shared with that team in the <a href="https://dev-portal.onshape.com">Developer Portal</a>. See the <a href="https://onshape.wistia.com/medias/5t1dwkspfo">Create a Team in Onshape video</a> for a walkthrough.</li> -</ol> -<h3 id="7-determine-your-apps-price">7. Determine your app&rsquo;s price</h3> -<p>Once you&rsquo;ve determined your monetization model, set up your price, billing, and other details. Billing should be tested, and to do so a staging environment is available. See the <a href="https://onshape-public.github.io/docs/api-adv/billing">Billing API</a> page for more details.</p> -<h3 id="8-sign-and-return-the-developer-agreement">8. Sign and return the developer agreement</h3> -<p>Email to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> to obtain yours.</p> -<h3 id="9-submit-your-app-for-final-testing">9. Submit your app for final testing</h3> -<p>Once you&rsquo;ve returned the developer agreement, you can submit your app to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> for final testing. <a href="https://onshape-public.github.io/docs/app-store/testingguidelines">This is a comprehensive functionality and design test.</a> During this testing period (expect up to a week, depending on complexity), changes to code are prohibited unless requested. At the conclusion of the test, you will receive one of the following notifications from our Developer Relations team:</p> -<ul> -<li>Approved for release</li> -<li>Approved for release with feedback</li> -<li>Changes required before another round of testing</li> -</ul> -<h3 id="10-integrate-your-support-systems">10. Integrate your support systems</h3> -<p>Whether you use Zendesk, Jira, or email support, we’ll help you determine and set up this integration. Contact the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> to explore these options. This is the channel we will use to test your app and provide feedback.</p> -<h3 id="11-connect-via-slack">11. Connect via Slack</h3> -<p>Connecting directly with our Support, Tech, and Sales teams has proven to be valuable to app developers. This dedicated channel is simple to implement if you already have a paid Slack account. If not (or if you want to use the free version of Slack), we can add members of your team as guests to our account. Please contact <a href="mailto:amagnin@ptc.com">Aaron Magnin</a> to establish this connection.</p> -<h3 id="12-final-check-and-publish">12. Final check and publish</h3> -<p>First, double-check you&rsquo;ve done everything on this list. Now you&rsquo;re ready to publish your app to the production channel! Send an email detailing <strong>when</strong> you’d like this to happen to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a>.</p> -<h3 id="13-promote-your-app">13. Promote your app</h3> -<p>Start promoting your app with the <a href="https://www.ptc.com/en/brand-guide/logos/onshape">Onshape badge</a> and by presenting it to our internal teams in one of the following ways:</p> -<ul> -<li>To the Onshape Tech and Sales teams in a small meeting (~1 hour, Wednesdays at noon Eastern Time)</li> -<li>To the entire Onshape organization in a company-wide meeting (~5-10 minutes, Thursdays at 11am Eastern Time).</li> -</ul> -<h3 id="14-encourage-reviews-from-users">14. Encourage reviews from users</h3> -<p>The value of reviews is not to be underestimated. Reviews give users an opportunity to provide feedback, and can also signal to others that your app is worth investigating.</p> -<h3 id="15-maintain-your-app">15. Maintain your app</h3> -<p>Continually fix stability and performance issues. Improving the user experience will result in more engaged users, higher ratings, and in turn, more success.</p> -<blockquote> -<blockquote> -<p>Failure to respond to customer tickets in a reasonable time will lead to the removal of your app from the Onshape App Store.</p> -</blockquote> -</blockquote> -<h3 id="16-increase-engagement-and-retention">16. Increase engagement and retention</h3> -<p>Aim to increase user engagement, retain and grow your audience, and earn more revenue by:</p> -<ul> -<li>Encouraging repeat visits with a nurture stream and training materials</li> -<li>Integrating more features from user requests</li> -<li>Interacting with and understanding your audience via the <a href="https://forum.onshape.com/categories/developer-community">Onshape forum</a>, social media, etc.</li> -</ul> -<h3 id="17-address-app-security">17. Address app security</h3> -<p>At some point, a prospect or user will enquire about your app&rsquo;s security controls. To address this, we recommend that you understand SOC 2 Compliance requirements, and consider filling out the <a href="https://www.google.com/url?q=https://cloudsecurityalliance.org/artifacts/consensus-assessments-initiative-questionnaire-v3-1/&amp;sa=D&amp;source=editors&amp;ust=1686683388460627&amp;usg=AOvVaw2xq8zlODs3a7W2Y3jighnr">Consensus Assessment Initiative Questionnaire</a> (CAIQ). Onshape/PTC cannot and will not attest to your compliance. More on SOC Compliance can be found at the following links:</p> -<ul> -<li><a href="https://us.aicpa.org/interestareas/frc/assuranceadvisoryservices/aicpasoc2report">AICPA.org</a></li> -<li><a href="https://en.wikipedia.org/wiki/System_and_Organization_Controls">Wikipedia: System and Organization Controls</a></li> -</ul>Docs: Testing Guidelineshttps://onshape-public.github.io/docs/app-store/testingguidelines/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/testingguidelines/ -<p>The purpose of this document is to help you get your application and App Store entry ready for QA testing.</p> -<h2 id="application-release-workflow-arw">Application Release Workflow (ARW)</h2> -<p>Each application submitted to the Onshape App Store goes through a series of stage-gates:</p> -<ol> -<li>Starting state: <code>Ok to deploy to limited visibility on Production</code> (Beta testing)</li> -<li><code>Ok to make Public</code></li> -<li>Goal state: <code>Application is Public</code></li> -</ol> -<p>To advance to the next stage, your application must pass testing, and your App Store entry must pass review.</p> -<h2 id="kick-off-testing">Kick Off Testing</h2> -<p>While completing the <a href="https://onshape-public.github.io/docs/app-store/checklist">Launch Checklist</a>, you will need to use Jira to request testing and release for your application. You can initiate the following tasks from Jira:</p> -<ul> -<li><code>Request application testing</code>: This puts your application in the testing queue. We will note when testing has started (<code>in progress</code>) and when concluded, the ticket will be closed. The outcome will include notes and links to any issues generated (<code>tickets</code>). This phase may include as many iterations as needed to get your application ready.</li> -<li><code>Request public (general) authorization</code>: We will note when testing has started (<code>in progress</code>), and this request will trigger a review of your app store entry and any outstanding bugs. Note there is no implied testing of your application, simply a review of outstanding issues (<code>tickets</code>) and of the App Store entry. Success at this stage will advance the Application Release Workflow (ARW), and you can request public release.</li> -<li><code>Request public (general) release</code>: This request states that you have coordinated with the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> and the Onshape Marketing team<!--How do they get in touch with the Marketing team? Slack?-->, and agreement has been reached that the app is ready for launch. Congratulations!</li> -</ul> -<h2 id="testing-protocol">Testing Protocol</h2> -<p><em>Applications</em> are first tested against the checklist in <a href="#addendum-a">Addendum A</a>. <em>Production App Store</em> entries are then performed against the checklist in <a href="#addendum-b">Addendum B</a>.</p> -<p>Results will be viewable in your Onshape support system (i.e., Zendesk, Jira). The result of each test will be one of:</p> -<ul> -<li><code>Pass</code>: -<ul> -<li>No action needed.</li> -<li>No notification issued. <!-- How do they know it passed? Does it just show up in the app store? --></li> -</ul> -</li> -<li><code>Enhancement</code>: Suggestions we believe would make the application better. -<ul> -<li>Will NOT prevent the application from being turned on for public access.</li> -</ul> -</li> -<li><code>Bug (low priority)</code>: Slight deviations from the criteria that have low end user impact. -<ul> -<li>Will NOT prevent the application being turned on for public access.</li> -<li>No stipulated time-frame for resolution.</li> -</ul> -</li> -<li><code>Bug (medium priority)</code>: Material deviations from the criteria that are noticeable to the end-user. Represents a minor problem that requires a work-around. -<ul> -<li>Will NOT prevent the application from being turned on for public access.</li> -<li>Must be fixed within 30 days.</li> -</ul> -</li> -<li><code>Bug (high priority)</code>: Significant deviation from the criteria. -<ul> -<li>WILL prevent the application from being turned on for public access.</li> -</ul> -</li> -<li><code>Bug (MUST FIX)</code>: Significant deviation from protocol or security violation. -<ul> -<li>WILL prevent the application from being turned on for public access.</li> -<li>If the application is already public, it may be temporarily suspended from the App Store.</li> -</ul> -</li> -</ul> -<h2 id="testing-notes">Testing Notes</h2> -<ul> -<li>Testing may be requested at any time.</li> -<li>Testing is done on a first-come basis.</li> -<li>When testing is complete (pass or fail), you go to the back of the queue.</li> -</ul> -<h2 id="addendum-a">Addendum A</h2> -<p><font size="5">Application Test Criteria</font></p> -<ul> -<li>The application must use the Onshape OAUTH mechanism</li> -<li>The OAUTH must be against the correct stack</li> -<li>To be promoted to the Production stack, and hosted service must be on a monitored production server with worldwide 24/7 availability.</li> -<li>The application should not generate any avoidable console (browser) errors</li> -<li>The application should should provide one or more of the following options. The user should not have to leave the registration workflow to complete a pre-requisite. -<ul> -<li>Sign in using the Onshape ID (account created silently on first use)</li> -<li>Sign in with partner product account credentials</li> -<li>Create a new partner account</li> -</ul> -</li> -<li>The application must be capable of managing/displaying documents in excess of 20. The application must display reasonable performance when reading documents, workspaces, elements, and parts. At scale, an account may have thousands of documents, many with multiple workspaces and each with multiple elements. Suggested strategies include: -<ul> -<li>Using a <code>Next</code> button to load the next 20 documents</li> -<li>Using infinite scroll (loading the next 20 if the scrollbar reaches the bottom of the dialog)</li> -<li>Displaying the most recently-opened documents first</li> -<li>Displaying a counter of documents/workspaces/elements read</li> -<li>Using progressive loading</li> -</ul> -</li> -<li>The application should correctly list valid documents when <code>per document app access</code> is turned on.</li> -<li>The application should correctly handle selection of versions.</li> -<li>The application should correctly handle selection of workspaces (branches).</li> -<li>The application should correctly handle/display elements that are: -<ul> -<li>Part Studios that contain nothing</li> -<li>Assemblies that contain nothing</li> -<li>Part Studios that contain only surfaces</li> -<li>Part Studios that contain only wire data (e.g., helices)</li> -</ul> -</li> -<li>The application should appropriately handle revocation of a grant.</li> -</ul> -<h2 id="addendum-b">Addendum B</h2> -<p><font size="5">App Store Testing Criteria</font></p> -<ul> -<li>The application should have a descriptive name</li> -<li>The application summary should be accurate</li> -<li>The redirect URLS should be valid</li> -<li>The iframe URL should be valid</li> -<li>The <code>Grant</code> (permissions) request should be no more than is needed</li> -<li>The <code>Application Type</code> should be correctly set</li> -<li>Team visibility should be set (optional)</li> -<li>The category should be appropriate</li> -<li>The application description should be accurate</li> -<li>The Sign-In URL should be valid</li> -<li>The pricing summary should be accurate -<ul> -<li>i.e., trials should not be listed as <code>Free</code>; <code>Free for xx days and then $xx/month</code> is more accurate.</li> -</ul> -</li> -<li>All pay plans should have accurate descriptions.</li> -<li>The support URL should point to a resource for help (the resource should NOT be an FAQ page, unless that page also contains one of the other options): -<ul> -<li>Support ticketing system (e.g., Zendesk, Jira, etc.)</li> -<li>Web page with a telephone number</li> -<li>Web page with an email address</li> -<li>Forum</li> -</ul> -</li> -<li>The EULA link should point to an English Language EULA.</li> -</ul>Docs: Quality Considerationshttps://onshape-public.github.io/docs/app-store/quality/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/quality/ -<h2 id="core-app-quality">Core App Quality</h2> -<p>Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention.</p> -<p>This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria.</p> -<p>Before publishing your apps, test them against these criteria to ensure that they function well. Your testing should go well beyond what&rsquo;s described here; the purpose of this page is to specify the essential quality characteristics all apps should display, so that you can cover them in your test plans.</p> -<h2 id="functionality">Functionality</h2> -<p>These criteria ensure that your app provides the expected functional behavior, with the appropriate level of permissions.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Permissions</td> -<td>The app requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.</td> -</tr> -</tbody> -</table> -<h2 id="compatibility-performance-and-stability">Compatibility, Performance, and Stability</h2> -<p>These criteria ensure that apps provide the compatibility, performance, stability, and responsiveness expected by users.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Stability</td> -<td>The app does not crash, force close, freeze, or otherwise function abnormally.</td> -</tr> -<tr> -<td>Performance</td> -<td>The app loads quickly or provides onscreen feedback to the user (e.g., a progress indicator or similar cue) if the app takes longer than two (2) seconds to load.</td> -</tr> -<tr> -<td>Visual quality</td> -<td>The app displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</td> -</tr> -</tbody> -</table> -<h2 id="security">Security</h2> -<p>These criteria ensure that apps handle user data and personal information safely.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Data</td> -<td>All private data is stored in the app&rsquo;s internal storage. </br> All data from external storage is verified before being accessed. </br> No personal or sensitive user data is logged to the system or app-specific log.</td> -</tr> -<tr> -<td>Networking</td> -<td>All network traffic is sent over SSL.</td> -</tr> -</tbody> -</table> -<h2 id="onshape-app-store">Onshape App Store</h2> -<p>These criteria ensure that your apps are ready to publish on Onshape App Store.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>App Details page</td> -<td>The app’s feature graphic follows guidelines such as: </br>- The app listing includes a high-quality feature graphic.</br>- The feature graphic does not resemble an advertisement.</br>- The app’s screenshots or videos do not represent the content and experience of your app in a misleading way.</td> -</tr> -<tr> -<td>User support</td> -<td>User-reported bugs are addressed if they are reproducible.</td> -</tr> -</tbody> -</table> -<h2 id="test-procedures">Test procedures</h2> -<p>These test procedures help you discover various types of quality issues in your app. You can combine the tests or integrate groups of tests together in your own test plans. See the sections above for references that associate criteria with these test procedures.</p> -<table> -<thead> -<tr> -<th>Type</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Core suite</td> -<td>Navigate to all parts of the app: all screens, dialogs, settings, and all user flows.</td> -</tr> -<tr> -<td>Security</td> -<td>- Review all data stored in external storage. </br>- Review how data loaded from external storage is handled and processed.</td> -</tr> -</tbody> -</table> \ No newline at end of file +Onshape App Store onhttps://onshape-public.github.io/docs/app-store/Recent content in Onshape App Store onHugoen-usLaunch Checklisthttps://onshape-public.github.io/docs/app-store/checklist/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/checklist/This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion. +1. Understand quality expectations These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the Quality Considerations page, and reach out to the Developer Relations team with any questions.Testing Guidelineshttps://onshape-public.github.io/docs/app-store/testingguidelines/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/testingguidelines/The purpose of this document is to help you get your application and App Store entry ready for QA testing. +Application Release Workflow (ARW) Each application submitted to the Onshape App Store goes through a series of stage-gates: +Starting state: Ok to deploy to limited visibility on Production (Beta testing) Ok to make Public Goal state: Application is Public To advance to the next stage, your application must pass testing, and your App Store entry must pass review.Quality Considerationshttps://onshape-public.github.io/docs/app-store/quality/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/quality/Core App Quality Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention. +This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria. +Before publishing your apps, test them against these criteria to ensure that they function well. \ No newline at end of file diff --git a/docs/app-store/quality/index.html b/docs/app-store/quality/index.html index ead8b5b..3193496 100644 --- a/docs/app-store/quality/index.html +++ b/docs/app-store/quality/index.html @@ -1,9 +1,9 @@ -Quality Considerations | Quality Considerations |

    Quality Considerations

    Core App Quality

    Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention.

    This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria.

    Before publishing your apps, test them against these criteria to ensure that they function well. Your testing should go well beyond what’s described here; the purpose of this page is to specify the essential quality characteristics all apps should display, so that you can cover them in your test plans.

    Functionality

    These criteria ensure that your app provides the expected functional behavior, with the appropriate level of permissions.

    AreaDescription
    PermissionsThe app requests only the absolute minimum permissions that it needs to support core functionality.

    Compatibility, Performance, and Stability

    These criteria ensure that apps provide the compatibility, performance, stability, and responsiveness expected by users.

    AreaDescription
    StabilityThe app does not crash, force close, freeze, or otherwise function abnormally.
    PerformanceThe app loads quickly or provides onscreen feedback to the user (e.g., a progress indicator or similar cue) if the app takes longer than two (2) seconds to load.
    Visual qualityThe app displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.

    Security

    These criteria ensure that apps handle user data and personal information safely.

    AreaDescription
    DataAll private data is stored in the app’s internal storage.
    All data from external storage is verified before being accessed.
    No personal or sensitive user data is logged to the system or app-specific log.
    NetworkingAll network traffic is sent over SSL.

    Onshape App Store

    These criteria ensure that your apps are ready to publish on Onshape App Store.

    AreaDescription
    App Details pageThe app’s feature graphic follows guidelines such as:
    - The app listing includes a high-quality feature graphic.
    - The feature graphic does not resemble an advertisement.
    - The app’s screenshots or videos do not represent the content and experience of your app in a misleading way.
    User supportUser-reported bugs are addressed if they are reproducible.

    Test procedures

    These test procedures help you discover various types of quality issues in your app. You can combine the tests or integrate groups of tests together in your own test plans. See the sections above for references that associate criteria with these test procedures.

    TypeDescription
    Core suiteNavigate to all parts of the app: all screens, dialogs, settings, and all user flows.
    Security- Review all data stored in external storage.
    - Review how data loaded from external storage is handled and processed.
    \ No newline at end of file +Before publishing your apps, test them against these criteria to ensure that they function well.">

    Quality Considerations

    Core App Quality

    Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention.

    This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria.

    Before publishing your apps, test them against these criteria to ensure that they function well. Your testing should go well beyond what’s described here; the purpose of this page is to specify the essential quality characteristics all apps should display, so that you can cover them in your test plans.

    Functionality

    These criteria ensure that your app provides the expected functional behavior, with the appropriate level of permissions.

    AreaDescription
    PermissionsThe app requests only the absolute minimum permissions that it needs to support core functionality.

    Compatibility, Performance, and Stability

    These criteria ensure that apps provide the compatibility, performance, stability, and responsiveness expected by users.

    AreaDescription
    StabilityThe app does not crash, force close, freeze, or otherwise function abnormally.
    PerformanceThe app loads quickly or provides onscreen feedback to the user (e.g., a progress indicator or similar cue) if the app takes longer than two (2) seconds to load.
    Visual qualityThe app displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.

    Security

    These criteria ensure that apps handle user data and personal information safely.

    AreaDescription
    DataAll private data is stored in the app’s internal storage.
    All data from external storage is verified before being accessed.
    No personal or sensitive user data is logged to the system or app-specific log.
    NetworkingAll network traffic is sent over SSL.

    Onshape App Store

    These criteria ensure that your apps are ready to publish on Onshape App Store.

    AreaDescription
    App Details pageThe app’s feature graphic follows guidelines such as:
    - The app listing includes a high-quality feature graphic.
    - The feature graphic does not resemble an advertisement.
    - The app’s screenshots or videos do not represent the content and experience of your app in a misleading way.
    User supportUser-reported bugs are addressed if they are reproducible.

    Test procedures

    These test procedures help you discover various types of quality issues in your app. You can combine the tests or integrate groups of tests together in your own test plans. See the sections above for references that associate criteria with these test procedures.

    TypeDescription
    Core suiteNavigate to all parts of the app: all screens, dialogs, settings, and all user flows.
    Security- Review all data stored in external storage.
    - Review how data loaded from external storage is handled and processed.
    \ No newline at end of file diff --git a/docs/app-store/testingguidelines/index.html b/docs/app-store/testingguidelines/index.html index d323fc5..5a64232 100644 --- a/docs/app-store/testingguidelines/index.html +++ b/docs/app-store/testingguidelines/index.html @@ -1,10 +1,9 @@ -Testing Guidelines | Testing Guidelines |

    Testing Guidelines

    The purpose of this document is to help you get your application and App Store entry ready for QA testing.

    Application Release Workflow (ARW)

    Each application submitted to the Onshape App Store goes through a series of stage-gates:

    1. Starting state: Ok to deploy to limited visibility on Production (Beta testing)
    2. Ok to make Public
    3. Goal state: Application is Public

    To advance to the next stage, your application must pass testing, and your App Store entry must pass review.

    Kick Off Testing

    While completing the Launch Checklist, you will need to use Jira to request testing and release for your application. You can initiate the following tasks from Jira:

    • Request application testing: This puts your application in the testing queue. We will note when testing has started (in progress) and when concluded, the ticket will be closed. The outcome will include notes and links to any issues generated (tickets). This phase may include as many iterations as needed to get your application ready.
    • Request public (general) authorization: We will note when testing has started (in progress), and this request will trigger a review of your app store entry and any outstanding bugs. Note there is no implied testing of your application, simply a review of outstanding issues (tickets) and of the App Store entry. Success at this stage will advance the Application Release Workflow (ARW), and you can request public release.
    • Request public (general) release: This request states that you have coordinated with the Developer Relations team and the Onshape Marketing team, and agreement has been reached that the app is ready for launch. Congratulations!

    Testing Protocol

    Applications are first tested against the checklist in Addendum A. Production App Store entries are then performed against the checklist in Addendum B.

    Results will be viewable in your Onshape support system (i.e., Zendesk, Jira). The result of each test will be one of:

    • Pass:
      • No action needed.
      • No notification issued.
    • Enhancement: Suggestions we believe would make the application better.
      • Will NOT prevent the application from being turned on for public access.
    • Bug (low priority): Slight deviations from the criteria that have low end user impact.
      • Will NOT prevent the application being turned on for public access.
      • No stipulated time-frame for resolution.
    • Bug (medium priority): Material deviations from the criteria that are noticeable to the end-user. Represents a minor problem that requires a work-around.
      • Will NOT prevent the application from being turned on for public access.
      • Must be fixed within 30 days.
    • Bug (high priority): Significant deviation from the criteria.
      • WILL prevent the application from being turned on for public access.
    • Bug (MUST FIX): Significant deviation from protocol or security violation.
      • WILL prevent the application from being turned on for public access.
      • If the application is already public, it may be temporarily suspended from the App Store.

    Testing Notes

    • Testing may be requested at any time.
    • Testing is done on a first-come basis.
    • When testing is complete (pass or fail), you go to the back of the queue.

    Addendum A

    Application Test Criteria

    • The application must use the Onshape OAUTH mechanism
    • The OAUTH must be against the correct stack
    • To be promoted to the Production stack, and hosted service must be on a monitored production server with worldwide 24/7 availability.
    • The application should not generate any avoidable console (browser) errors
    • The application should should provide one or more of the following options. The user should not have to leave the registration workflow to complete a pre-requisite.
      • Sign in using the Onshape ID (account created silently on first use)
      • Sign in with partner product account credentials
      • Create a new partner account
    • The application must be capable of managing/displaying documents in excess of 20. The application must display reasonable performance when reading documents, workspaces, elements, and parts. At scale, an account may have thousands of documents, many with multiple workspaces and each with multiple elements. Suggested strategies include:
      • Using a Next button to load the next 20 documents
      • Using infinite scroll (loading the next 20 if the scrollbar reaches the bottom of the dialog)
      • Displaying the most recently-opened documents first
      • Displaying a counter of documents/workspaces/elements read
      • Using progressive loading
    • The application should correctly list valid documents when per document app access is turned on.
    • The application should correctly handle selection of versions.
    • The application should correctly handle selection of workspaces (branches).
    • The application should correctly handle/display elements that are:
      • Part Studios that contain nothing
      • Assemblies that contain nothing
      • Part Studios that contain only surfaces
      • Part Studios that contain only wire data (e.g., helices)
    • The application should appropriately handle revocation of a grant.

    Addendum B

    App Store Testing Criteria

    • The application should have a descriptive name
    • The application summary should be accurate
    • The redirect URLS should be valid
    • The iframe URL should be valid
    • The Grant (permissions) request should be no more than is needed
    • The Application Type should be correctly set
    • Team visibility should be set (optional)
    • The category should be appropriate
    • The application description should be accurate
    • The Sign-In URL should be valid
    • The pricing summary should be accurate
      • i.e., trials should not be listed as Free; Free for xx days and then $xx/month is more accurate.
    • All pay plans should have accurate descriptions.
    • The support URL should point to a resource for help (the resource should NOT be an FAQ page, unless that page also contains one of the other options):
      • Support ticketing system (e.g., Zendesk, Jira, etc.)
      • Web page with a telephone number
      • Web page with an email address
      • Forum
    • The EULA link should point to an English Language EULA.
    \ No newline at end of file +Starting state: Ok to deploy to limited visibility on Production (Beta testing) Ok to make Public Goal state: Application is Public To advance to the next stage, your application must pass testing, and your App Store entry must pass review.">

    Testing Guidelines

    The purpose of this document is to help you get your application and App Store entry ready for QA testing.

    Application Release Workflow (ARW)

    Each application submitted to the Onshape App Store goes through a series of stage-gates:

    1. Starting state: Ok to deploy to limited visibility on Production (Beta testing)
    2. Ok to make Public
    3. Goal state: Application is Public

    To advance to the next stage, your application must pass testing, and your App Store entry must pass review.

    Kick Off Testing

    While completing the Launch Checklist, you will need to use Jira to request testing and release for your application. You can initiate the following tasks from Jira:

    • Request application testing: This puts your application in the testing queue. We will note when testing has started (in progress) and when concluded, the ticket will be closed. The outcome will include notes and links to any issues generated (tickets). This phase may include as many iterations as needed to get your application ready.
    • Request public (general) authorization: We will note when testing has started (in progress), and this request will trigger a review of your app store entry and any outstanding bugs. Note there is no implied testing of your application, simply a review of outstanding issues (tickets) and of the App Store entry. Success at this stage will advance the Application Release Workflow (ARW), and you can request public release.
    • Request public (general) release: This request states that you have coordinated with the Developer Relations team and the Onshape Marketing team, and agreement has been reached that the app is ready for launch. Congratulations!

    Testing Protocol

    Applications are first tested against the checklist in Addendum A. Production App Store entries are then performed against the checklist in Addendum B.

    Results will be viewable in your Onshape support system (i.e., Zendesk, Jira). The result of each test will be one of:

    • Pass:
      • No action needed.
      • No notification issued.
    • Enhancement: Suggestions we believe would make the application better.
      • Will NOT prevent the application from being turned on for public access.
    • Bug (low priority): Slight deviations from the criteria that have low end user impact.
      • Will NOT prevent the application being turned on for public access.
      • No stipulated time-frame for resolution.
    • Bug (medium priority): Material deviations from the criteria that are noticeable to the end-user. Represents a minor problem that requires a work-around.
      • Will NOT prevent the application from being turned on for public access.
      • Must be fixed within 30 days.
    • Bug (high priority): Significant deviation from the criteria.
      • WILL prevent the application from being turned on for public access.
    • Bug (MUST FIX): Significant deviation from protocol or security violation.
      • WILL prevent the application from being turned on for public access.
      • If the application is already public, it may be temporarily suspended from the App Store.

    Testing Notes

    • Testing may be requested at any time.
    • Testing is done on a first-come basis.
    • When testing is complete (pass or fail), you go to the back of the queue.

    Addendum A

    Application Test Criteria

    • The application must use the Onshape OAUTH mechanism
    • The OAUTH must be against the correct stack
    • To be promoted to the Production stack, and hosted service must be on a monitored production server with worldwide 24/7 availability.
    • The application should not generate any avoidable console (browser) errors
    • The application should should provide one or more of the following options. The user should not have to leave the registration workflow to complete a pre-requisite.
      • Sign in using the Onshape ID (account created silently on first use)
      • Sign in with partner product account credentials
      • Create a new partner account
    • The application must be capable of managing/displaying documents in excess of 20. The application must display reasonable performance when reading documents, workspaces, elements, and parts. At scale, an account may have thousands of documents, many with multiple workspaces and each with multiple elements. Suggested strategies include:
      • Using a Next button to load the next 20 documents
      • Using infinite scroll (loading the next 20 if the scrollbar reaches the bottom of the dialog)
      • Displaying the most recently-opened documents first
      • Displaying a counter of documents/workspaces/elements read
      • Using progressive loading
    • The application should correctly list valid documents when per document app access is turned on.
    • The application should correctly handle selection of versions.
    • The application should correctly handle selection of workspaces (branches).
    • The application should correctly handle/display elements that are:
      • Part Studios that contain nothing
      • Assemblies that contain nothing
      • Part Studios that contain only surfaces
      • Part Studios that contain only wire data (e.g., helices)
    • The application should appropriately handle revocation of a grant.

    Addendum B

    App Store Testing Criteria

    • The application should have a descriptive name
    • The application summary should be accurate
    • The redirect URLS should be valid
    • The iframe URL should be valid
    • The Grant (permissions) request should be no more than is needed
    • The Application Type should be correctly set
    • Team visibility should be set (optional)
    • The category should be appropriate
    • The application description should be accurate
    • The Sign-In URL should be valid
    • The pricing summary should be accurate
      • i.e., trials should not be listed as Free; Free for xx days and then $xx/month is more accurate.
    • All pay plans should have accurate descriptions.
    • The support URL should point to a resource for help (the resource should NOT be an FAQ page, unless that page also contains one of the other options):
      • Support ticketing system (e.g., Zendesk, Jira, etc.)
      • Web page with a telephone number
      • Web page with an email address
      • Forum
    • The EULA link should point to an English Language EULA.
    \ No newline at end of file diff --git a/docs/auth/apikeys/index.html b/docs/auth/apikeys/index.html index 984a9ec..f596fe9 100644 --- a/docs/auth/apikeys/index.html +++ b/docs/auth/apikeys/index.html @@ -1,10 +1,8 @@ -API Keys |

    API Keys

    📘 Note

    All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

    Why API Keys?

    API keys are useful for small applications meant for personal use, allowing developers to avoid the overhead of the OAuth workflow. Creating an app is very easy with API keys: create an API key with the Developer Portal, set up a function to build your API key header as in the samples, and make your API calls! There’s no need to deal with OAuth redirects or things like that.

    We’ve moved over to using API keys for authenticating requests instead of using cookies for several reasons.

    1. Security: Each request is signed with unique headers so that we can be sure it’s coming from the right place.
    2. OAuth: The API key system we’re now using for HTTP requests is the same process developers follow when building full-blown OAuth applications; there’s no longer a disconnect between the two.

    Once you create an API key, it will only be valid in the stack on which it was created. An API key created on the partner stack, for example, will not function on the production stack.

    If you need information or have a question unanswered in this documentation, feel free to chat with us by sending an email to api-support@onshape.com or by checking out the forums. If you are a member of the DevPartners group (see the Development help page for information) more detailed instructions and code examples are in the apikey sample repo.

    1. Create API Keys

    1. Go to https://dev-portal.onshape.com.
    2. In the left pane, click API keys.
    3. Click the Create new API key button.
    4. Select the desired permissions for your app.
    5. Click the Create API key button.
      image
    6. Copy both the access key and secret key from the pop-up window, save them somewhere, then click the Close button.
      IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!
      image
    7. The details for your application appear.
      image
    8. Now that you have a key pair, see Generate a Request Signature for information on signing your requests to use our API.

    Once you have your access key and secret, you will want to avoid giving others access to them, since they’re tied directly to your personal Onshape account. Think of your API key as a username and password pair. Do not place them directly in the code for your application, especially if others might see it. The samples we provide here use a separate configuration file to contain this information, but there are other ways to keep the access key and secret safe, like setting them as environment variables.

    Scopes

    There are several scopes available for API keys (equivalent to OAuth scopes):

    • OAuth2Read - Read non-personal information (documents, parts, etc.)
    • OAuth2ReadPII - Read personal information (name, email, etc.)
    • OAuth2Write - Create and edit documents, etc.
    • OAuth2Delete - Delete documents, etc.
    • OAuth2Purchase - Authorize purchases from account

    2. Select an Authentication Option

    Please select an option for authentication:

    Basic Authorization

    For local testing, you can provide a basic authentication via your API Keys.

    1. Open your terminal and run the following command, replacing ACCESS_KEY and SECRET_KEY with the access key and secret key you created earlier. Remember to include the colon (:) between the keys. You will receive a long, base-64-encoded string as output.
      • MacOS:
        printf ACCESS_KEY:SECRET_KEY | base64
        +API Keys | 

        API Keys

        📘 Note

        All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

        Why API Keys?

        API keys are useful for small applications meant for personal use, allowing developers to avoid the overhead of the OAuth workflow. Creating an app is very easy with API keys: create an API key with the Developer Portal, set up a function to build your API key header as in the samples, and make your API calls! There’s no need to deal with OAuth redirects or things like that.

        We’ve moved over to using API keys for authenticating requests instead of using cookies for several reasons.

        1. Security: Each request is signed with unique headers so that we can be sure it’s coming from the right place.
        2. OAuth: The API key system we’re now using for HTTP requests is the same process developers follow when building full-blown OAuth applications; there’s no longer a disconnect between the two.

        Once you create an API key, it will only be valid in the stack on which it was created. An API key created on the partner stack, for example, will not function on the production stack.

        If you need information or have a question unanswered in this documentation, feel free to chat with us by sending an email to api-support@onshape.com or by checking out the forums. If you are a member of the DevPartners group (see the Development help page for information) more detailed instructions and code examples are in the apikey sample repo.

        1. Create API Keys

        1. Go to https://dev-portal.onshape.com.
        2. In the left pane, click API keys.
        3. Click the Create new API key button.
        4. Select the desired permissions for your app.
        5. Click the Create API key button.
          image
        6. Copy both the access key and secret key from the pop-up window, save them somewhere, then click the Close button.
          IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!
          image
        7. The details for your application appear.
          image
        8. Now that you have a key pair, see Generate a Request Signature for information on signing your requests to use our API.

        Once you have your access key and secret, you will want to avoid giving others access to them, since they’re tied directly to your personal Onshape account. Think of your API key as a username and password pair. Do not place them directly in the code for your application, especially if others might see it. The samples we provide here use a separate configuration file to contain this information, but there are other ways to keep the access key and secret safe, like setting them as environment variables.

        Scopes

        There are several scopes available for API keys (equivalent to OAuth scopes):

        • OAuth2Read - Read non-personal information (documents, parts, etc.)
        • OAuth2ReadPII - Read personal information (name, email, etc.)
        • OAuth2Write - Create and edit documents, etc.
        • OAuth2Delete - Delete documents, etc.
        • OAuth2Purchase - Authorize purchases from account

        2. Select an Authentication Option

        Please select an option for authentication:

        Basic Authorization

        For local testing, you can provide a basic authentication via your API Keys.

        1. Open your terminal and run the following command, replacing ACCESS_KEY and SECRET_KEY with the access key and secret key you created earlier. Remember to include the colon (:) between the keys. You will receive a long, base-64-encoded string as output.
          • MacOS:
            printf ACCESS_KEY:SECRET_KEY | base64
             
          • Windows:
            powershell "[convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\"ACCESS_KEY:SECRET_KEY\"))"
             
        2. Add the authorization header to your code, replacing CREDENTIALS with the string you receieved in Step 1:
          -H 'Authorization: Basic CREDENTIALS' \
           

        See our Quick Start Guide for an example of using Basic Authorization in an app.

        Request Signature

        For additional security, you can include your API Keys as part of a request signature. This provides more security than the Basic Authorization above, but less security than OAuth2.

        To ensure that a request is coming from you, we have a process for signing requests that you must follow for API calls to work. Everything is done via HTTP headers that you’ll need to set:

        1. Date: A standard date header giving the time of the request; must be accurate within 5 minutes of request. Example: Mon, 11 Apr 2016 20:08:56 GMT
        2. On-Nonce: A string that satisfies the following requirements (see the code for one possible way to generate it):
          • At least 16 characters
          • Alphanumeric
          • Unique for each request
        3. Authorization: This is where the API keys come into play. You’ll sign the request by implementing this algorithm:
          • Input: Method, URL, On-Nonce, Date, Content-Type, AccessKey, SecretKey
          • Output: String of the form: On <AccessKey>:HmacSHA256:<Signature>
          • Steps to generate the signature portion:
            1. Parse the URL and get the following:
              1. The path, e.g. /api/documents (no query params!)
              2. The query string, e.g. a=1&b=2
                • NOTE: If no query paramaters are present, use an empty string
            2. Create a string by appending the following information in order. Each field should be separated by a newline (\n) character, and the string must be converted to lowercase:
              1. HTTP method
              2. On-Nonce header value
              3. Date header value
              4. Content-Type header value
              5. URL pathname
              6. URL query string
            3. Using SHA-256, generate an HMAC digest, using the API secret key first and then the above string, then encode it in Base64.
            4. Create the On <AccessKey>:HmacSHA256:<Signature> string and use that in the Authorization header in your request.

        Below is an example function to generate the authorization header, using Node.js’s standard crypto and url libraries:

        // ...at top of file
        @@ -39,4 +37,4 @@
             var signature = 'On ' + accessKey + ':HmacSHA256:' + hmac;
             return signature;
         }
        -

        Redirects

        Some API endpoints return 307 redirects. You must generate an Authorization header for the redirect as well, but please note that the server portion of the URL might be different, the redirect URL may contain query parameters that must be encoded in the Authorization header, etc.

        \ No newline at end of file +

    Redirects

    Some API endpoints return 307 redirects. You must generate an Authorization header for the redirect as well, but please note that the server portion of the URL might be different, the redirect URL may contain query parameters that must be encoded in the Authorization header, etc.

    \ No newline at end of file diff --git a/docs/auth/index.html b/docs/auth/index.html index 7bd873d..087e705 100644 --- a/docs/auth/index.html +++ b/docs/auth/index.html @@ -1,4 +1,4 @@ -Authentication |

    Authentication

    📘 Note

    All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

    We’ve structured API keys to work very similarly to OAuth in the operation of your app. You must build your Authorization header differently (and set up redirects and sign-ins), but the API calls themselves work the same in both versions, provided that the API key and the OAuth app have the same scopes. An API key with the OAuth2Read and OAuth2Write scopes have the same access to the same API endpoints as an OAuth application with the OAuth2Read and OAuth2Write scopes. The only differences are when calling API endpoints in relation to the OAuth application itself, since an API key request does not come from an OAuth application.

    Please select an option for authentication:

    \ No newline at end of file +Authentication |

    Authentication

    📘 Note

    All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

    We’ve structured API keys to work very similarly to OAuth in the operation of your app. You must build your Authorization header differently (and set up redirects and sign-ins), but the API calls themselves work the same in both versions, provided that the API key and the OAuth app have the same scopes. An API key with the OAuth2Read and OAuth2Write scopes have the same access to the same API endpoints as an OAuth application with the OAuth2Read and OAuth2Write scopes. The only differences are when calling API endpoints in relation to the OAuth application itself, since an API key request does not come from an OAuth application.

    Please select an option for authentication:

    \ No newline at end of file diff --git a/docs/auth/index.xml b/docs/auth/index.xml index 02ce612..99bf056 100644 --- a/docs/auth/index.xml +++ b/docs/auth/index.xml @@ -1,685 +1,4 @@ -– Authenticationhttps://onshape-public.github.io/docs/auth/Recent content in Authentication onHugo -- gohugo.ioen-usMon, 18 May 2020 20:25:28 -0400Docs: OAuthhttps://onshape-public.github.io/docs/auth/oauth/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/auth/oauth/ -<p><strong>See the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app</a> for a working example of OAuth2.</strong></p> -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.</p> -</blockquote> -<h2 id="what-is-oauth2">What is OAuth2?</h2> -<p>The OAuth (Open authorization) protocol was developed by the Internet Engineering Task Force, an open standards organization that develops and promotes voluntary Internet standards (particularly the technical standards that comprise the Internet protocol suite) to enable secure, delegated access to an application&rsquo;s resources.</p> -<p>The OAuth2 protocol enables an application to access a resource that is under the control of someone else. In order to access that resource, a <i>token</i> is required. The token represent the delegated rights of access (that is, what rights this application has, such as read/write/update, scope, rights to different resources, and more).</p> -<p><i>This means the application can be accessed by a third-party system without that system -impersonating the user that controls the resource.</i></p> -<p>A good analogy is the hotel check-in process. When you arrive at the front desk of a hotel, you provide an ID and a form of payment. Then, you are given a key card that opens a specific door. When you reach that door, you swipe your key card and are granted access. The door itself doesn’t know who you are or anything about you, it just knows that the key card was encoded correctly, and it allows you access. At some point, the key card expires, and the door no longer lets you into the room. This is the same for access tokens in the OAuth2 flow.</p> -<p>With the OAuth2 protocol, you register your application with the third party, and you are given a set of keys. These keys get exchanged for an access token that grants you access to resources in the third-party application. The token expires regularly; you miust get a new token to access the application again. For this, you are provided with a <i>refresh token</i>. Sending the refresh token to the authentication server updates your access token and gives you a new refresh token.</p> -<p><img src="https://onshape-public.github.io/images/APITokenRequestDiagram.png" alt="api token request diagram"></p> -<h3 id="oauth2--onshape">OAuth2 &amp; Onshape</h3> -<p>The first step in the OAuth flow is for the Onshape user to request that Onshape let the third-party application access Onshape.</p> -<p>Once the user has authorized the application, they are redirected to a predefined URL (called a <i>redirect URL</i>) with a code that will requests an access token from Onshape. Therefore, the redirect URL should contain a script that can capture the authorization code.</p> -<p>You will use the access token to authenticate requests to the Onshape API. The token expires after preset amount of time. To get a new valid access token after one has expired, you must use the refresh token to request a new access token. Refreshing the access token also provides you with an updated refresh token to use in the next refresh access token request. Make sure to store both the the access token and the refresh token, and update them with each refresh of the token. The authorization token must accompany any call to the API, this is done by adding the token to an Authorization field in the header of each request:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>Authorization: Bearer &lt;accessToken&gt; -</span></span></code></pre></div><p>If correctly authenticated, most responses from the REST API call return JSON data (though some return binary data), with an HTTP response code of <code>200 Success</code>, <code>204 - No Content</code>, or <code>301 - Permanent Redirect</code>. <code>301</code> responses will include a redirect for you to follow.</p> -<p>In the event that the authorization code is incorrect (for instance, if it expired), you will receive an <strong>HTTP 401</strong> response. This response means that the client request has not been completed, since it lacks valid authentication credentials for the requested resource. In this event, your code for each call to the REST API should include a catch clause for a 401 exception. Once caught, you can refresh the token and make the request again. Pay close attention to the <code>Content-Type</code> header for what data to parse and expect.</p> -<p>When integrating with Onshape, OAuth tokens give third-party applications (such as desktop applications or web services) access to users&rsquo; data as defined by the permissions scope (such as users&rsquo; documents or profile information). Using OAuth terminology, Onshape acts as both the authorization and resource server, while the desktop or web-based application is the client. Resource owners have the option of granting or denying access to applications.</p> -<p>Once obtained, an OAuth token will work for third-party APIs under <code>/api</code>. Do NOT attempt to use an OAuth token to fetch the URLs typically displayed in a web browsers location bar.</p> -<h3 id="more-resources">More resources</h3> -<ul> -<li><a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2">Digital Ocean</a> - A good resource for learning more about OAuth2.</li> -<li><a href="http://tools.ietf.org/html/rfc6749">RFC 6749</a> - The reference for the OAuth framework as a whole. Most of this document describes how to implement the OAuth exchanges described by the reference within the context of Onshape and client applications.</li> -<li><a href="http://tools.ietf.org/html/rfc6750">RFC 6750</a> - Describes the exchange of OAuth access tokens between clients and OAuth servers.</li> -</ul> -<h2 id="implement-oauth2">Implement OAuth2</h2> -<p>This OAuth tutorial demonstrates how to recreate the authentication process in Node.js found in the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app</a> sample code. The <a href="#final-code">final code</a> in Node.js and other languages can be found at the end of this page.</p> -<h3 id="1-register-the-app">1: Register the app</h3> -<ol> -<li>Navigate to <a href="https://dev-portal.onshape.com/signin">https://dev-portal.onshape.com/signin</a> and sign in.</li> -<li>In the left sidebar, click <strong>OAuth applications</strong>.</li> -<li>Click the <strong>Create new OAuth application</strong> button.</li> -<li>Fill out the form as follows: -<ul> -<li>Name: <code>gltf-viewer-yourname</code> -<ul> -<li>The application name to display to users.</li> -<li>Should include the name of your company to differentiate it from other possibly similar applications.</li> -</ul> -</li> -<li>Primary format: <code>com.yourname.gltf-viewer</code> -<ul> -<li>String that uniquely identifies your application and is a marker for the data it might store on Onshape servers.</li> -<li>Cannot be changed after the application is registered.</li> -</ul> -</li> -<li>Summary: <code>Onshape OAuth tutorial</code> -<ul> -<li>Description of your application.</li> -<li>Displayed to the user when they’re asked to grant the application permission to access their data.</li> -</ul> -</li> -<li>Redirect URLs: <code>http://localhost:5000/token</code> -<ul> -<li>Your application must specify at least one URL used in the OAuth protocol exchanges.</li> -<li>This URL must also use SSL (a URL that begins with https), with two exceptions applicable for -installed desktop applications: <code>http://localhost:&lt;port&gt;</code> and <code>urn:ietf:wg:oauth:2.0:oob</code>.</li> -<li>e.g., <code>https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthRedirect</code></li> -</ul> -</li> -<li>Admin team: <code>No Team</code> -<ul> -<li>Optional.</li> -<li>If defined, members of the team can make changes to the definition of this OAuth application.</li> -<li>See the <a href="https://cad.onshape.com/help/Content/teams-enterprise.htm">Help Docs: Teams</a> page for more information on creating teams in Onshape.</li> -</ul> -</li> -<li>OAuth URL: <code>none</code> -<ul> -<li>Should contain the URL of your deployed application.</li> -<li>This is the first URL called from the Onshape Applications page.</li> -<li>The page hosted at this URL should handle the OAuth authentication. Once your application’s server has been authenticated on behalf of the user, that user should be redirected to your applications content.</li> -<li>If you have not deployed your app yet, you can leave this field blank (as shown in this example) for local work and update it later.</li> -<li>e.g., <code>https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthSignin</code></li> -</ul> -</li> -<li>Settings: check <strong>Supports collaboration</strong></li> -<li>Permissions: -<ul> -<li>This is also called application scope, and it defines what access rights your application has to the user’s data.</li> -<li><strong>Application can read your profile information</strong> - Enable your application to access the Onshape user profile. Check this option.</li> -<li><strong>Application can read your documents</strong> - Onshape documents created by this user can be accessed with read privileges only. Check this option.</li> -<li><strong>Application can write to your documents</strong> - The user-owned Onshape documents can be modified by this application. Check this option.</li> -<li><strong>Application can delete documents and workspaces</strong> - Your application will be able to delete a workspace within a document or the complete Onshape document. Do not check this option for this example.</li> -<li><strong>Application can request Purchases on Your behalf</strong> - The application will have access to make purchases if required. Do not check this option for this example.</li> -<li><strong>Application can share and unshare documents on your behalf</strong> - Onshape’s document sharing capabilities are very powerful; they enable other parties to access your shared documents with -predefined rights. If this option is checked, the application can automatically share a document with other people. Do not check this option for this example.</li> -</ul> -</li> -</ul> -</li> -<li>Click <strong>Create application</strong>.</li> -<li><font style="color: red"><b>COPY THE OAUTH SECRET FROM THE POP-UP WINDOW.<b></font> -<ul> -<li>You will not be able to access this secret again.</li> -<li>This secret is unique to you and your app and should be protected like any sensitive password. For example, it should <em>NOT</em> be checked in to source code control systems.</li> -</ul> -</li> -<li>Click <strong>Close</strong>.</li> -<li>Copy the <strong>OAuth client identifier</strong> from the app Details page that opens. -<ul> -<li>These OAuth secret and client ID keys will be used in your code for requesting a one-time user authorization code from Onshape.</li> -</ul> -</li> -</ol> -<p>Your application is now registered with Onshape and you have options to -modify the application definition through this portal.</p> -<img src="https://onshape-public.github.io/images/dev-portal-app-details-01.png" alt="the gltf-viewer app in the onshape dev portal app details screen" /> -<h3 id="2-get-the-user-authorization-code">2: Get the user authorization code</h3> -<p>We’ll start by loading the basic libraries required to run this sample. We&rsquo;ll use Passport to authenticate requests through plugins known as strategies. In this example, we&rsquo;ll use an Onshape-developed plugin called <code>passport-onshape</code>, but you can define your own strategy to use with Passport, if you prefer. You can find more information on <a href="https://www.npmjs.com/package/passport">Passport here</a>.</p> -<ol> -<li>Create a directory for your app, and then install Passport and passport-onshape:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>npm install passport -</span></span><span style="display:flex;"><span>npm install passport-onshape -</span></span></code></pre></div><ol start="2"> -<li>Next, create a file calls <code>app.js</code> and add the following definitions to the top of the file:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// App definitions -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> path = require(<span style="color:#a50">&#39;path&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> uuid = require(<span style="color:#a50">&#39;uuid&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> express = require(<span style="color:#a50">&#39;express&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> session = require(<span style="color:#a50">&#39;express-session&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> bodyParser = require(<span style="color:#a50">&#39;body-parser&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> passport = require(<span style="color:#a50">&#39;passport&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> OnshapeStrategy = require(<span style="color:#a50">&#39;passport-onshape&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> config = require(<span style="color:#a50">&#39;./config&#39;</span>); -</span></span></code></pre></div><ol start="3"> -<li>Next, tell Express to use Passport and initialize it. Note: you can replace the Express code with code for the web server of your choice.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// Tell Express to use Passport, and initialize it. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> app = express(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;dist&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(bodyParser.json()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.set(<span style="color:#a50">&#39;trust proxy&#39;</span>, <span style="color:#099">1</span>); <span style="color:#aaa;font-style:italic">// To allow to run correctly behind Heroku when deployed -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span>app.use(session({ -</span></span><span style="display:flex;"><span> secret: config.sessionSecret, -</span></span><span style="display:flex;"><span> saveUninitialized: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> resave: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> cookie: { -</span></span><span style="display:flex;"><span> name: <span style="color:#a50">&#39;app-gltf-viewer&#39;</span>, -</span></span><span style="display:flex;"><span> sameSite: <span style="color:#a50">&#39;none&#39;</span>, -</span></span><span style="display:flex;"><span> secure: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> httpOnly: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> path: <span style="color:#a50">&#39;/&#39;</span>, -</span></span><span style="display:flex;"><span> maxAge: <span style="color:#099">1000</span> * <span style="color:#099">60</span> * <span style="color:#099">60</span> * <span style="color:#099">24</span> <span style="color:#aaa;font-style:italic">// 1 day -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span>})); -</span></span><span style="display:flex;"><span>app.use(passport.initialize()); -</span></span><span style="display:flex;"><span>app.use(passport.session()); -</span></span></code></pre></div><ol start="4"> -<li>Next, we&rsquo;ll store the Onshape user information so it can be retrieved from <code>req.user</code> in -each call. Passport uses the <code>serializeUser</code> function to persist user data (after successful -authentication) into the session. The function <code>deserializeUser</code> is used -to retrieve user data from session.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Store the Onshape user information -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.serializeUser((user, done) =&gt; done(<span style="color:#00a">null</span>, user)); -</span></span><span style="display:flex;"><span>passport.deserializeUser((obj, done) =&gt; done(<span style="color:#00a">null</span>, obj)); -</span></span></code></pre></div><ol start="6"> -<li>Initialize Passport with the Onshape Strategy:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Initialize Passport with the Onshape Strategy -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.use(<span style="color:#00a">new</span> OnshapeStrategy({ -</span></span><span style="display:flex;"><span> clientID: config.oauthClientId, -</span></span><span style="display:flex;"><span> clientSecret: config.oauthClientSecret, -</span></span><span style="display:flex;"><span> callbackURL: config.oauthCallbackUrl, -</span></span><span style="display:flex;"><span> authorizationURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/authorize`</span>, -</span></span><span style="display:flex;"><span> tokenURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/token`</span>, -</span></span><span style="display:flex;"><span> userProfileURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/api/users/sessioninfo`</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> (accessToken, refreshToken, profile, done) =&gt; { -</span></span><span style="display:flex;"><span> profile.accessToken = accessToken; -</span></span><span style="display:flex;"><span> profile.refreshToken = refreshToken; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> done(<span style="color:#00a">null</span>, profile); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>)); -</span></span></code></pre></div><ol start="7"> -<li>Open your environment variables file (e.g.,<code>.env</code>, <code>.bashrc</code>, <code>.bash_profile</code>, <code>.zshrc,</code> etc.) and add the following environment variables, then save and close the file.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>authorizationURL : https://oauth.onshape.com/oauth/authorize -</span></span><span style="display:flex;"><span>tokenURL : https://oauth.onshape.com/oauth/token -</span></span><span style="display:flex;"><span>userProfileURL : https://cad.onshape.com/api/users/sessioninfo -</span></span></code></pre></div><p>The callback function will provide us with the <code>accessToken</code>, the <code>refreshToken</code>, and the user’s Onshape profile once authentication has been successfully passed. We can now use this to update our database with user-specific information.</p> -<p>Note that if you store the <code>accessToken</code> and <code>refreshToken</code> in the database along with the user record, you must update it each time that the access codes are refreshed.</p> -<ol start="8"> -<li>Next, we define our endpoint where the authorization flow starts (in this case, <code>/oauthSignin</code>). This is the endpoint that we previously defined in the Onshape application setup. This will redirect to an Onshape page in order for the user to confirm (or deny) the applications access to theOnshape resources.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Define the Onshape API endpoint -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthSignin&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* These 5 lines are specific to the glTF Viewer sample app. You can replace them with the input for whatever Onshape endpoints you are using in your app */</span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> state = { -</span></span><span style="display:flex;"><span> docId: req.query.documentId, -</span></span><span style="display:flex;"><span> workId: req.query.workspaceId, -</span></span><span style="display:flex;"><span> elId: req.query.elementId -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> req.session.state = state; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { state: uuid.v4(state) })(req, res); -</span></span><span style="display:flex;"><span>}, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> }); -</span></span></code></pre></div><h3 id="3-exchange-the-code-for-an-access-token">3: Exchange the code for an access token</h3> -<p>Fortunately, if you are using Passport, there isn’t much to do once the user grants authorization. The return URL will contain the one-time authorization token, which Passport will extract and exchange for an access token and a refresh token, which are available in Passport callback function.</p> -<ol> -<li>Add the following code to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Exchange the code for an access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthRedirect&#39;</span>, passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { failureRedirect: <span style="color:#a50">&#39;/grantDenied&#39;</span> }), (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* This code is specific to the glTF Viewer sample app. You can replace it with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> res.redirect(<span style="color:#a50">`/?documentId=</span><span style="color:#a50">${</span>req.session.state.docId<span style="color:#a50">}</span><span style="color:#a50"> -</span></span></span><span style="display:flex;"><span><span style="color:#a50">&amp;workspaceId=</span><span style="color:#a50">${</span>req.session.state.workId<span style="color:#a50">}</span><span style="color:#a50">&amp;elementId= -</span></span></span><span style="display:flex;"><span><span style="color:#a50"> </span><span style="color:#a50">${</span>req.session.state.elId<span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span>}); -</span></span></code></pre></div><ol start="2"> -<li>If the user clicks <strong>Deny</strong> instead of <strong>Authorize Application</strong>, they are taken to a page that notifies them that access to the application was denied. We can see that in the <code>failureRedirect</code> argument. Add the following to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Handle denied access -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/grantDenied&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;grantDenied.html&#39;</span>)); -</span></span><span style="display:flex;"><span>}) -</span></span></code></pre></div><p>Now we have received the access token, and it can be accessed from <code>res.user.accessToken</code> on this page or from <code>req.user.accessToken</code> from any other page you redirect to from here.</p> -<h3 id="4-use-the-access-token">4: Use the access token</h3> -<ol> -<li>Add the following to the bottom of <code>app.js</code>. You can see that the access token is used as an Authorization header:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Use the access token as an Authorization header -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>makeOnshapeAPICall: <span style="color:#00a">async</span> (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">try</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> apiUrl = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents?ownerType=1&amp;sortColumn=createdAt&amp;sortOrder=desc&amp;offset=0&amp;limit=20&#34;</span>; <span style="color:#aaa;font-style:italic">//You can replace this with any Onshape API endpoint URL. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">const</span> resp = <span style="color:#00a">await</span> fetch(normalizedUrl, { headers: { Authorization: <span style="color:#a50">`Bearer </span><span style="color:#a50">${</span>req.user.accessToken<span style="color:#a50">}</span><span style="color:#a50">`</span> }}); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> data = <span style="color:#00a">await</span> resp.text(); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> contentType = resp.headers.get(<span style="color:#a50">&#39;Content-Type&#39;</span>); -</span></span><span style="display:flex;"><span> res.status(resp.status).contentType(contentType).send(data); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">catch</span> (err) { -</span></span><span style="display:flex;"><span> res.status(<span style="color:#099">500</span>).json({ error: err }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><p>Note: in the glTF Viewer sample app, this code appears in <code>utils.js</code> instead of <code>app.js</code>.</p> -<h3 id="5-refresh-the-token">5: Refresh the token</h3> -<p>When the access token expires, it must be refreshed by making another <code>POST</code> request to <code>https://oauth.onshape.com/oauth/token</code> with the following URL-encoded form body (with <code>Content-Type application/x-www-form-urlencoded</code>):</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#a00">grant_type</span>=refresh_token&amp;<span style="color:#a00">refresh_token</span>=<span style="color:#a50">\&lt;</span>refresh_token<span style="color:#a50">\&gt;</span>&amp;<span style="color:#a00">client_id</span>=<span style="color:#a50">\&lt;</span>client_id<span style="color:#a50">\&gt;</span>&amp;<span style="color:#a00">client_secret</span>=<span style="color:#a50">\&lt;</span>client_secret<span style="color:#a50">\&gt;</span> -</span></span></code></pre></div><p>As with the authorization code data, the parameters in the form body must be URL-encoded. The response to this <code>POST</code> request will be a JSON-encoded structure with a new <code>access_token</code> value that can be used for the next 60 minutes.</p> -<p>Refresh tokens are valid for the lifetime of the user’s grant. If a user who previously granted access to your application decides to revoke the grant, the refresh token is invalidated. If the user decides to re-grant application access, a new refresh token is generated and returned along with the access token.</p> -<ol> -<li>Add the following to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** After landing on the home page, we check if a user had already signed in. If no user has signed in, we redirect the request to the OAuth sign-in page. If a user had signed in previously, we will attempt to refresh the access token of the user. After successfully refreshing the access token, we will simply take the user to the landing page of the app. If the refresh token request fails, we will redirect the user to the OAuth sign-in page again. */</span> -</span></span><span style="display:flex;"><span>app.get(<span style="color:#a50">&#39;/&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (!req.user) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> refreshAccessToken(req.user).then((tokenJson) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Dereference the user object and update the access token and refresh token in the in-memory object. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">let</span> usrObj = JSON.parse(JSON.stringify(req.user)); -</span></span><span style="display:flex;"><span> usrObj.accessToken = tokenJson.access_token; -</span></span><span style="display:flex;"><span> usrObj.refreshToken = tokenJson.refresh_token; -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Update the user object in PassportJS. No redirections will happen here, this is a purely internal operation. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> req.login(usrObj, () =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;index.html&#39;</span>)); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> }).<span style="color:#00a">catch</span>(() =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Refresh token failed, take the user to OAuth sign in page. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Refresh the access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> refreshAccessToken = <span style="color:#00a">async</span> (user) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> body = <span style="color:#a50">&#39;grant_type=refresh_token&amp;refresh_token=&#39;</span> + user.refreshToken + <span style="color:#a50">&#39;&amp;client_id=&#39;</span> + config.oauthClientId + <span style="color:#a50">&#39;&amp;client_secret=&#39;</span> + config.oauthClientSecret; -</span></span><span style="display:flex;"><span> <span style="color:#00a">let</span> res = <span style="color:#00a">await</span> fetch(config.oauthUrl + <span style="color:#a50">&#34;/oauth/token&#34;</span>, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;POST&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/x-www-form-urlencoded&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> body: body -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (res.ok) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#00a">await</span> res.json(); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">throw</span> <span style="color:#00a">new</span> <span style="color:#0aa">Error</span>(<span style="color:#a50">&#34;Could not refresh access token, please sign in again.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/api&#39;</span>, require(<span style="color:#a50">&#39;./api&#39;</span>)); -</span></span><span style="display:flex;"><span>module.exports = app; -</span></span></code></pre></div><ol start="2"> -<li>Save the file.</li> -<li>To see the authentication working in practice, you can follow the instructions in the <a href="https://github.com/onshape-public/app-gltf-viewer#readme">glTF Viewer README</a> to deploy the glTF Viewer app.</li> -</ol> -<h3 id="6-grant-authorization">6: Grant authorization</h3> -<p>For apps published in the Onshape App Store, the Onshape user must grant authorization to your application to access the Onshape data. This must be done by each user of your app.</p> -<p>To grant the application access to a user&rsquo;s data in Onshape, the <em>Onshape user</em> must follow the steps below:</p> -<ol> -<li>Sign in to <code>cad.onshape.com</code>. -<ul> -<li>Note: Use <code>https://companyName.onshape.com</code> for Enterprise accounts. See <a href="#enterprise-users">Enterprise users</a> below for more information.</li> -</ul> -</li> -<li>Click their name in the top-right corner of the Onshape window, and then click <strong>My account</strong> in the dropdown menu. -</br><img src="https://onshape-public.github.io/images/myaccountdropdown.png" alt="drawing" width="300"/></li> -<li>Click <strong>Applications</strong> in the left sidebar. -<ul> -<li>Note that the gltf-viewer app will not appear in this list until it has been deployed and subscribed to as described in the <a href="https://github.com/onshape-public/app-gltf-viewer#readme">glTF Viewer README</a>.</li> -</ul> -</li> -<li>Click <strong>Grant</strong> next to your app name to grant it access to their Onshape data. The Onshape user can click <strong>Revoke</strong> at any time to prevent your app from accessing their Onshape data.</li> -<li>The user will see the Authorize application screen shown below and will need to confirm their authorization grant by clicking <strong>Authorize application</strong>. The user is then redirected to the Redirect URL you specified in your code. Your app can now access the user&rsquo;s Onshape resources and profile.</li> -</ol> -<h2 id="notes">Notes</h2> -<h3 id="installed-desktop-applications">Installed desktop applications</h3> -<p>OAuth is designed for interactions between two servers using a browser. However, it can also be used by an installed desktop (or mobile) application. The application must perform a similar role to that of a third party server: it must exchange the code for an access token structure.</p> -<p>To enable this, Onshape allows two special forms of redirect URI to be registered:</p> -<ul> -<li><code>http://localhost:&lt;port&gt;</code> Causes the browser to attempt to load a page from the host upon which it is running. The code parameter will be supplied exactly the same as outlined above. If the application can listen on the registered port and behave as a simple web server for the redirect URL, it can retrieve the code in the same way as a deployed web server.</li> -<li><code>urn:ietf:wg:oauth:2.0:oob</code> Causes the browser to display a simple page after a request has been granted instead of going to a new URL. The page contains simple instructions to copy and paste code into an application field. The browser will also update the title of the window to contain the code. An application could also look for browsers with window titles containing the string <code>Success code=&lt;code&gt;</code> and automatically grab the code from the browser window title. If an error occurs (e.g., the grant is denied), the browser window title will contain <code>Error description=&lt;error string&gt;</code>.</li> -</ul> -<h3 id="enterprise-users">Enterprise users</h3> -<p>When a user authorizes an OAuth app to access Onshape on their behalf, they get a bearer token that corresponds to their session and the allowed scopes.</p> -<p>However, if the user has a seat in the Enterprise, additional information is needed to determine whether to allow the bearer token to access enterprise data for the user or simply return non-enterprise data. We use the <code>companyId</code> field for this distinction.</p> -<p>There are two ways of setting the <code>companyId</code> correctly to access enterprise data:</p> -<ul> -<li>During the authorization process, select the name and URL of the enterprise instead of <code>cad.onshape.com</code>. This will correctly associate your bearer token with the <code>companyId</code>.</li> -<li>If you have an integrated app, call the <a href="https://cad.onshape.com/glassworks/explorer/#/Company/findCompany">Company/findCompany</a> endpoint to obtain the <code>companyId</code>. Append this <code>companyId</code> as a query parameter to the <code>/authorize</code> URL while initiating the OAuth workflow. (Note: you may be asked to authenticate yourself again.)</li> -</ul> -<h3 id="3rd-party-cookies">3rd-party cookies</h3> -<p>3rd-party cookies must be enabled in the browser for Onshape apps to work correctly.</p> -<h3 id="debugging">Debugging</h3> -<p>Debugging OAuth can be a little tricky. Some tips are below:</p> -<ol> -<li>Make sure you are correctly URL encoding the values supplied to the oauth/authorize and oauth/token endpoints.</li> -<li>Use a <code>GET /oauth/authorize</code> but a <code>POST /oauth/token</code> and make sure that the GET uses query parameters but that the <code>POST</code> uses a URL-encoded form body.</li> -<li>If you supply a <code>redirect_uri</code> to <code>/oauth/authorize</code>, you must also supply it as an additional parameter in the <code>POST</code> to <code>/oauth/token</code></li> -<li>Use a tool such as <a href="https://portswigger.net/burp">Burp</a> or <a href="http://charlesproxy.com">Charles</a> to deliberately &lsquo;man-in-the-middle&rsquo; the connection requests between your server and Onshape, and verify that you are performing the correct REST operations (GET vs. POST) and correctly URL-encoding the parameter values.</li> -</ol> -<h2 id="final-code">Final Code</h2> -<p>The above example uses Node.js to authenticate an Onshape app. This section includes the code for using OAuth2 with other coding languages.</p> -<h3 id="nodejs">Node.js</h3> -<p><strong>Prerequisites</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npm install passport -</span></span><span style="display:flex;"><span>npm install passport-onshape -</span></span></code></pre></div><p><strong>Environment variables</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>authorizationURL : &lt;https://oauth.onshape.com/oauth/authorize&gt; -</span></span><span style="display:flex;"><span>tokenURL : &lt;https://oauth.onshape.com/oauth/token&gt; -</span></span><span style="display:flex;"><span>userProfileURL : &lt;https://cad.onshape.com/api/users/sessioninfo&gt; -</span></span></code></pre></div><p><strong>app.js</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//App definitions -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> path = require(<span style="color:#a50">&#39;path&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> uuid = require(<span style="color:#a50">&#39;uuid&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> express = require(<span style="color:#a50">&#39;express&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> session = require(<span style="color:#a50">&#39;express-session&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> bodyParser = require(<span style="color:#a50">&#39;body-parser&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> passport = require(<span style="color:#a50">&#39;passport&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> OnshapeStrategy = require(<span style="color:#a50">&#39;passport-onshape&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> config = require(<span style="color:#a50">&#39;./config&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Tell Express to use Passport, and initialize it. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> app = express(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;dist&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(bodyParser.json()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.set(<span style="color:#a50">&#39;trust proxy&#39;</span>, <span style="color:#099">1</span>); <span style="color:#aaa;font-style:italic">// To allow to run correctly behind Heroku when deployed. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span>app.use(session({ -</span></span><span style="display:flex;"><span> secret: config.sessionSecret, -</span></span><span style="display:flex;"><span> saveUninitialized: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> resave: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> cookie: { -</span></span><span style="display:flex;"><span> name: <span style="color:#a50">&#39;app-gltf-viewer&#39;</span>, -</span></span><span style="display:flex;"><span> sameSite: <span style="color:#a50">&#39;none&#39;</span>, -</span></span><span style="display:flex;"><span> secure: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> httpOnly: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> path: <span style="color:#a50">&#39;/&#39;</span>, -</span></span><span style="display:flex;"><span> maxAge: <span style="color:#099">1000</span> * <span style="color:#099">60</span> * <span style="color:#099">60</span> * <span style="color:#099">24</span> <span style="color:#aaa;font-style:italic">// 1 day -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span>})); -</span></span><span style="display:flex;"><span>app.use(passport.initialize()); -</span></span><span style="display:flex;"><span>app.use(passport.session()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Store the Onshape user information -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.serializeUser((user, done) =&gt; done(<span style="color:#00a">null</span>, user)); -</span></span><span style="display:flex;"><span>passport.deserializeUser((obj, done) =&gt; done(<span style="color:#00a">null</span>, obj)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Initialize Passport with the Onshape Strategy -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.use(<span style="color:#00a">new</span> OnshapeStrategy({ -</span></span><span style="display:flex;"><span> clientID: config.oauthClientId, -</span></span><span style="display:flex;"><span> clientSecret: config.oauthClientSecret, -</span></span><span style="display:flex;"><span> callbackURL: config.oauthCallbackUrl, -</span></span><span style="display:flex;"><span> authorizationURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/authorize`</span>, -</span></span><span style="display:flex;"><span> tokenURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/token`</span>, -</span></span><span style="display:flex;"><span> userProfileURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/api/users/sessioninfo`</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> (accessToken, refreshToken, profile, done) =&gt; { -</span></span><span style="display:flex;"><span> profile.accessToken = accessToken; -</span></span><span style="display:flex;"><span> profile.refreshToken = refreshToken; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> done(<span style="color:#00a">null</span>, profile); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Define the Onshape API endpoint -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthSignin&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* These 5 lines are specific to the glTF Viewer sample app. You can replace them with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> state = { -</span></span><span style="display:flex;"><span> docId: req.query.documentId, -</span></span><span style="display:flex;"><span> workId: req.query.workspaceId, -</span></span><span style="display:flex;"><span> elId: req.query.elementId -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> req.session.state = state; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { state: uuid.v4(state) })(req, res); -</span></span><span style="display:flex;"><span>}, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/oauthRedirect&#39;</span>, passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { failureRedirect: <span style="color:#a50">&#39;/grantDenied&#39;</span> }), (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* This code is specific to the glTF Viewer sample app. You can replace it with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> res.redirect(<span style="color:#a50">`/?documentId=</span><span style="color:#a50">${</span>req.session.state.docId<span style="color:#a50">}</span><span style="color:#a50">&amp;workspaceId=</span><span style="color:#a50">${</span>req.session.state.workId<span style="color:#a50">}</span><span style="color:#a50">&amp;elementId=</span><span style="color:#a50">${</span>req.session.state.elId<span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Handle denied access -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/grantDenied&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;grantDenied.html&#39;</span>)); -</span></span><span style="display:flex;"><span>}) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** After landing on the home page, we check if a user had already signed in. If no user has signed in, we redirect the request to the OAuth sign-in page. If a user had signed in previously, we will attempt to refresh the access token of the user. After successfully refreshing the access token, we will simply take the user to the landing page of the app. If the refresh token request fails, we will redirect the user to the OAuth sign-in page again. */</span> -</span></span><span style="display:flex;"><span>app.get(<span style="color:#a50">&#39;/&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (!req.user) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> refreshAccessToken(req.user).then((tokenJson) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Dereference the user object, and update the access token and refresh token in the in-memory object. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">let</span> usrObj = JSON.parse(JSON.stringify(req.user)); -</span></span><span style="display:flex;"><span> usrObj.accessToken = tokenJson.access_token; -</span></span><span style="display:flex;"><span> usrObj.refreshToken = tokenJson.refresh_token; -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Update the user object in PassportJS. No redirections will happen here, this is a purely internal operation. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> req.login(usrObj, () =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;index.html&#39;</span>)); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> }).<span style="color:#00a">catch</span>(() =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Refresh token failed, take the user to OAuth sign in page. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Refresh the access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> refreshAccessToken = <span style="color:#00a">async</span> (user) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> body = <span style="color:#a50">&#39;grant_type=refresh_token&amp;refresh_token=&#39;</span> + user.refreshToken + <span style="color:#a50">&#39;&amp;client_id=&#39;</span> + config.oauthClientId + <span style="color:#a50">&#39;&amp;client_secret=&#39;</span> + config.oauthClientSecret; -</span></span><span style="display:flex;"><span> <span style="color:#00a">let</span> res = <span style="color:#00a">await</span> fetch(config.oauthUrl + <span style="color:#a50">&#34;/oauth/token&#34;</span>, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;POST&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/x-www-form-urlencoded&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> body: body -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (res.ok) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#00a">await</span> res.json(); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">throw</span> <span style="color:#00a">new</span> <span style="color:#0aa">Error</span>(<span style="color:#a50">&#34;Could not refresh access token, please sign in again.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/api&#39;</span>, require(<span style="color:#a50">&#39;./api&#39;</span>)); -</span></span><span style="display:flex;"><span>module.exports = app; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Use the access token in an Authorization header. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>makeOnshapeAPICall: <span style="color:#00a">async</span> (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">try</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> apiUrl = <span style="color:#a50">&#34;https://cad.onshape.com/glassworks/explorer/#/Document/getDocuments&#34;</span>; <span style="color:#aaa;font-style:italic">//You can replace this with any Onshape API endpoint URL. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">const</span> resp = <span style="color:#00a">await</span> fetch(normalizedUrl, { headers: { Authorization: <span style="color:#a50">`Bearer </span><span style="color:#a50">${</span>req.user.accessToken<span style="color:#a50">}</span><span style="color:#a50">`</span> }}); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> data = <span style="color:#00a">await</span> resp.text(); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> contentType = resp.headers.get(<span style="color:#a50">&#39;Content-Type&#39;</span>); -</span></span><span style="display:flex;"><span> res.status(resp.status).contentType(contentType).send(data); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">catch</span> (err) { -</span></span><span style="display:flex;"><span> res.status(<span style="color:#099">500</span>).json({ error: err }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><h3 id="python">Python</h3> -<p>This Python code only works on a local machine. To deploy the code, you can replace the Flask code with the web server of your choice.</p> -<p><strong>Prerequisites</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pip3 install flask -</span></span><span style="display:flex;"><span>pip3 install requests_oauthlib -</span></span></code></pre></div><p><strong>app.py</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">flask</span> <span style="color:#00a">import</span> Flask, request, redirect, session, url_for -</span></span><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">flask.json</span> <span style="color:#00a">import</span> jsonify -</span></span><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">requests_oauthlib</span> <span style="color:#00a">import</span> OAuth2Session -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">os</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app = Flask(__name__) -</span></span><span style="display:flex;"><span>app.secret_key = <span style="color:#a50">b</span><span style="color:#a50">&#39;F</span><span style="color:#a50">\xf5\xe5\xc0\xbe\t</span><span style="color:#a50">g</span><span style="color:#a50">\x7f\xac\x89\x87</span><span style="color:#a50">e</span><span style="color:#a50">\xc2</span><span style="color:#a50">4</span><span style="color:#a50">\xe8</span><span style="color:#a50">m</span><span style="color:#a50">\x1c\xd9\xda\x96</span><span style="color:#a50">G,</span><span style="color:#a50">\x90</span><span style="color:#a50">i&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>os.environ[<span style="color:#a50">&#39;OAUTHLIB_INSECURE_TRANSPORT&#39;</span>] = <span style="color:#a50">&#34;1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>client_id = &lt;Client ID of your application&gt; -</span></span><span style="display:flex;"><span>client_secret = &lt;Client Secret of your application&gt; -</span></span><span style="display:flex;"><span>authorization_base_url = <span style="color:#a50">&#34;https://oauth.onshape.com/oauth/authorize&#34;</span> -</span></span><span style="display:flex;"><span>token_url = <span style="color:#a50">&#34;https://oauth.onshape.com/oauth/token&#34;</span> -</span></span><span style="display:flex;"><span>redirect_url = <span style="color:#a50">&#34;http://localhost:5000&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/&#39;</span>) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">home</span>(): -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> auth_url, state = onshape.authorization_url(authorization_base_url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_state&#39;</span>] = state -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> redirect(auth_url) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/token&#39;</span>, methods=[<span style="color:#a50">&#34;GET&#34;</span>]) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">token</span>(): -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, state=session[<span style="color:#a50">&#39;oauth_state&#39;</span>], redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> token = onshape.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_token&#39;</span>] = token -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> redirect(url_for(<span style="color:#a50">&#39;.documents&#39;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/documents&#39;</span>, methods=[<span style="color:#a50">&#34;GET&#34;</span>]) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">documents</span>(): -</span></span><span style="display:flex;"><span> extra = { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;client_id&#39;</span>: client_id, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;client_secret&#39;</span>: client_secret, -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, token=session[<span style="color:#a50">&#39;oauth_token&#39;</span>], redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_token&#39;</span>] = onshape.refresh_token(token_url, **extra) -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> jsonify(onshape.get(<span style="color:#a50">&#39;https://cad.onshape.com/api/v6/documents?q=Untitled&amp;ownerType=1&amp;sortColumn=createdAt&amp;sortOrder=desc&amp;offset=0&amp;limit=20&#39;</span>).json()) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">if</span> __name__ == <span style="color:#a50">&#34;__main__&#34;</span>: -</span></span><span style="display:flex;"><span> app.run() -</span></span><span style="display:flex;"><span> -</span></span></code></pre></div>Docs: API Keyshttps://onshape-public.github.io/docs/auth/apikeys/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/auth/apikeys/ -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a> page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.</p> -</blockquote> -<h2 id="why-api-keys">Why API Keys?</h2> -<p>API keys are useful for small applications meant for personal use, allowing developers to avoid the overhead of the OAuth workflow. Creating an app is very easy with API keys: create an API key with the Developer Portal, set up a function to build your API key header as in the samples, and make your API calls! There&rsquo;s no need to deal with OAuth redirects or things like that.</p> -<p>We&rsquo;ve moved over to using API keys for authenticating requests instead of using cookies for several reasons.</p> -<ol> -<li>Security: Each request is signed with unique headers so that we can be sure it&rsquo;s coming from the right place.</li> -<li>OAuth: The API key system we&rsquo;re now using for HTTP requests is the same process developers follow when building full-blown OAuth applications; there&rsquo;s no longer a disconnect between the two.</li> -</ol> -<p>Once you create an API key, it will only be valid in the stack on which it was created. An API key created on the partner stack, for example, will not function on the production stack.</p> -<p>If you need information or have a question unanswered in this documentation, feel free to chat with us by sending an email to <a href="mailto:api-support@onshape.com">api-support@onshape.com</a> or by checking out the <a href="https://forum.onshape.com" target="_blank">forums</a>. If you are a member of the DevPartners group (see the Development help page for information) more detailed instructions and code examples are in the apikey sample repo.</p> -<h2 id="1-create-api-keys">1. Create API Keys</h2> -<ol> -<li>Go to <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</li> -<li>In the left pane, click <code>API keys</code>.</li> -<li>Click the <code>Create new API key</code> button.</li> -<li>Select the desired permissions for your app.</li> -<li>Click the <code>Create API key</code> button. </br> -<img src="https://onshape-public.github.io/images/CreateNewAPIKey.png" alt="image"></li> -<li>Copy both the <strong>access key</strong> and <strong>secret key</strong> from the pop-up window, save them somewhere, then click the <code>Close</code> button. -</br><strong>IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!</strong></br> -<img src="https://onshape-public.github.io/images/APIKeySecretKey.png" alt="image"></li> -<li>The details for your application appear. </br> -<img src="https://onshape-public.github.io/images/DevPortalKeys.png" alt="image"></li> -<li>Now that you have a key pair, see <a href="#generating-a-request-signature">Generate a Request Signature</a> for information on signing your requests to use our API.</li> -</ol> -<p>Once you have your access key and secret, you will want to avoid giving others access to them, since they&rsquo;re tied directly to your personal Onshape account. Think of your API key as a username and password pair. Do not place them directly in the code for your application, especially if others might see it. The samples we provide here use a separate configuration file to contain this information, but there are other ways to keep the access key and secret safe, like setting them as environment variables.</p> -<h3 id="scopes">Scopes</h3> -<p>There are several scopes available for API keys (equivalent to OAuth scopes):</p> -<ul> -<li><code>OAuth2Read</code> - Read non-personal information (documents, parts, etc.)</li> -<li><code>OAuth2ReadPII</code> - Read personal information (name, email, etc.)</li> -<li><code>OAuth2Write</code> - Create and edit documents, etc.</li> -<li><code>OAuth2Delete</code> - Delete documents, etc.</li> -<li><code>OAuth2Purchase</code> - Authorize purchases from account</li> -</ul> -<h2 id="2-select-an-authentication-option">2. Select an Authentication Option</h2> -<p>Please select an option for authentication:</p> -<ul> -<li><a href="#local-authorization">Basic Authorization</a>: Lowest security. For local testing only.</li> -<li><a href="#request-signature">Request Signature</a>: Medium security. For testing and internal use.</li> -<li><a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>: Highest security. Required for all Onshape Apps.</li> -</ul> -<h2 id="basic-authorization">Basic Authorization</h2> -<p>For local testing, you can provide a basic authentication via your API Keys.</p> -<ol> -<li>Open your terminal and run the following command, replacing <code>ACCESS_KEY</code> and <code>SECRET_KEY</code> with the <strong>access key</strong> and <strong>secret key</strong> you created earlier. Remember to include the colon (<code>:</code>) between the keys. <em>You will receive a long, base-64-encoded string as output.</em> -<ul> -<li><strong>MacOS</strong>: -<pre tabindex="0"><code>printf ACCESS_KEY:SECRET_KEY | base64 -</code></pre></li> -<li><strong>Windows</strong>: -<pre tabindex="0"><code>powershell &#34;[convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\&#34;ACCESS_KEY:SECRET_KEY\&#34;))&#34; -</code></pre></li> -</ul> -</li> -<li>Add the authorization header to your code, replacing <code>CREDENTIALS</code> with the string you receieved in Step 1: -<pre tabindex="0"><code>-H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -</ol> -<p>See our <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start Guide</a> for an example of using Basic Authorization in an app.</p> -<h2 id="request-signature">Request Signature</h2> -<p>For additional security, you can include your API Keys as part of a request signature. This provides more security than the Basic Authorization above, but less security than OAuth2.</p> -<p>To ensure that a request is coming from you, we have a process for signing requests that you must follow for API calls to work. Everything is done via HTTP headers that you&rsquo;ll need to set:</p> -<ol> -<li><em>Date</em>: A standard date header giving the time of the request; must be accurate within <strong>5 minutes</strong> of request. Example: <code>Mon, 11 Apr 2016 20:08:56 GMT</code></li> -<li><em>On-Nonce</em>: A string that satisfies the following requirements (see the code for one possible way to generate it): -<ul> -<li>At least 16 characters</li> -<li>Alphanumeric</li> -<li>Unique for each request</li> -</ul> -</li> -<li><em>Authorization</em>: This is where the API keys come into play. You&rsquo;ll sign the request by implementing this algorithm: -<ul> -<li><strong>Input</strong>: Method, URL, On-Nonce, Date, Content-Type, AccessKey, SecretKey</li> -<li><strong>Output</strong>: String of the form: <code>On &lt;AccessKey&gt;:HmacSHA256:&lt;Signature&gt;</code></li> -<li><strong>Steps to generate the signature portion</strong>: -<ol> -<li>Parse the URL and get the following: -<ol> -<li>The path, e.g. <code>/api/documents</code> (no query params!)</li> -<li>The query string, e.g. <code>a=1&amp;b=2</code> -<ul> -<li>NOTE: If no query paramaters are present, use an empty string</li> -</ul> -</li> -</ol> -</li> -<li>Create a string by appending the following information in order. Each field should be separated by a newline (<code>\n</code>) character, and the string must be converted to lowercase: -<ol> -<li>HTTP method</li> -<li>On-Nonce header value</li> -<li>Date header value</li> -<li>Content-Type header value</li> -<li>URL pathname</li> -<li>URL query string</li> -</ol> -</li> -<li>Using SHA-256, generate an <a href="https://en.wikipedia.org/wiki/Hash-based_message_authentication_code" target="_blank">HMAC digest</a>, using the API secret key first and then the above string, then encode it in Base64.</li> -<li>Create the <code>On &lt;AccessKey&gt;:HmacSHA256:&lt;Signature&gt;</code> string and use that in the Authorization header in your request.</li> -</ol> -</li> -</ul> -</li> -</ol> -<p>Below is an example function to generate the authorization header, using Node.js&rsquo;s standard <code>crypto</code> and <code>url</code> libraries:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// ...at top of file -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">var</span> u = require(<span style="color:#a50">&#39;url&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">var</span> crypto = require(<span style="color:#a50">&#39;crypto&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* Generates the &#34;Authorization&#34; HTTP header for using the Onshape API -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} method - Request method; GET, POST, etc. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} url - The full request URL -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} nonce - 25-character nonce (generated by you) -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} authDate - UTC-formatted date string (generated by you) -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} contentType - Value of the &#34;Content-Type&#34; header; generally &#34;application/json&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} accessKey - API access key -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} secretKey - API secret key -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @return {string} Value for the &#34;Authorization&#34; header -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">*/</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">function</span> createSignature(method, url, nonce, authDate, contentType, accessKey, secretKey) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlObj = u.parse(url); -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlPath = urlObj.pathname; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlQuery = urlObj.query ? urlObj.query : <span style="color:#a50">&#39;&#39;</span>; <span style="color:#aaa;font-style:italic">// if no query, use empty string -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> str = (method + <span style="color:#a50">&#39;\n&#39;</span> + nonce + <span style="color:#a50">&#39;\n&#39;</span> + authDate + <span style="color:#a50">&#39;\n&#39;</span> + contentType + <span style="color:#a50">&#39;\n&#39;</span> + -</span></span><span style="display:flex;"><span> urlPath + <span style="color:#a50">&#39;\n&#39;</span> + urlQuery + <span style="color:#a50">&#39;\n&#39;</span>).toLowerCase(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> hmac = crypto.createHmac(<span style="color:#a50">&#39;sha256&#39;</span>, secretKey) -</span></span><span style="display:flex;"><span> .update(str) -</span></span><span style="display:flex;"><span> .digest(<span style="color:#a50">&#39;base64&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> signature = <span style="color:#a50">&#39;On &#39;</span> + accessKey + <span style="color:#a50">&#39;:HmacSHA256:&#39;</span> + hmac; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> signature; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h3 id="redirects">Redirects</h3> -<p>Some API endpoints return 307 redirects. You must generate an Authorization header for the redirect as well, but please note that the server portion of the URL might be different, the redirect URL may contain query parameters that must be encoded in the Authorization header, etc.</p> \ No newline at end of file +Authentication onhttps://onshape-public.github.io/docs/auth/Recent content in Authentication onHugoen-usMon, 18 May 2020 20:39:14 -0400OAuthhttps://onshape-public.github.io/docs/auth/oauth/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/auth/oauth/See the gltf-viewer-app for a working example of OAuth2. +📘 Note +All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.API Keyshttps://onshape-public.github.io/docs/auth/apikeys/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/auth/apikeys/📘 Note +All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys. \ No newline at end of file diff --git a/docs/auth/oauth/index.html b/docs/auth/oauth/index.html index d6af3a0..c0a35fd 100644 --- a/docs/auth/oauth/index.html +++ b/docs/auth/oauth/index.html @@ -1,14 +1,12 @@ -OAuth | OAuth |

    OAuth

    See the gltf-viewer-app for a working example of OAuth2.

    📘 Note

    All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

    What is OAuth2?

    The OAuth (Open authorization) protocol was developed by the Internet Engineering Task Force, an open standards organization that develops and promotes voluntary Internet standards (particularly the technical standards that comprise the Internet protocol suite) to enable secure, delegated access to an application’s resources.

    The OAuth2 protocol enables an application to access a resource that is under the control of someone else. In order to access that resource, a token is required. The token represent the delegated rights of access (that is, what rights this application has, such as read/write/update, scope, rights to different resources, and more).

    This means the application can be accessed by a third-party system without that system +All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.">

    OAuth

    See the gltf-viewer-app for a working example of OAuth2.

    📘 Note

    All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.

    What is OAuth2?

    The OAuth (Open authorization) protocol was developed by the Internet Engineering Task Force, an open standards organization that develops and promotes voluntary Internet standards (particularly the technical standards that comprise the Internet protocol suite) to enable secure, delegated access to an application’s resources.

    The OAuth2 protocol enables an application to access a resource that is under the control of someone else. In order to access that resource, a token is required. The token represent the delegated rights of access (that is, what rights this application has, such as read/write/update, scope, rights to different resources, and more).

    This means the application can be accessed by a third-party system without that system impersonating the user that controls the resource.

    A good analogy is the hotel check-in process. When you arrive at the front desk of a hotel, you provide an ID and a form of payment. Then, you are given a key card that opens a specific door. When you reach that door, you swipe your key card and are granted access. The door itself doesn’t know who you are or anything about you, it just knows that the key card was encoded correctly, and it allows you access. At some point, the key card expires, and the door no longer lets you into the room. This is the same for access tokens in the OAuth2 flow.

    With the OAuth2 protocol, you register your application with the third party, and you are given a set of keys. These keys get exchanged for an access token that grants you access to resources in the third-party application. The token expires regularly; you miust get a new token to access the application again. For this, you are provided with a refresh token. Sending the refresh token to the authentication server updates your access token and gives you a new refresh token.

    api token request diagram

    OAuth2 & Onshape

    The first step in the OAuth flow is for the Onshape user to request that Onshape let the third-party application access Onshape.

    Once the user has authorized the application, they are redirected to a predefined URL (called a redirect URL) with a code that will requests an access token from Onshape. Therefore, the redirect URL should contain a script that can capture the authorization code.

    You will use the access token to authenticate requests to the Onshape API. The token expires after preset amount of time. To get a new valid access token after one has expired, you must use the refresh token to request a new access token. Refreshing the access token also provides you with an updated refresh token to use in the next refresh access token request. Make sure to store both the the access token and the refresh token, and update them with each refresh of the token. The authorization token must accompany any call to the API, this is done by adding the token to an Authorization field in the header of each request:

    Authorization: Bearer <accessToken>
     

    If correctly authenticated, most responses from the REST API call return JSON data (though some return binary data), with an HTTP response code of 200 Success, 204 - No Content, or 301 - Permanent Redirect. 301 responses will include a redirect for you to follow.

    In the event that the authorization code is incorrect (for instance, if it expired), you will receive an HTTP 401 response. This response means that the client request has not been completed, since it lacks valid authentication credentials for the requested resource. In this event, your code for each call to the REST API should include a catch clause for a 401 exception. Once caught, you can refresh the token and make the request again. Pay close attention to the Content-Type header for what data to parse and expect.

    When integrating with Onshape, OAuth tokens give third-party applications (such as desktop applications or web services) access to users’ data as defined by the permissions scope (such as users’ documents or profile information). Using OAuth terminology, Onshape acts as both the authorization and resource server, while the desktop or web-based application is the client. Resource owners have the option of granting or denying access to applications.

    Once obtained, an OAuth token will work for third-party APIs under /api. Do NOT attempt to use an OAuth token to fetch the URLs typically displayed in a web browsers location bar.

    More resources

    • Digital Ocean - A good resource for learning more about OAuth2.
    • RFC 6749 - The reference for the OAuth framework as a whole. Most of this document describes how to implement the OAuth exchanges described by the reference within the context of Onshape and client applications.
    • RFC 6750 - Describes the exchange of OAuth access tokens between clients and OAuth servers.

    Implement OAuth2

    This OAuth tutorial demonstrates how to recreate the authentication process in Node.js found in the gltf-viewer-app sample code. The final code in Node.js and other languages can be found at the end of this page.

    1: Register the app

    1. Navigate to https://dev-portal.onshape.com/signin and sign in.
    2. In the left sidebar, click OAuth applications.
    3. Click the Create new OAuth application button.
    4. Fill out the form as follows:
      • Name: gltf-viewer-yourname
        • The application name to display to users.
        • Should include the name of your company to differentiate it from other possibly similar applications.
      • Primary format: com.yourname.gltf-viewer
        • String that uniquely identifies your application and is a marker for the data it might store on Onshape servers.
        • Cannot be changed after the application is registered.
      • Summary: Onshape OAuth tutorial
        • Description of your application.
        • Displayed to the user when they’re asked to grant the application permission to access their data.
      • Redirect URLs: http://localhost:5000/token
        • Your application must specify at least one URL used in the OAuth protocol exchanges.
        • This URL must also use SSL (a URL that begins with https), with two exceptions applicable for installed desktop applications: http://localhost:<port> and urn:ietf:wg:oauth:2.0:oob.
        • e.g., https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthRedirect
      • Admin team: No Team
        • Optional.
        • If defined, members of the team can make changes to the definition of this OAuth application.
        • See the Help Docs: Teams page for more information on creating teams in Onshape.
      • OAuth URL: none
        • Should contain the URL of your deployed application.
        • This is the first URL called from the Onshape Applications page.
        • The page hosted at this URL should handle the OAuth authentication. Once your application’s server has been authenticated on behalf of the user, that user should be redirected to your applications content.
        • If you have not deployed your app yet, you can leave this field blank (as shown in this example) for local work and update it later.
        • e.g., https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthSignin
      • Settings: check Supports collaboration
      • Permissions:
        • This is also called application scope, and it defines what access rights your application has to the user’s data.
        • Application can read your profile information - Enable your application to access the Onshape user profile. Check this option.
        • Application can read your documents - Onshape documents created by this user can be accessed with read privileges only. Check this option.
        • Application can write to your documents - The user-owned Onshape documents can be modified by this application. Check this option.
        • Application can delete documents and workspaces - Your application will be able to delete a workspace within a document or the complete Onshape document. Do not check this option for this example.
        • Application can request Purchases on Your behalf - The application will have access to make purchases if required. Do not check this option for this example.
        • Application can share and unshare documents on your behalf - Onshape’s document sharing capabilities are very powerful; they enable other parties to access your shared documents with @@ -337,4 +335,4 @@ if __name__ == "__main__": app.run() -
    \ No newline at end of file +
    \ No newline at end of file diff --git a/docs/changelog/index.html b/docs/changelog/index.html index 48a4b41..4fc3bae 100644 --- a/docs/changelog/index.html +++ b/docs/changelog/index.html @@ -1,4 +1 @@ -Changelog |

    Changelog

    rel-1.185 - released 2024-08-12

    • Updated all endpoints that return a user summary (createdBy, modifiedBy) have a new boolean property isOnshapeSupport for use to separate Onshape support employee activities.
    • Updated all bodyDetails, tessellatededged, and tessellatedfaces endpionts (parts and Part Studios) to include errorEnum vales for detecting new mate position, curve pattern and Simulation material checks.

    rel-1.184 - released 2024-07-19

    • Updated API version to V8, (https://cad.onshape.com/api/versions), A new microversion will not be created when a document restore operation results in a no-op.
    • Remove inconsistencies in assembly definition endpoint (/assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]) related to configuration parameters
    • Update all translation endpoints (POST : ../translations) to include new request property useFileNameToSetSinglePartName
    • Update all revision endpoints (GET : /revisions/..) to include response property canChangeType (supporting new admin option to change type part, assembly, file, etc)
    • Update GET : /users/[:uid]/settings endpoint to include responses for highlightLaminarEdges and perspectiveModeOn for default status

    rel-1.183 - released 2024-06-28

    • Added new V7 version to the api (https://cad.onshape.com/api/versions)
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches to return fully defined status (UNDERDEFINED, WELL_DEFINED, OVERDEFINED, UNKNOWN)
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches vectors are now maps instead of arrays, and may be BTVector2d or BTVector3d depending on the output3D parameter
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches to use more consistent naming:
    Fields
    sketch -> name
    sketchId -> featureId
    transformMatrix -> sketchMatrix
    featuresUsed -> featuresUsingSketch
    geomEntities -> entities
    • Updated GET : /variables endpoint to return variable description when variable is set through custom feature
    • Updated POST : /webhooks endpoint to default to isTransient = true if not specified (auto cleanup)
    • Updated descriptions for Assembly, Documents, Metadata, Parts, Part Studios, Revisions, Variables and Versions enddpoints

    rel-1.182 - released 2024-06-07

    • Updated descriptions for webhooks endpoints

    rel-1.181 - released 2024-05-17

    • Update Document, Assembly, Blob, Drawing and Part Studio translation POST endpoints to have a new request body property occurancesToExport
    • Update to /elements endpoint summary and descriptions in Glassworks
    • Updated documentation for webhooks (https://onshape-public.github.io/docs/app-dev/webhook/)

    rel-1.180 - released 2024-04-26

    rel-1.179 - released 2024-04-05

    • New drawing views list endpoint GET : /appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views
    • New drawing view endpoint GET : /appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views/[:viewid]/jsongeometry
    • New updated features endpoint documentation
    • Updated glassworks for all metadata endpoints to reference developer documentation
    • Added description of output to schema for Metadata APIs
    • Updated translation endpoints with new request property specifyMaterialData

    rel-1.178 - released 2024-03-15

    • Update Part Studio translation POST endpoint to have a new request body property importMaterialDensity
    • Update active workflow endpost GET: /workflow/active to have a new response property hasInactiveCustomWorkflows
    • Updated authorization (OAuth2 and BasicAuth) for publication endpoints
    • Various updates to descriptions of data types and query parameters
    • Fixed delete publication endpoint (HTTP::200 now removes publication)

    rel-1.177 - released 2024-02-23

    • Updated translation endpoints with new request property useIGESImportPostProcessing
    • Updated translation endpoints with modified request property stepParasolidPreprocessingOption
    • Updated descriptions for metadata | releasepackages for property propertyOverrideStatus

    rel-1.176 - released 2024-02-02

    • New create publication endpoint POST : /publications
    • New update publication endpoint POST: /publications/[:pid]
    • New delete publication endpoint DELETE: /publications/[:pid]
    • New create publication item endpoint POST : /publications/item
    • New update publication item endpoint POST: /publications/item/[:iid]
    • New delete publication item endpoint DELETE: /publications/item/[:iid]

    rel-1.175 - released 2024-01-12

    • Exclude suppressed sub assemblies from rootAssembly occurrences for GET: /assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]

    rel-1.174 - released 2023-12-15

    • Add microversion id the extension url [$microversionId]
    • Updated translation endpoints with new request property pdfVersion
    • Fixed issue with bodydetails endpoints always returning isInner and isOuter the same
    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new response body errorEnum:
    errorEnum
    BODY_DRAFT_STRAY_NONMITER_EDGES
    MASS_PROPERTY_FACES_NOT_COPLANAR
    PARAMETER_VALUE_INVALID
    SHEET_METAL_CHAMFER_NO_TANGENT_BASED
    CHAMFER_DIRECTION_OVERRIDE_NO_EFFECT
    FILLET_CHAMFER_UNSUPPORTED
    CHAMFER_HELD_BACK
    SWEEP_BAD_LOCK_DIRECTION
    SHEET_METAL_COUNTER_HOLE_UNSUPPORTED
    SWEEP_SELECT_DIRECTION
    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new property imageForeignId
    • Support sending a list of emails to POST : /classrooms/[cid]/members

    rel-1.173 - released 2023-11-28

    • Update all classroom endpoints (/classrooms/) to support OAuth
    • Add description of output to schema for getAssemblyShadedViews API

    rel-1.172 - released 2023-11-06

    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new response body errorEnum:
    errorEnum
    FIT_TOLERANCE_LIMITS_NOT_FOUND
    FIT_TOLERANCE_SIZE_TOO_LARGE_ISO
    FIT_TOLERANCE_SIZE_TOO_LARGE_ANSI
    OFFSET_WIRE_SHEET_CREATION_FAILED
    REPLACE_FACE_SHEET_SMALL
    REPLACE_FACES_NOT_ADJACENT
    SHEET_METAL_HOLE_REBUILD_FAILED
    CPLANE_TANGENT_INPUT
    CPLANE_TANGENT_SELECT_REFERENCE
    CNE_TANGENT_PLANE_INVALID
    CPLANE_TANGENT_POINT_INVALID
    REPLACE_FACES_NOT_SAME_BODY
    MUST_USE_DEFAULT_RADIUS_WITH_FACE_BEND
    CANNOT_RIP_A_FACE_BEND
    CANNOT_MAKE_A_FACE_BEND_TANGENT
    • References to API Guide for endpoint descriptions in Glassworks

    rel-1.171 - released 2023-10-13

    • Update all translation POST endpoints to have a new request body properties hideInspectionItems and textOption
    • Replaced GET : /releasepackages/companyreleaseworkflow | /workflow/active property canCurrentUserSyncVersionsToArena with canCurrentUserSyncStandardContentToArena
    • Updated GET and POST : /tabletemplates endpoint with new response property valueType
    • Comprehensive update to remaining endpoint summary and descriptions in Glassworks

    rel-1.170 - released 2023-09-22

    • New appelements delete subelement endpoint DELETE : /appelements/d/[did]/[wvm]/[wvmid]/e/[eid]/content/subelements
    • New company add new user endoint POST : /companies/[cid]/users
    • New company update user endoint POST : /companies/[cid]/users/[uid]
    • New company delete user endoint DELETE : /companies/[cid]/users/[uid]
    • Comprehensive update to remaining endpoint summary and descriptions in Glassworks

    rel-1.169 - released 2023-09-01

    • Comprehensive update to most endpoint summary and descriptions in Glassworks
    • Update all translation endpoints to include new property importAppearances
    • Update POST : /partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/featurescript has a new property expressionErrorInfo
    • Update GET and POST : /releasepackages/[rpid] property workflow/actions has a new enum value REASSIGN_TASK

    rel-1.168 - released 2023-08-11

    • Deprecated POST : /api/drawings/create -> Replaced with POST : /api/drawings/d/[did]/w/w/[wid]/create
    • Update GET : /api/documents endpoint has a new property publishedVersion
    • Update GET and POST : /api/releasepackages/[rpid] has a new property syncedWithPLM

    rel-1.167 - released 2023-07-21

    • Update glTF translation endpoints to use new field useGltfCompression (bool)
    • Update STEP translation endpoints to use new field stepParasolidPreprocessingOption (0-None, 1-Advanced, 2-Automatic, 3-Basic)
    • Update GET : /api/documents | /api/documents/[did] | /api/companies/[cid]/documentsbyname to include new field forceExportRules

    rel-1.165 - released 2023-06-12

    • Support partId array string for GET : /api/partstudios/bodydetails endpoint for the option of getting a subset of parts from a partstudio (empty = all parts)

    rel-1.163 - released 2023-04-28

    • Update documentation for the Documents endpoint (/api/documents)
    • Update Releasepackage endpoint GET : /api/releasepackage to include type to understand action (ie. Approve vs Reject)
    • Update API to V6 - Fix a bug in how updating the JSON tree of an app element in a transaction returns the diff

    rel-1.162 - released 2023-04-12

    • New Assembly modify endpoint POST : /api/assemblies/d/{did}/w/{wid}/e/{eid}/modify for bulk deletion and suppression of instances and features

    rel-1.161 - released 2023-03-20

    • New BOM templates endpoint (/api/tabletemplates)
    • Support POST /api/webhooks parameter isTransient = true to specify auto cleanup after a set number of days

    rel-1.160 - released 2023-02-24

    • Support configuratons for GET : /api/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features
    • Remove deprecated GET : /api/elements/:emid
    • Remove deprecated GET and POST : /api/elements/d/:did/[wvm]/:wvmid/e/:eid/metadata
    • Deprecated GET and POST : /api/parts/standardcontent/d/:did/v/:vid/e/:eid/[cu]/:cuid/partid/:pid/metadata
    • Deprecated GET and POST : /api/parts/d/:did/[wvm]/:wmvid/e/:eid/partid/:pid/metadata

    rel-1.158 - released 2023-01-11

    • New example values in Glassworks API documentation

    rel-1.155 - released 2022-11-01

    • Support Parasolid binary (x_b) exports

    rel-1.154 - released 2022-10-10

    • Add face color, hidden state and type of composite to body details endpoint

    rel-1.152 - released 2022-08-30

    • Support more parameters to filter the partstudio endpoint

    rel-1.147 - released 2022-05-16

    • Support global tree node endpoint for impacting recently opened filter

    rel-1.146 - released 2022-04-25

    • Support API versioning
    • Return ‘nodeId’ when adding or updating an AppElement

    rel-1.145 - released 2022-04-05

    • Fixed issue where assembly feature errors were missing

    rel-1.140 - released 2021-12-15

    • Add mass properties for assemblies

    rel-1.139 - released 2021-11-15

    • Relax casing search in Glassworks (Swagger client)
    • BOM and Metadata API endpoint responses now matched

    rel-1.138 - released 2021-10-25

    • Updated webhook documentation

    rel-1.135 - released 2021-8-20

    • Webhook events for Enterprise SSO configuration changes

    rel-1.134 - released 2021-07-30

    • Support comment events (add, update, delete) for the web-hook endpoint

    rel-1.131 - released 2021-06-01

    • Add synchronous glTF/gLB endpoint for assemblies

    rel-1.128 - released 2021-03-29

    • Support face color for export of glTF/gLB
    • Add document API endpoint for comments

    rel-1.127 - released 2021-03-08

    • Add translation option dtkPeriodicFacesPolicy=3 for CATIA parts

    rel-1.126 - released 2021-02-12

    • Add GLTF and GLB accepts option to the tessellation APIs

    rel-1.125 - released 2021-01-25

    • Add ‘good/better/best’ quality query parameters to tessellation endpoint

    rel-1.122 - released 2020-11-18

    • Enforce OAuth endpoint rate limiting
    • Add release package action/transition based webhooks

    rel-1.119 - released 2020-09-15

    • Add rollback bar to EvalFeatureScript endpoint

    rel-1.118 - released 2020-08-25

    • PartStudio GET support for sketch constraints in features endpoint

    rel-1.116 - released 2020-07-15

    • Specify starting elements to create document endpoint

    rel-1.114 - released 2020-06-03

    • Project endpoints

    rel-1.113 - released 2020-05-11

    • Output GLTF files for an element (tab)

    rel-1.111 - released 2020-03-31

    • Support ownership transfer for teams

    rel-1.110 - released 2020-03-09

    • Add support for exploded views

    rel-1.108 - released 2020-01-29

    • Drawings endpoints for create 4 view, get view geometry and view definition

    rel-1.102 - released 2019-09-11

    • Added webhook events for release management
    • Added webhook event for document version creation

    rel-1.99 - released 2019-07-08

    • Assembly BOM API support for items

    rel-1.96 - released 2019-05-03

    • Part Studio compare endpoint

    rel-1.93 - released 2019-03-01

    • Webhook subscriptions for a company

    rel-1.86 - released 2018-09-28

    • Export Drawings to DXF, DWG and PDF
    \ No newline at end of file +Changelog |

    Changelog

    rel-1.185 - released 2024-08-12

    • Updated all endpoints that return a user summary (createdBy, modifiedBy) have a new boolean property isOnshapeSupport for use to separate Onshape support employee activities.
    • Updated all bodyDetails, tessellatededged, and tessellatedfaces endpionts (parts and Part Studios) to include errorEnum vales for detecting new mate position, curve pattern and Simulation material checks.

    rel-1.184 - released 2024-07-19

    • Updated API version to V8, (https://cad.onshape.com/api/versions), A new microversion will not be created when a document restore operation results in a no-op.
    • Remove inconsistencies in assembly definition endpoint (/assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]) related to configuration parameters
    • Update all translation endpoints (POST : ../translations) to include new request property useFileNameToSetSinglePartName
    • Update all revision endpoints (GET : /revisions/..) to include response property canChangeType (supporting new admin option to change type part, assembly, file, etc)
    • Update GET : /users/[:uid]/settings endpoint to include responses for highlightLaminarEdges and perspectiveModeOn for default status

    rel-1.183 - released 2024-06-28

    • Added new V7 version to the api (https://cad.onshape.com/api/versions)
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches to return fully defined status (UNDERDEFINED, WELL_DEFINED, OVERDEFINED, UNKNOWN)
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches vectors are now maps instead of arrays, and may be BTVector2d or BTVector3d depending on the output3D parameter
    • Updated GET : V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches to use more consistent naming:
    Fields
    sketch -> name
    sketchId -> featureId
    transformMatrix -> sketchMatrix
    featuresUsed -> featuresUsingSketch
    geomEntities -> entities
    • Updated GET : /variables endpoint to return variable description when variable is set through custom feature
    • Updated POST : /webhooks endpoint to default to isTransient = true if not specified (auto cleanup)
    • Updated descriptions for Assembly, Documents, Metadata, Parts, Part Studios, Revisions, Variables and Versions enddpoints

    rel-1.182 - released 2024-06-07

    • Updated descriptions for webhooks endpoints

    rel-1.181 - released 2024-05-17

    • Update Document, Assembly, Blob, Drawing and Part Studio translation POST endpoints to have a new request body property occurancesToExport
    • Update to /elements endpoint summary and descriptions in Glassworks
    • Updated documentation for webhooks (https://onshape-public.github.io/docs/app-dev/webhook/)

    rel-1.180 - released 2024-04-26

    rel-1.179 - released 2024-04-05

    • New drawing views list endpoint GET : /appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views
    • New drawing view endpoint GET : /appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views/[:viewid]/jsongeometry
    • New updated features endpoint documentation
    • Updated glassworks for all metadata endpoints to reference developer documentation
    • Added description of output to schema for Metadata APIs
    • Updated translation endpoints with new request property specifyMaterialData

    rel-1.178 - released 2024-03-15

    • Update Part Studio translation POST endpoint to have a new request body property importMaterialDensity
    • Update active workflow endpost GET: /workflow/active to have a new response property hasInactiveCustomWorkflows
    • Updated authorization (OAuth2 and BasicAuth) for publication endpoints
    • Various updates to descriptions of data types and query parameters
    • Fixed delete publication endpoint (HTTP::200 now removes publication)

    rel-1.177 - released 2024-02-23

    • Updated translation endpoints with new request property useIGESImportPostProcessing
    • Updated translation endpoints with modified request property stepParasolidPreprocessingOption
    • Updated descriptions for metadata | releasepackages for property propertyOverrideStatus

    rel-1.176 - released 2024-02-02

    • New create publication endpoint POST : /publications
    • New update publication endpoint POST: /publications/[:pid]
    • New delete publication endpoint DELETE: /publications/[:pid]
    • New create publication item endpoint POST : /publications/item
    • New update publication item endpoint POST: /publications/item/[:iid]
    • New delete publication item endpoint DELETE: /publications/item/[:iid]

    rel-1.175 - released 2024-01-12

    • Exclude suppressed sub assemblies from rootAssembly occurrences for GET: /assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]

    rel-1.174 - released 2023-12-15

    • Add microversion id the extension url [$microversionId]
    • Updated translation endpoints with new request property pdfVersion
    • Fixed issue with bodydetails endpoints always returning isInner and isOuter the same
    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new response body errorEnum:
    errorEnum
    BODY_DRAFT_STRAY_NONMITER_EDGES
    MASS_PROPERTY_FACES_NOT_COPLANAR
    PARAMETER_VALUE_INVALID
    SHEET_METAL_CHAMFER_NO_TANGENT_BASED
    CHAMFER_DIRECTION_OVERRIDE_NO_EFFECT
    FILLET_CHAMFER_UNSUPPORTED
    CHAMFER_HELD_BACK
    SWEEP_BAD_LOCK_DIRECTION
    SHEET_METAL_COUNTER_HOLE_UNSUPPORTED
    SWEEP_SELECT_DIRECTION
    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new property imageForeignId
    • Support sending a list of emails to POST : /classrooms/[cid]/members

    rel-1.173 - released 2023-11-28

    • Update all classroom endpoints (/classrooms/) to support OAuth
    • Add description of output to schema for getAssemblyShadedViews API

    rel-1.172 - released 2023-11-06

    • Update all endpoints for bodydetails | tessellatededges | tessellatedfaces | featurescript to include new response body errorEnum:
    errorEnum
    FIT_TOLERANCE_LIMITS_NOT_FOUND
    FIT_TOLERANCE_SIZE_TOO_LARGE_ISO
    FIT_TOLERANCE_SIZE_TOO_LARGE_ANSI
    OFFSET_WIRE_SHEET_CREATION_FAILED
    REPLACE_FACE_SHEET_SMALL
    REPLACE_FACES_NOT_ADJACENT
    SHEET_METAL_HOLE_REBUILD_FAILED
    CPLANE_TANGENT_INPUT
    CPLANE_TANGENT_SELECT_REFERENCE
    CNE_TANGENT_PLANE_INVALID
    CPLANE_TANGENT_POINT_INVALID
    REPLACE_FACES_NOT_SAME_BODY
    MUST_USE_DEFAULT_RADIUS_WITH_FACE_BEND
    CANNOT_RIP_A_FACE_BEND
    CANNOT_MAKE_A_FACE_BEND_TANGENT
    • References to API Guide for endpoint descriptions in Glassworks

    rel-1.171 - released 2023-10-13

    • Update all translation POST endpoints to have a new request body properties hideInspectionItems and textOption
    • Replaced GET : /releasepackages/companyreleaseworkflow | /workflow/active property canCurrentUserSyncVersionsToArena with canCurrentUserSyncStandardContentToArena
    • Updated GET and POST : /tabletemplates endpoint with new response property valueType
    • Comprehensive update to remaining endpoint summary and descriptions in Glassworks

    rel-1.170 - released 2023-09-22

    • New appelements delete subelement endpoint DELETE : /appelements/d/[did]/[wvm]/[wvmid]/e/[eid]/content/subelements
    • New company add new user endoint POST : /companies/[cid]/users
    • New company update user endoint POST : /companies/[cid]/users/[uid]
    • New company delete user endoint DELETE : /companies/[cid]/users/[uid]
    • Comprehensive update to remaining endpoint summary and descriptions in Glassworks

    rel-1.169 - released 2023-09-01

    • Comprehensive update to most endpoint summary and descriptions in Glassworks
    • Update all translation endpoints to include new property importAppearances
    • Update POST : /partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/featurescript has a new property expressionErrorInfo
    • Update GET and POST : /releasepackages/[rpid] property workflow/actions has a new enum value REASSIGN_TASK

    rel-1.168 - released 2023-08-11

    • Deprecated POST : /api/drawings/create -> Replaced with POST : /api/drawings/d/[did]/w/w/[wid]/create
    • Update GET : /api/documents endpoint has a new property publishedVersion
    • Update GET and POST : /api/releasepackages/[rpid] has a new property syncedWithPLM

    rel-1.167 - released 2023-07-21

    • Update glTF translation endpoints to use new field useGltfCompression (bool)
    • Update STEP translation endpoints to use new field stepParasolidPreprocessingOption (0-None, 1-Advanced, 2-Automatic, 3-Basic)
    • Update GET : /api/documents | /api/documents/[did] | /api/companies/[cid]/documentsbyname to include new field forceExportRules

    rel-1.165 - released 2023-06-12

    • Support partId array string for GET : /api/partstudios/bodydetails endpoint for the option of getting a subset of parts from a partstudio (empty = all parts)

    rel-1.163 - released 2023-04-28

    • Update documentation for the Documents endpoint (/api/documents)
    • Update Releasepackage endpoint GET : /api/releasepackage to include type to understand action (ie. Approve vs Reject)
    • Update API to V6 - Fix a bug in how updating the JSON tree of an app element in a transaction returns the diff

    rel-1.162 - released 2023-04-12

    • New Assembly modify endpoint POST : /api/assemblies/d/{did}/w/{wid}/e/{eid}/modify for bulk deletion and suppression of instances and features

    rel-1.161 - released 2023-03-20

    • New BOM templates endpoint (/api/tabletemplates)
    • Support POST /api/webhooks parameter isTransient = true to specify auto cleanup after a set number of days

    rel-1.160 - released 2023-02-24

    • Support configuratons for GET : /api/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features
    • Remove deprecated GET : /api/elements/:emid
    • Remove deprecated GET and POST : /api/elements/d/:did/[wvm]/:wvmid/e/:eid/metadata
    • Deprecated GET and POST : /api/parts/standardcontent/d/:did/v/:vid/e/:eid/[cu]/:cuid/partid/:pid/metadata
    • Deprecated GET and POST : /api/parts/d/:did/[wvm]/:wmvid/e/:eid/partid/:pid/metadata

    rel-1.158 - released 2023-01-11

    • New example values in Glassworks API documentation

    rel-1.155 - released 2022-11-01

    • Support Parasolid binary (x_b) exports

    rel-1.154 - released 2022-10-10

    • Add face color, hidden state and type of composite to body details endpoint

    rel-1.152 - released 2022-08-30

    • Support more parameters to filter the partstudio endpoint

    rel-1.147 - released 2022-05-16

    • Support global tree node endpoint for impacting recently opened filter

    rel-1.146 - released 2022-04-25

    • Support API versioning
    • Return ‘nodeId’ when adding or updating an AppElement

    rel-1.145 - released 2022-04-05

    • Fixed issue where assembly feature errors were missing

    rel-1.140 - released 2021-12-15

    • Add mass properties for assemblies

    rel-1.139 - released 2021-11-15

    • Relax casing search in Glassworks (Swagger client)
    • BOM and Metadata API endpoint responses now matched

    rel-1.138 - released 2021-10-25

    • Updated webhook documentation

    rel-1.135 - released 2021-8-20

    • Webhook events for Enterprise SSO configuration changes

    rel-1.134 - released 2021-07-30

    • Support comment events (add, update, delete) for the web-hook endpoint

    rel-1.131 - released 2021-06-01

    • Add synchronous glTF/gLB endpoint for assemblies

    rel-1.128 - released 2021-03-29

    • Support face color for export of glTF/gLB
    • Add document API endpoint for comments

    rel-1.127 - released 2021-03-08

    • Add translation option dtkPeriodicFacesPolicy=3 for CATIA parts

    rel-1.126 - released 2021-02-12

    • Add GLTF and GLB accepts option to the tessellation APIs

    rel-1.125 - released 2021-01-25

    • Add ‘good/better/best’ quality query parameters to tessellation endpoint

    rel-1.122 - released 2020-11-18

    • Enforce OAuth endpoint rate limiting
    • Add release package action/transition based webhooks

    rel-1.119 - released 2020-09-15

    • Add rollback bar to EvalFeatureScript endpoint

    rel-1.118 - released 2020-08-25

    • PartStudio GET support for sketch constraints in features endpoint

    rel-1.116 - released 2020-07-15

    • Specify starting elements to create document endpoint

    rel-1.114 - released 2020-06-03

    • Project endpoints

    rel-1.113 - released 2020-05-11

    • Output GLTF files for an element (tab)

    rel-1.111 - released 2020-03-31

    • Support ownership transfer for teams

    rel-1.110 - released 2020-03-09

    • Add support for exploded views

    rel-1.108 - released 2020-01-29

    • Drawings endpoints for create 4 view, get view geometry and view definition

    rel-1.102 - released 2019-09-11

    • Added webhook events for release management
    • Added webhook event for document version creation

    rel-1.99 - released 2019-07-08

    • Assembly BOM API support for items

    rel-1.96 - released 2019-05-03

    • Part Studio compare endpoint

    rel-1.93 - released 2019-03-01

    • Webhook subscriptions for a company

    rel-1.86 - released 2018-09-28

    • Export Drawings to DXF, DWG and PDF
    \ No newline at end of file diff --git a/docs/help/index.html b/docs/help/index.html index 669d563..eaaefa7 100644 --- a/docs/help/index.html +++ b/docs/help/index.html @@ -1,3 +1,7 @@ -Get Help |

    Get Help

    Onshape Help

    See the Onshape Help Docs at https://cad.onshape.com/help/Content (or https://<companyName>.onshape.com/help/Content for Enterprise accounts).

    Contact Us

    You can contact the Onshape API Support team at api-support@onshape.com, or browse through our FAQs and troubleshooting tips below.

    FAQs

    What is the user experience of granting and revoking OAuth access?

    Once users have purchased the application from the App Store, they will start seeing actions and panel icons as described by the extensions. When they try to use these actions and panels, they will be prompted by an error message stating that they need to grant access first.

    They can grant access by navigating to the ‘Applications’ section under ‘My Account’.

    image alt text

    Users will have to grant 2 permissions. The first button called ‘Onshape access’ will enable the application to make calls to the Onshape API. This will require the user’s Onshape credentials.

    The second button calls ‘External access’ and enables Onshape to make calls to the application API. This will require the user’s credentials in the application. Both modes of access use OAuth, so credentials are not stored in the other system.

    If the access is revoked at any time, the actions and panels will ask the user to re-authenticate from the ‘Applications’ page. Access may be revoked manually from Onshape or the application, or because a new version is installed that requires a different scope.

    Who can get access to my app, and how?

    Applications with extensions are only available to people who have been explicitly granted this permission in Onshape. Users who have been given this permission will be able to go to the App Store and purchase the application. There is no change to this process from earlier. They will then be able to grant access to the application as described in the previous question.

    Do not publish your application if it contains extensions in the App Store for all users. Other users (who have not been granted permission) will not be able to see the extensions and will have a bad experience.

    How is my application informed about selection changes in the Onshape UI?

    Let’s take the case where your application has an extension that is showing some information in the document info panel that is based on document selection. As the selection changes, the action URL passed to the extension will change (based on parameterization). The new action URL will be loaded into the IFrame for the extension, and the application page will reload. We are adding support for post messages to reduce loading overhead in the future.

    What is the timeout for the action_url of extensions? Is it configurable?

    Timeout set for each GET or POST request set as action_url of an extension is 180 seconds. Timeout is not configurable.

    What changed when my legacy application migrated to extensions?

    If you had created a desktop or connected ckoud app, nothing has changed.

    If you had created an integrated cloud app, the following changes have been made to the app.

    • The IFrame URL has been changed to the OAuth URL. This is now invoked from the user’s application setting page to grant OAuth access. A redirect URL is passed along with the call as a query parameter named ‘redirectOnshapeUri’. You will need to modify your code to redirect to this URL if it is present.
    • A new tab extension is automatically created for your applications. The target URL for this extension is the earlier IFrame URL. This should continue to work as earlier.
    • The tab icon will also be populated into the extension from the earlier application icon and should work as earlier.
    \ No newline at end of file +Get Help |

    Get Help

    Onshape Help

    See the Onshape Help Docs at https://cad.onshape.com/help/Content (or https://<companyName>.onshape.com/help/Content for Enterprise accounts).

    Contact Us

    You can contact the Onshape API Support team at api-support@onshape.com, or browse through our FAQs and troubleshooting tips below.

    FAQs

    What is the user experience of granting and revoking OAuth access?

    Once users have purchased the application from the App Store, they will start seeing actions and panel icons as described by the extensions. When they try to use these actions and panels, they will be prompted by an error message stating that they need to grant access first.

    They can grant access by navigating to the ‘Applications’ section under ‘My Account’.

    image alt text

    Users will have to grant 2 permissions. The first button called ‘Onshape access’ will enable the application to make calls to the Onshape API. This will require the user’s Onshape credentials.

    The second button calls ‘External access’ and enables Onshape to make calls to the application API. This will require the user’s credentials in the application. Both modes of access use OAuth, so credentials are not stored in the other system.

    If the access is revoked at any time, the actions and panels will ask the user to re-authenticate from the ‘Applications’ page. Access may be revoked manually from Onshape or the application, or because a new version is installed that requires a different scope.

    Who can get access to my app, and how?

    Applications with extensions are only available to people who have been explicitly granted this permission in Onshape. Users who have been given this permission will be able to go to the App Store and purchase the application. There is no change to this process from earlier. They will then be able to grant access to the application as described in the previous question.

    Do not publish your application if it contains extensions in the App Store for all users. Other users (who have not been granted permission) will not be able to see the extensions and will have a bad experience.

    How is my application informed about selection changes in the Onshape UI?

    Let’s take the case where your application has an extension that is showing some information in the document info panel that is based on document selection. As the selection changes, the action URL passed to the extension will change (based on parameterization). The new action URL will be loaded into the IFrame for the extension, and the application page will reload. We are adding support for post messages to reduce loading overhead in the future.

    What is the timeout for the action_url of extensions? Is it configurable?

    Timeout set for each GET or POST request set as action_url of an extension is 180 seconds. Timeout is not configurable.

    What changed when my legacy application migrated to extensions?

    If you had created a desktop or connected ckoud app, nothing has changed.

    If you had created an integrated cloud app, the following changes have been made to the app.

    • The IFrame URL has been changed to the OAuth URL. This is now invoked from the user’s application setting page to grant OAuth access. A redirect URL is passed along with the call as a query parameter named ‘redirectOnshapeUri’. You will need to modify your code to redirect to this URL if it is present.
    • A new tab extension is automatically created for your applications. The target URL for this extension is the earlier IFrame URL. This should continue to work as earlier.
    • The tab icon will also be populated into the extension from the earlier application icon and should work as earlier.
    \ No newline at end of file diff --git a/docs/help/index.xml b/docs/help/index.xml index 5788bb3..39a0738 100644 --- a/docs/help/index.xml +++ b/docs/help/index.xml @@ -1 +1 @@ -– Get Helphttps://onshape-public.github.io/docs/help/Recent content in Get Help onHugo -- gohugo.ioen-usMon, 18 May 2020 20:25:28 -0400 \ No newline at end of file +Get Help onhttps://onshape-public.github.io/docs/help/Recent content in Get Help onHugoen-us \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 7e1bfe2..39c41a7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,2 +1,4 @@ -Welcome to the Onshape Developer Documentation |

    Welcome to the Onshape Developer Documentation

    Welcome to the Onshape Developer Documentation. You can find resources here for developing applications that integrate with Onshape. Use the navigation bar on the left to navigate through the documentation.

    \ No newline at end of file +Welcome to the Onshape Developer Documentation |

    Welcome to the Onshape Developer Documentation

    Welcome to the Onshape Developer Documentation. You can find resources here for developing applications that integrate with Onshape. Use the navigation bar on the left to navigate through the documentation.

    \ No newline at end of file diff --git a/docs/index.xml b/docs/index.xml index 7d7928b..50245ce 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -1,7756 +1 @@ -– Welcome to the Onshape Developer Documentationhttps://onshape-public.github.io/docs/Recent content in Welcome to the Onshape Developer Documentation onHugo -- gohugo.ioen-usThu, 15 Aug 2024 00:00:00 +0000Docs: API Explorerhttps://onshape-public.github.io/docs/api-intro/explorer/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/explorer/ -<p>We document all available Onshape REST API endpoints in our Glassworks API Explorer:</p> -<p><b><font size="5"><a href="https://cad.onshape.com/glassworks/explorer/">https://cad.onshape.com/glassworks/explorer/</a></font></b></p> -<hr> -<p>This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below:</p> -<ol> -<li>Open this public Onshape document in your browser: -<font size="1"><a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22</a></font></li> -<li>Open the API Explorer in a new browser tab: <a href="https://cad.onshape.com/glassworks/explorer/">https://cad.onshape.com/glassworks/explorer/</a> -<ul> -<li>Note: For Enterprise accounts, substitue <code>cad</code> in this URL with your company name.</li> -</ul> -</li> -<li>Scroll down to <a href="https://cad.onshape.com/glassworks/explorer/#/Document">Document</a>.</li> -<li>Click to expand the <a href="https://cad.onshape.com/glassworks/explorer/#/Document/getDocument"><code>getDocument</code></a> endpoint. (Hint: it appears in the API Ref as <code>GET /documents/{did}</code>).</li> -<li>Go back to the public document you opened in Step 2, and copy the document ID from the Onshape URL (<code>e60c4803eaf2ac8be492c18e</code>). -<img src="https://onshape-public.github.io/images/OnshapeAPIGuidePublicDoc.png" alt="image"></li> -<li>Paste the document ID into the <code>did</code> field in the API Explorer. -<ul> -<li>Note: If you can&rsquo;t edit the <code>did</code> field, click the <strong>Try it out</strong> button. This will toggle to a <strong>Cancel</strong> button when the fields are editable.</li> -</ul> -</li> -<li>Scroll down and click <strong>Execute</strong>. -<ul> -<li>Note: If you receive a <code>403</code> error, see the <a href="#authentication">Authentication</a> section for help.</li> -</ul> -</li> -<li>Scroll to the bottom of the 200 response body. We have correctly returned <code>Onshape API Guide</code> as the document name.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/GlassworksAPIExplorerDemo.gif" alt="gif of using glassworks"></p> -<p><strong>IMPORTANT NOTE</strong>: The documentation in the API Explorer reflects the supported interface. Some API calls may, for historical reasons, return additional undocumented fields. Unless the return fields are documented in the API Explorer, you should NOT use them, as they may be removed without warning. Your application should always ignore unexpected or undocumented return data. Onshape reserves the right to add, remove or change any undocumented fields.</p> -<h3 id="authentication">Authentication</h3> -<p>You can authenticate in the API Explorer in one of three ways:</p> -<ol> -<li><strong>Onshape</strong>: -<ol> -<li>Open Onshape in a new tab in your browser.</li> -<li>Sign in with your Onshape credentials. Onshape will pass your credentials to the API Explorer.</li> -</ol> -</li> -<li><strong>API Keys</strong>: -<ol> -<li>Click <strong>Authorize</strong> in the top-right of the API Explorer page and scroll to the bottom of the dialog. -</br><img src="https://onshape-public.github.io/images/glassworks-auth-button.png" alt="Glassworks Authorize button" width=175></li> -<li>Provide your API access key in the Username field and your secret key in the Password field. See <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> for help creating your API Keys. Do NOT enter your Onshape credentials. -</br><img style='border:.7px solid #808080' src="https://onshape-public.github.io/images/ApiExplorerBasicAuth.png" alt="drawing" width="500"/></li> -<li>Click <strong>Authorize</strong>, and then click <strong>Close</strong>.</li> -</ol> -</li> -<li><strong>Oauth</strong>: -<ol> -<li>Click <strong>Authorize</strong> in the top-right of the API Explorer page. -</br><img src="https://onshape-public.github.io/images/glassworks-auth-button.png" alt="Glassworks Authorize button" width=175></li> -<li>Fill out the OAuth fields. See <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth</a> for more information on autheneticating with OAuth2.</li> -<li>Click <strong>Authorize</strong>, and then click <strong>Close</strong>.</li> -</ol> -</li> -</ol> -<h3 id="use-the-auto-fill-feature">Use the Auto-fill feature</h3> -<ol> -<li>Expand the endpoint you want to use in the API Explorer.</li> -<li>Paste an entire Onshape URL into the top field.</li> -<li>Click <strong>Auto-fill</strong>. The document ID, workspace/version/microversion ID, and element ID are pushed from the URL into the correct fields.</li> -<li>Confirm all fields are filled out as expected. Not every parameter can be extracted from an Onshape URL, so there may be more fields to fill out.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/GlassworksAutofill.png" alt="glassworks api explorer auto fill feature"></p> -<h3 id="view-response-body-docs">View response body docs</h3> -<ol> -<li>Expand the endpoint you want to use the in API Explorer.</li> -<li>Scroll down to the Responses section.</li> -<li>Click Schema.</li> -<li>Click the <code>[...]</code> symbols to expand the docs for the response JSON.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerResponseJSON.png" alt="glassworks api explorer response json docs"></p> -<h3 id="view-request-body-docs">View request body docs</h3> -<ol> -<li>Expand the endpoint you want to use the in API Explorer.</li> -<li><strong>Click the <em>Cancel</em> button to make the schema viewable.</strong></li> -<li>Click Schema.</li> -<li>Click the <code>[...]</code> symbols to expand the docs for the response JSON.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerRequestJSON.png" alt="glassworks api explorer response json docs"></p> -<h3 id="copy-a-curl">Copy a cURL</h3> -<ol> -<li>Expand the endpoint you want to use in the API Explorer.</li> -<li>Fill out the parameter fields.</li> -<li>Click Execute in the API Explorer.</li> -<li>Copy the curl from the Curl field.</li> -</ol> -<p><img src="https://onshape-public.github.io/images/APIExplorerCopyCurl.png" alt="api explorer curl copy"></p> -<h3 id="troubleshooting">Troubleshooting</h3> -<ul> -<li>If the parameter fields in the API Explorer are grayed out, click the <strong>Try it Out!</strong> button to toggle it to a <strong>Cancel</strong> button. The parameter fields should become editable.</li> -<li>If you can&rsquo;t see the request body JSON docs, click the <strong>Cancel</strong> button to toggle it back to the <strong>Try it Out!</strong> button.</li> -<li>If you see authentication issues, review the <a href="#authentication">Authentication</a> section above.</li> -</ul>Docs: Architecturehttps://onshape-public.github.io/docs/api-intro/architecture/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/architecture/ -<p>Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also:</p> -<ul> -<li>The <a href="https://onshape-public.github.io/docs/api-intro/">API Introduction</a> page for information on how documents, workspaces, and elements are assembled into a URL.</li> -<li>The <a href="https://onshape-public.github.io/docs/api-adv/associativity">Associativity</a> page for information on how Parts, Assemblies, and Elements relate to each other.</li> -</ul> -<h2 id="elements">Elements</h2> -<p>All data in an Onshape document are stored in Elements (represented as tabs in the user interface). Onshape documents contain five kinds of elements:</p> -<ul> -<li><strong>Part Studio</strong>: Contains zero or more parts</li> -<li><strong>Assembly</strong>: Contains zero or more parts or assemblies</li> -<li><strong>Blob</strong> (Binary Large OBject): Can be provided by a partner or by the end user. For example, the user can upload a PDF file, an image, or a text file. Partner applications can store arbitrary data, but we recommend using the <a href="https://onshape-public.github.io/docs/app-dev/structuredstorage">structured storage</a> available in an element for better integration.</li> -<li><strong>Application</strong>: Presents an iframe to the user. The user interface is managed by a server that can be provided by a third-party. Onshape Drawings are a special case of an application element.</li> -<li><strong>Feature Studio</strong>: Contains the definition for Onshape Features, which are defined in FeatureScript.</li> -</ul> -<h2 id="workspaces-versions-and-microversions">Workspaces, Versions, and Microversions</h2> -<p>A document is stored in Onshape as a collection of changes.</p> -<ul> -<li>You can think of a <strong>workspace</strong> as a branch of the document, similar to a branch in a source control system. Documents can be branched to create new workspaces.</li> -<li>Each individual change to the document creates a new document <strong>microversion</strong>. As the document is edited, changes are applied to the active workspace, creating new microversions.</li> -<li>Periodically, the user may designate versions of the document. A <strong>version</strong> is a named snapshot of the entire document at some point in time (that is, at some microversion).</li> -</ul> -<p>You cannot change a version or microversion of a document; all changes are applied to a workspace (and create a new microversion). Thus, while in general the <code>GET</code> methods of the API can read from a version, microversion, or workspace, the <code>POST</code> methods generally require a workspace, and create a new microversion when data is written to the document. (An exception is that it is possible to set metadata within a version; this does not create a new microversion).</p> -<p>The following IDs are used by many of the APIs. Each ID (except for Geometry IDs such as Part, Face and Edge) is a 24-character string that is used internally by Onshape to uniquely identify the resource. The Geometry IDs are variable-length strings used to resolve to a specific geometric entity within a model.</p> -<table> -<thead> -<tr> -<th>ID</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td><strong>User ID</strong></td> -<td>Identifies a single user.</td> -</tr> -<tr> -<td><strong>Document ID</strong></td> -<td>Identifies a document. The logged-in user must have access to the requested document for the API to succeed.</td> -</tr> -<tr> -<td><strong>Workspace ID</strong></td> -<td>The Workspace ID identifies a workspace within the document. Workspaces are used to distinguish between different branches of the document.</td> -</tr> -<tr> -<td><strong>Version ID</strong></td> -<td>The Version ID identifies a specific named version.</td> -</tr> -<tr> -<td><strong>Microversion ID</strong></td> -<td>The Microversion ID identifies an internal revision of the document.</td> -</tr> -<tr> -<td><strong>Element ID</strong></td> -<td>The Element ID identifies an element within the document.</td> -</tr> -<tr> -<td><strong>Part ID </br> Face ID </br> Edge ID</strong></td> -<td>The Part ID identifies a part within a part studio. The Part ID should generally not be stored for long-term use, as it is only expected to be valid during the course of a session.</td> -</tr> -</tbody> -</table> -<p>Note that a Part ID may reference a part that no longer exists if the model is changed, so it is best to specify a Version or Microversion to pick the context for the Part ID. Note that even with the Version or Microversion, internal changes to the Onshape system may also change the Part ID. Onshape provides mechanisms for maintaining persistent references. See the <a href="https://onshape-public.github.io/docs/api-adv/associativity">Associativity</a> page for more information. Face and Edge IDs are used in similar ways.</p> -<p>The following table identifies Onshape concepts and the corresponding Git concepts. Note that this is not a direct mapping, and the implementation of the concepts is very different.</p> -<table> -<thead> -<tr> -<th>Onshape concept</th> -<th>Git concept</th> -</tr> -</thead> -<tbody> -<tr> -<td>Document</td> -<td>Repository</td> -</tr> -<tr> -<td>Element</td> -<td>File</td> -</tr> -<tr> -<td>Workspace</td> -<td>Branch</td> -</tr> -<tr> -<td>Version</td> -<td>Tag</td> -</tr> -<tr> -<td>Microversion</td> -<td>Commit</td> -</tr> -</tbody> -</table> -<h2 id="linked-documents">Linked Documents</h2> -<p>Although a document can contain a complex model tree involving many Part Studio and Assembly elements, it is often more efficient to split the content into multiple documents. Connections between documents always refer to a specific version of the target document. <em>Once a version is used as the target of a linked document, that document version is preserved as long as any document references it, even if the containing document is deleted.</em> Additionally, any user that has access to the referring document will have limited read access to the target document, regardless of what permissions are currently on the target document.</p> -<h2 id="configurations">Configurations</h2> -<p>Onshape Part Studios can be constructed to be configurable using Onshape Configurations. API calls that reference Part Studios (primarily within the <a href="https://cad.onshape.com/glassworks/explorer/#/Part">Parts</a> and <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">Part Studios</a> APIs) often accept a <code>configuration</code> parameter that identifies what specific configuration of the Part Studios is being referenced. When not specified, the API implementation typically uses the configuration that is currently selected within the Part Studio. An interactive ad-hoc API call might not behave consistently in an application, so be sure to specify the configuration parameter where applicable.</p> -<h2 id="onshape-data-model">Onshape Data Model</h2> -<p>Onshape data is stored in replicated databases in the cloud. The Onshape data model is influenced by the Git data model and similar source code repositories.</p> -<p>Documents contain <strong>elements</strong>. Elements are presented as tabs in the user interface. With some exceptions, all data in a document is stored within an element. The following table describes what data stored in each Element type:</p> -<table> -<thead> -<tr> -<th>Element Type</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td><strong>Part Studio</strong></td> -<td>Each Part Studio contains exactly one Feature list. The Feature list contains Features such as sketches, planes, extrudes, etc. Each Feature contains one or parameters. Whenever the Feature list changes, the parametric history is evaluated, and the model is regenerated.</td> -</tr> -<tr> -<td><strong>Assembly</strong></td> -<td>Each Assembly contains an assembly tree, which contains parts and/or other assemblies (sub-assemblies), along with mate information. Onshape provides an API call to retrieve the assembly tree definition.</td> -</tr> -<tr> -<td><strong>Blob</strong></td> -<td>Each Blob element contains an uninterpreted binary object that has been uploaded to Onshape, typically from a file. Onshape depends on the browser client to display some blob data (e.g., PDF and image data), but does not interpret the data. A blob element can be updated with new data.</td> -</tr> -<tr> -<td><strong>Application</strong></td> -<td>Each Application element contains zero or more sub-elements, providing a structured set of transactional data that is defined and managed by an application. Application data can be displayed in the Onshape tab in an iframe; the application is responsible for rendering the data in the iframe from its server.</td> -</tr> -</tbody> -</table> -<p>Note that Onshape Drawing elements are Application elements managed by Onshape.</p> -<p>Tessellated data is not stored persistently in Onshape; it is generated on demand for display by the Onshape clients, or in response to application REST API requests. This data may be cached for performance.</p> -<h3 id="document-data">Document data</h3> -<p>All elements, including Assemblies, Part Studios, Drawings, or even apps, are history based. Each change to an element or set of elements represents a unique record in the document’s history, known as a microversion. The document can be restored to that particular state any time in the future.</p> -<h3 id="part-studio-data">Part Studio data</h3> -<p>The Part Studio element is defined by a list of features, some of which (e.g., a sketch), may have a complex internal structure composed of entities. Part Studio features and entities are referenced by unique persistent identifiers. Part Studio features and entities can appear, disappear, and reappear depending on the current microversion of the model.</p> -<h3 id="assembly-data">Assembly data</h3> -<p>The Assembly element is defined as a list of assembly features and a tree of subassemblies/part instances. Occurrence ID is a unique persistent identifier of an occurrence of a part in the assembly structure.</p> -<h3 id="external-application-data">External application data</h3> -<p>An external application has complete control over how it manages/stores documents, however, to take advantage of the Onshape data model, there is a set of endpoints they should use to store state. These are collectively known as the AppElement API.</p> -<h3 id="model-presentation-data">Model presentation data</h3> -<p>A valid model definition usually corresponds to a real-world manufacturable topology, represented internally as a set of parts, faces, edges, and vertices and the set of relations between them. Each of these has a unique identifier in every state of the model. The identifier represents an encoded index in the model’s history, and its value depends on the structure of the model’s history. The value is not guaranteed to be preserved across model changes, and will almost always change if the model changes in significant ways. The model can be tessellated into a set of geometric primitives, which approximate the shape of the model. Tessellated data can be used for visual representation of the model or other processing related to the shape of the model.</p> -<p>The following changes in the topological representation can occur between two microversions of the model:</p> -<ul> -<li>New topological entities appear</li> -<li>Id of existing topology change</li> -<li>Topological entities disappear</li> -<li>Existing topological entities are merged into a single entity</li> -<li>Existing topological entity are split into multiple entities</li> -</ul> -<p>The model microversion and topology ID can be used to identify topological entities across the model changes. Topology ID defined in a specific microversion can be translated into a set of topology IDs in the current microversion of the model. (The Topology ID is sometimes referred to as a Deterministic ID within Onshape, and is exposed in specific API calls as partId, faceId, etc.). See the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">PartStudio APIs</a> to see what topology IDs are exposed.</p>Docs: Quick Starthttps://onshape-public.github.io/docs/api-intro/quickstart/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/quickstart/ -<p>In this example, we will call an Onshape REST API endpoint to send a document name to our console. Please note that the sample shown on this page is only designed to be used as a quick start guide and does not represent a full Onshape application.</p> -<h2 id="system-requirements">System Requirements</h2> -<ul> -<li>You must be signed in to your Onshape account at <a href="https://cad.onshape.com">https://cad.onshape.com</a> (or <a href="https://companyName.onshape.com">https://companyName.onshape.com</a> for Enterprise accounts).</li> -<li>This example is coded in Python. The equivalent code is provided in other languages at the end of the example. To follow along with this tutorial, you can download and install Python here: <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a>.</li> -</ul> -<h2 id="review-the-api-endpoint">Review the API Endpoint</h2> -<ol> -<li>Go to the <a href="https://cad.onshape.com/glassworks/explorer">API Explorer</a> and scroll to <code>Document</code>.</li> -<li>Expand the <code>GET /documents/{did}</code> endpoint. Note that in the URL, the name of this API is <code>getDocument</code>.</li> -<li>Make a note of the URL structure and the parameters required to make this request. This will become the fixed URL part of our API call. </br> -<img src="https://onshape-public.github.io/images/Glassworks_getDocument.png" alt="image"> </br> -For this endpoint, we only need to get the document ID from the document URL.</li> -<li>Scroll down and make a note of the <code>Media Type</code> that we’ll need to include in our header. </br> -<img src="https://onshape-public.github.io/images/Glassworks_MediaType.png" alt="image"></li> -</ol> -<h2 id="review-the-document">Review the Document</h2> -<p>Navigate to <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a>, and make a note of the document ID in the URL (<code>e60c4803eaf2ac8be492c18e</code>). </br> -<img src="https://onshape-public.github.io/images/OnshapeAPIGuidePublicDoc.png" alt="image"></p> -<h2 id="create-your-api-keys">Create your API Keys</h2> -<ol> -<li>Go to <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</li> -<li>In the left pane, click <code>API keys</code>.</li> -<li>Click the <code>Create new API key</code> button.</li> -<li>Select the following permissions for your app: -<ul> -<li><code>Application can read your documents.</code></li> -<li><code>Application can write to your documents.</code></li> -</ul> -</li> -<li>Click the <code>Create API key</code> button. </br> -<img src="https://onshape-public.github.io/images/CreateNewAPIKey.png" alt="image"></li> -<li>Copy both the <strong>access key</strong> and <strong>secret key</strong> from the pop-up window, save them somewhere, then click the <code>Close</code> button. -</br><strong>IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!</strong></br> -<img src="https://onshape-public.github.io/images/APIKeySecretKey.png" alt="image"></li> -<li>The details for your application appear. </br> -<img src="https://onshape-public.github.io/images/DevPortalKeys.png" alt="image"></li> -<li>Open your terminal and run the following command, replacing <code>ACCESS_KEY</code> and <code>SECRET_KEY</code> with the <strong>access key</strong> and <strong>secret key</strong> you created above. Remember to include the colon (<code>:</code>) between the keys. -<ul> -<li><strong>MacOS</strong>: -<pre tabindex="0"><code>printf ACCESS_KEY:SECRET_KEY | base64 -</code></pre></li> -<li><strong>Windows</strong>: -<pre tabindex="0"><code>powershell &#34;[convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\&#34;ACCESS_KEY:SECRET_KEY\&#34;))&#34; -</code></pre></li> -</ul> -</li> -<li>You will receive a long, base-64-encoded string. You will need this string later, so keep it somewhere safe. We&rsquo;ll refer to it as our <code>CREDENTIALS</code>.</li> -</ol> -<h2 id="write-your-code">Write Your Code</h2> -<ol> -<li>Create a new file called <code>hello.py</code>.</li> -<li>Start your file by importing the necessary libraries.</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span></code></pre></div><ol start="3"> -<li>Next, define the URL for the API call:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;ASSEMBLED_URL&#34;</span> -</span></span></code></pre></div><ol start="4"> -<li>Replace <code>ASSEMBLED_URL</code> with the fully formed API. This is where we’ll put together everything we’ve learned so far: -<ol> -<li>The base URL: -<ul> -<li><code>https://cad.onshape.com/api</code></li> -<li><code>https://companyName.onshape.com/api</code> for Enterprise accounts</li> -</ul> -</li> -<li>The fixed URL is specified in the <a href="https://cad.onshape.com/glassworks/explorer/#/Document/getDocument"><code>getDocument</code></a> API in Glassworks: <code>/documents/{did}</code></li> -<li>The document ID parameter from the public document URL to include in the fixed URL: <code>{did}: e60c4803eaf2ac8be492c18e</code></li> -<li>Together, this makes the URL for our API request: -<code>https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e</code> </br></li> -</ol> -</li> -<li>We don&rsquo;t need to send any optional parameters with our request, so we can define them as an empty object:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span></code></pre></div><ol start="6"> -<li>Now, define your API keys: </br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span></code></pre></div><ol start="7"> -<li>Replace <code>CREDENTIALS</code> with the string you created in the last section.</li> -<li>Next, define your headers:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;MEDIA_TYPE&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span></code></pre></div><ol start="9"> -<li>Replace <code>MEDIA_TYPE</code> with the Media type we obtained from the API Explorer during the Review the API section above:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>application/json;charset=UTF-<span style="color:#099">8</span>;qs=<span style="color:#099">0.09</span> -</span></span></code></pre></div><ol start="10"> -<li>Put all the variables you just defined together into the request:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Put everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span></code></pre></div><ol start="11"> -<li>And finally, print the name value from the response:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div><ol start="12"> -<li>Make sure your file matches the full example below:</br></li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Putting everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div><h2 id="run-your-code">Run Your Code</h2> -<ol> -<li>Open your terminal and navigate into the folder where you saved your <code>hello.py</code> file: <code>cd ~/&lt;your-file-path&gt;</code></li> -<li>Install the necessary modules:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 -m pip install requests -</span></span><span style="display:flex;"><span>python3 -m pip install jsons -</span></span></code></pre></div><ol start="3"> -<li>Run your code:</br><code>python3 hello.py</code></li> -<li>Confirm that your console displays:</br><code>&quot;Onshape API Guide&quot;</code></li> -</ol> -<h2 id="other-language-examples">Other Language Examples</h2> -<p>Remember to replace <code>CREDENTIALS</code> with your credentials.</p> -<h3 id="curl">cURL</h3> -<p>Returns the entire response json. Scroll to the bottom to the see <code>name</code> field.</p> -<pre tabindex="0"><code class="language-curl" data-lang="curl">curl -X &#39;GET&#39; \ -https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39; \ --H &#39;Content-Type: application/json&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre><h3 id="javascript">JavaScript</h3> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#00a">import</span> fetch from <span style="color:#a50">&#39;node-fetch&#39;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">async</span> <span style="color:#00a">function</span> getDocument(url=<span style="color:#a50">&#39;&#39;</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> response = <span style="color:#00a">await</span> fetch(url, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;GET&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>, -</span></span><span style="display:flex;"><span> Accept: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> Authorization: <span style="color:#a50">`Basic </span><span style="color:#a50">${</span>btoa(<span style="color:#a50">&#39;CREDENTIALS&#39;</span>)<span style="color:#a50">}</span><span style="color:#a50">`</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> response.json(); -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>getDocument(<span style="color:#a50">&#39;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39;</span> -</span></span><span style="display:flex;"><span>).then((data) =&gt; { -</span></span><span style="display:flex;"><span> console.log(data.name); -</span></span><span style="display:flex;"><span>}); -</span></span></code></pre></div><h3 id="c">C++</h3> -<p>Returns the entire response json. Scroll to the bottom to the see <code>name</code> field.</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cpp" data-lang="cpp"><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;iostream&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;string&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317">#include</span> <span style="color:#4c8317">&lt;stdio.h&gt;</span><span style="color:#4c8317"> -</span></span></span><span style="display:flex;"><span><span style="color:#4c8317"></span><span style="color:#00a">using</span> <span style="color:#00a">namespace</span> std; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">int</span> <span style="color:#0a0">main</span>() { -</span></span><span style="display:flex;"><span> string url = <span style="color:#a50">&#34;curl &#34;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-X &#39;GET&#39; &#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;&#39;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#39;&#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; &#34;</span>; -</span></span><span style="display:flex;"><span> url += <span style="color:#a50">&#34;-H &#39;Authorization: Basic CREDENTIALS&#39;&#34;</span>; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> system(url.c_str()); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#099">0</span>; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h3 id="python">Python</h3> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">requests</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">jsons</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Assemble the URL for the API call </span> -</span></span><span style="display:flex;"><span>api_url = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents/e60c4803eaf2ac8be492c18e&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Optional query parameters can be assigned </span> -</span></span><span style="display:flex;"><span>params = {} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Use the encoded authorization string you created from your API Keys.</span> -</span></span><span style="display:flex;"><span>api_keys = (<span style="color:#a50">&#34;CREDENTIALS&#34;</span>) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Define the header for the request </span> -</span></span><span style="display:flex;"><span>headers = {<span style="color:#a50">&#39;Accept&#39;</span>: <span style="color:#a50">&#39;application/json;charset=UTF-8;qs=0.09&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/json&#39;</span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Putting everything together to make the API request </span> -</span></span><span style="display:flex;"><span>response = requests.get(api_url, -</span></span><span style="display:flex;"><span> params=params, -</span></span><span style="display:flex;"><span> auth=api_keys, -</span></span><span style="display:flex;"><span> headers=headers) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"># Convert the response to formatted JSON and print the `name` property</span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">print</span>(json.dumps(response.json()[<span style="color:#a50">&#34;name&#34;</span>], indent=<span style="color:#099">4</span>)) -</span></span></code></pre></div>Docs: Why Onshape?https://onshape-public.github.io/docs/api-intro/whyonshape/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/whyonshape/ -<h2 id="why-onshape">Why Onshape?</h2> -<p>As long as there have been applications that manage organizational data -into a database, there has been a need to share that data between -different departments and therefore, usually, different systems. In a -typical design/manufacturing organization, there could be at least four -or five mission-critical databases that manage the data for different -departments and for different stages in the product’s lifecycle.</p> -<p>Initially, these systems provide the capabilities required by their -consumers (i.e., the departments that use these systems). For instance, -the Finance might use QuickBooks, Manufacturing -might use a manufacturing planning and execution system (MES), -Engineering might use a Product Data management System (PDM), and so on for each -group in the organization.</p> -<p>This often leads to disparate silos of data and knowledge. -The departments in an organization do not work in a vacuum; each is -dependent on information generated by other groups. For -instance, Manufacturing can’t produce accurate assembly instructions -without input from engineering on the designs and the bill of -materials. Finance can’t price the product without understanding its -contents and which parts are manufactured in-house or -purchased.</p> -<p>Therefore, the need to integrate these systems becomes critical for the -organization to function optimally. Initially, connecting one system to -another can be a straightforward process. This usually involves -some services to get the systems to talk to each other, however it -isn&rsquo;t too painful as long as the requirements are clearly -defined.</p> -<p>Anyone who has implemented integrations between PLM (Product -Lifecycle Management) systems or ERP (Enterprise Resource Planning) systems will tell -you of the nightmare scenarios they encountered. Often this is the -result of poorly scoped and defined requirements, conflicting -requirements coming from multiple departments, and the many integration -points required between systems. The result is that the organization is -not getting what it wants or needs, the customer is paying for services -that do not provide the promised solution, and usually the project is -long overdue. All this equals an unhappy customer and often the software -vendor’s solutions are blamed for the disaster.</p> -<p>Over the years, many technologies have appeared (and some of them, just as -quickly disappeared) to enable integration without the need -to write thousands of lines of custom code that needs to be re-written -for every software upgrade. Several technologies provide “codeless” integration between SaaS -products (<a href="wwww.zapier.com">Zapier</a>, for example). These solutions -are particularly good for generic use cases for data exchange between -systems, but can be limited when it comes to custom modifications to the -data being sent that might be required by a specific customer. In -addition, they have the overhead of requiring a subscription to their -service. Sending -corporate IP through another third-party can also cause data security issues.</p> -<p>Therefore, we can understand that in most organizations integration -between systems is a necessary evil that must be tackled, either with -an out-of-the-box solution or through some custom coding.</p> -<p>Early on, Onshape understood that as an engineering system, it cannot -exist in a vacuum; it must be able to communicate with other systems. -For this reason, the REST API was developed.</p> -<p>An API, or <em>application -programming interface</em>, is a set of rules that define how applications -or devices can connect to and communicate with each other. A REST API is -an API that conforms to the design principles of the REST, -or <em>representational state transfer <em>architectural style. For this -reason, REST APIs are sometimes referred to RESTful APIs</em>.</em></p> -<h2 id="onshape-saas">Onshape SaaS</h2> -<p>Onshape was built from the ground up as a true SaaS-based system; Onshape had no investment in legacy code and was able to develop an application that truly runs as a multi-tenant -SaaS solution from the first line of code. Many companies claim to run -cloud-based solutions, but since they have such a large investment -in their legacy code, that they can’t just discard and start again from -scratch. Instead, they tend to try and port that code to the web.</p> -<p>More often than not, porting existing code to the web and calling it a -SaaS solution is no more than a marketing ploy; it isn’t a true SaaS -solution if it wasn’t written as one. These are generally known as cloud-hosted solutions. This means that a typical three-tier data management -solution (which could have previously been installed on a set of servers), -has now been modified to be hosted on the web.</p> -<h3 id="traditional-three-tier-architecture">Traditional three-tier architecture</h3> -<p>Traditional PLM systems typically use a three-tier architecture, mainly -consisting of an application server, a database server, and a client (either a web client or a thick client installed on the client -hardware).</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage10.png" -style="width:4.91807in;height:3.27083in" -alt="The 3-tier architecture | Download Scientific Diagram" /></p> -<p><em>Typical three-tier architecture</em></p> -<p>To connect to and integrate with this architecture, APIs are usually exposed on -the application or web server. If this -architecture is ported to the web, it cannot make -customizations through the API, since it would modify the behavior of -the program for everyone connected to that application server.</p> -<h3 id="single--vs-multiple-tenant-architectures">Single- vs multiple-tenant architectures</h3> -<p>The three-tier architecture is typical of most -PLM solutions on the market today, which is fine -if you want the solution to be installed on company servers and be -accessible to people within the company only.</p> -<p>When this type of solution is ported to the web, software -vendors typically must create a single-tenant application where an -application server and a database server are provisioned for each new -customer.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage11.png" -style="width:5.4311in;height:4.35417in" -alt="Enterprise SaaS Architecture - The Why | Frontegg" /></p> -<p><em>Single-tenant architecture</em></p> -<p>In this case, the vendor must use expensive -hardware to host more customers, which is not a -sustainable model.</p> -<p>Modern 21<sup>st</sup> century software solutions use multi-tenant -solutions that can be hosted on services such as Amazon cloud, Azure, etc. There are many benefits to this architecture, including that servers can be provisioned and -decommissioned on the fly to provide ultimate performance whenever -required. Since servers cost money, decommissioning servers when they -are not required is a key benefit to a true SaaS solution.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage12.png" style="width:6.5in;height:4.65417in" -alt="Saas Solutions - Multi-tenant vs multi-instance architectures" /></p> -<p><em>Multi-tenant architecture</em></p> -<p>Since each application is separate in this architecture, we can enable customizations that can’t be implemented in a single-tenant architecture. For example, we can provide access to the REST -APIs that are required for Onshape integration. In the single-tenant -architecture, if you provide API access to the application server, one -customer will be modifying that application for all customers who are -registered on that tenant.</p> -<h2 id="the-onshape-difference">The Onshape Difference</h2> -<p>Onshape does not work like other legacy CAD systems. Onshape was built from scratch for the cloud and as a modern -CAD system, so many of the failings of legacy CAD -systems were excluded.</p> -<p>There are many differences -and benefits to Onshape, which are well-documented in the Onshape Help -and training materials.</p> -<p>The information in this section is specific to integrations, since Onshape does not behave like a traditional file-based -systems. When writing an integration for Onshape, it is -critical to understand the nuances in Onshape’s design practices and how -data is organized in Onshape.</p> -<h3 id="data-drivenfileless">Data-driven/fileless</h3> -<p>Most traditional PDM/PLM systems integrated with CAD systems -enable this integration on a per-file basis. This means that you have an -object in the PDM/PLM system that corresponds directly to a file in the -CAD system. In this way, the PDM/PLM system can manage access to the -files, build assemblies from the files, view the CAD data, and much more.</p> -<p>Onshape, however, does not work this way.</p> -<p>Being data-driven means that Onshape has no files, just data, so an integration into Onshape is going to look -different from any integration to a CAD system that you might have done -previously.</p> -<p>In traditional CAD, a single file represents a snapshot of what the -design looked like at a specific moment in time. Unless it’s changed, it will remain in that state forever. PDM -systems manage these files, and once a designer decides to make a -revision or a release, the file is locked, and a new file can be created -to represent any further updated versions or releases of the design. -PDM/PLM systems are very good at managing this data in an up-to-date -structure, but it does have the drawbacks. They generate many file -copies of a specific design, and once a file is taken out from the system (for instance, to share with a supplier), it is no longer managed and -tracked.</p> -<p>Onshape uses data instead of files. The data is always up-to-date and -can be collaborated on in real-time without the need to send file copies -back and forth. This means that Onshape views versions and releases differently -than those traditional systems do. When integrating with Onshape, we must design for data rather than files.</p> -<p>Files can be generated from -the Onshape data. For example, you can generate a PDF of a -drawing upon release or of a STEP file that can be used by other downstream systems.</p> -<p>A key benefit of a data-driven system is the ability to retrieve detailed, real-time -analytics. Onshape has comprehensive analytics; including who can view or edit a design, when and exactly what edits are made, which commands were used, and how long was spent modifying the design.</p> -<h3 id="built-in-pdm">Built in PDM</h3> -<p>Up until now, CAD was one software program, and PDM/PLM was another -program that had to be integrated with the CAD. In many cases, both -programs could be sold by the same software vendor (even though there -are many PLM systems available that are sold by independent vendors who -have no CAD system). Regardless, a PDM/PLM system always had to be an added solution to the CAD system.</p> -<p>No matter how deep the integration between a CAD system and a PLM -system, there is always the need to sync data between the two. This is usually a weak point in any solution that is prone to errors.</p> -<p>Being data-driven, Onshape already has PDM built in as part of the CAD -system. This is unique in the industry: CAD and PDM as part -of the same solution with no additional piece of software required.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage14.png" -style="width:4.49202in;height:4.1652in" -alt="A picture containing graphical user interface Description automatically generated" /></p> -<p><em>Onshape’s revision and part number schema definition interface</em></p> -<p>For instance:</p> -<ul> -<li> -<p>Since the <strong>data is always up-to-date</strong>, the correct state of any design -is always represented in real-time with no delay for syncing between -systems.</p> -</li> -<li> -<p>Unlike file-based systems, <strong>the data is never locked</strong>; it -is always available and always changing.</p> -</li> -<li> -<p>PDM system <strong>data management aspects are fully integrated</strong> into every aspect of -the CAD system.</p> -</li> -<li> -<p>True <strong>real-time collaboration/co-design</strong> on both design and data is -enabled.</p> -</li> -</ul> -<p>So, what does this mean when it comes to integrating Onshape with -another PLM system? First and foremost, we must understand that there -are many things that a PLM system does that Onshape’s PDM capabilities -can’t do. Integrating Onshape to a PLM system should augment the -powerful capabilities already available inside Onshape, not -necessarily replace them. Similarly, Onshape does not replace PLM-native capabilities. Instead, depending on the business case, we can use the best-in-class capabilities of each system to augment the -other.</p> -<p>The Onshape release process is an example of the augmentation of each system&rsquo;s capabilities. Onshape has a specific way of managing the release of data that is -different from traditional PDM systems. This capability is inherently -suited to a data-driven approach and provides a lot of value to the -update of design data in Onshape. At the same time, PLM systems provide -enterprise release processes that may include many people and different -departments that extend beyond the engineering domain. Such PLM -processes can be highly customized and suited to the organizations -established business processes.</p> -<p>In this scenario, it doesn&rsquo;t make sense to avoid the enterprise release -processes in the PLM system. However, also omitting Onshape’s release -capabilities could put data between Onshape and the PLM system out of -sync and prevent Onshape from updating data (e.g., watermarks and -title blocks on drawings, icons related the visualizing the state of -data, etc.).</p> -<p>In this case, we want to use the best-in-class features of each software -solution without compromising the capability provided by each solution. -If we plan our integration correctly, this can be achieved by initiating -the release of the data in Onshape, transferring the release data to the -PLM system where the release process will be triggered, and finally -automating the release in Onshape once the process has been completed in -the PLM system.</p> -<h3 id="multi-part-part-studios">Multi-part Part Studios</h3> -<p>In traditional CAD systems, one file typically equals -one part. While design-in-context is available in most CAD systems, and -multiple solid bodies can be created, each part is self-contained in a separate file. For PLM systems, this -makes it easy to associate an object in the PDM/PLM database with a -specific CAD file. <em>This is not the case in Onshape.</em></p> -<p>In Onshape, parts are designed in what’s called a <em>Part Studio.</em> Within -a Part Studio, the designer is free to create as many parts as they want. -The general rule is that the parts should be related to each other in a -system, thereby making it easier to design one part from another, however -there is a lot of flexibility in how the designer wishes to work.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage15.png" -style="width:4.45764in;height:4.12141in" -alt="A picture containing text Description automatically generated" /></p> -<p><em>An example of a multi-part Part Studio in Onshape</em></p> -<p>The structure of the Onshape document is discussed in detail in the <a href="https://onshape-public.github.io/docs/api-intro/architecture">Onshape Architecture</a> page. The Part Studio is included in an Onshape document.</p> -<p>We can already begin to understand that the traditional CAD/PDM paradigm -of &ldquo;one file per object&rdquo; will not work with Onshape; the designer would be forced by the -PDM/PLM system to only create one part per Part Studio. This would -therefore limit the designer’s freedom for creativity in Onshape and -seriously reduce the powerful functionality available for the designer -to use.</p> -<p>Therefore, we need to re-think how we integrate with Onshape versus how we -integrate with traditional CAD systems. Fortunately, Onshape’s REST API -supports the multi-part Part Studio scenario. Instead of associating a -file with an object in the PDM/PLM database, we now use the REST API to -associate a Part with its corresponding object.</p> -<h3 id="versions-and-releases">Versions and releases</h3> -<p>Traditional PDM/PLM systems provide design release support by locking a -CAD file for access. The access controls are defined in the database and -the definition of a part/assembly/drawing as released is controlled by -the database. When a new revision of the part is required, a file copy -is made, and the database provides access to the new copy. Generally, -the old copy representing the previous release persists in the file -store and can be referenced by the database. <em>This is not how Onshape works.</em></p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage16.png" -style="width:2.66865in;height:3.09375in" />Since there are no files in -Onshape (just data) no file locking or copy mechanisms are -available. Instead, Onshape looks at the data as a continuous timeline -that is always moving forward and always changing as the design evolves. -The data is never locked; it is always available.</p> -<p>In place of file copies that represent versions and releases of the -design, Onshape provides the ability to create <em>versions</em> as bookmarks -in the timeline. When creating a version, Onshape places a bookmark in -the timeline that represents the state of the design at that specific -moment in time. Releases work in a similar way, but they are defined -as official, company-approved processes and have special meaning.</p> -<p>In addition to creating versions and releases, Onshape can create <em>branches</em>, which can be defined as alternative timelines. A -designer might want to experiment with alternate design ideas without -modifying the existing design that others are working on. By -creating a branch from any point in the timeline, the designer is -free to experiment with alternate ideas. If the ideas work, they can be -merged into the current timeline at any point.</p> -<p>From an integration perspective, we need to take into -consideration how Onshape works with versions and releases. Since a release represents a company-approved design, Onshape provides processes for the approval of -a release and the change of state of a design. Onshape also provides -APIs and triggers (events) that enable integration points throughout the -release process. It is through the triggers and the APIs that -integration of any third-party system that wishes to manage the release -process is enabled.</p> -<h3 id="workflows">Workflows</h3> -<p>Release and obsoletion workflows are included with Onshape and can be customized to meet company standards.</p> -<p>For details on how to implement and customize Onshape’s workflows, -please review these online help topics:</p> -<ul> -<li><a href="https://cad.onshape.com/help/Content/relmgmt_custom.htm">How to design release management processes</a></li> -<li><a href="https://cad.onshape.com/help/Content/custom_workflow.htm">How to create a customized release workflow</a></li> -</ul> -<p>Most PDM/PLM systems can model a company’s -business processes in a workflow. These can be highly automated -processes that move data and file references through a process of -reviews and approvals. Onshape also has this capability, which is -currently used for release and obsoletion processes.</p> -<p>There are no files or file references in Onshape that are moved -through the process. Onshape only has data. Therefore, it is the data -that is referenced at each stage of the process. Traditional PDM systems -might make file copies and lock files as they move through a release -process. If the process is rejected at any stage, those -files must be discarded, the previous version of the files unlocked and -all states updated. In short, it system must rewind back to the state of the files and -the data when the workflow was initiated. This is a lot of complex -actions that must occur when a process is rejected for any reason. <em>Onshape doesn’t work this way.</em></p> -<p>A release process can be started on data (such as assemblies, parts, -drawings, etc.). For example, if the state of a referenced part is updated to -“Pending,” and the process is rejected at any stage, there -is no rewinding of files and data; the data just reverts to the -original “In Progress” state, and the workflow is discarded. Since the -workflow didn’t complete, nothing related to the data has actually -changed. When you are used to traditional PDM systems, this feels like -an anti-climax, and we often receive the question, “But where’s my -process? Where’s the data that was attached to the process?”. Well, the -answer is: nothing changed. Until the process is completed, nothing -actually changes, so the data is in the same state it was prior to the -initialization of the release process.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage17.png" -style="width:3.39863in;height:2.61034in" -alt="A picture containing chart Description automatically generated" /></p> -<p><em>A custom release process in Onshape</em></p>Docs: OAuthhttps://onshape-public.github.io/docs/auth/oauth/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/auth/oauth/ -<p><strong>See the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app</a> for a working example of OAuth2.</strong></p> -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.</p> -</blockquote> -<h2 id="what-is-oauth2">What is OAuth2?</h2> -<p>The OAuth (Open authorization) protocol was developed by the Internet Engineering Task Force, an open standards organization that develops and promotes voluntary Internet standards (particularly the technical standards that comprise the Internet protocol suite) to enable secure, delegated access to an application&rsquo;s resources.</p> -<p>The OAuth2 protocol enables an application to access a resource that is under the control of someone else. In order to access that resource, a <i>token</i> is required. The token represent the delegated rights of access (that is, what rights this application has, such as read/write/update, scope, rights to different resources, and more).</p> -<p><i>This means the application can be accessed by a third-party system without that system -impersonating the user that controls the resource.</i></p> -<p>A good analogy is the hotel check-in process. When you arrive at the front desk of a hotel, you provide an ID and a form of payment. Then, you are given a key card that opens a specific door. When you reach that door, you swipe your key card and are granted access. The door itself doesn’t know who you are or anything about you, it just knows that the key card was encoded correctly, and it allows you access. At some point, the key card expires, and the door no longer lets you into the room. This is the same for access tokens in the OAuth2 flow.</p> -<p>With the OAuth2 protocol, you register your application with the third party, and you are given a set of keys. These keys get exchanged for an access token that grants you access to resources in the third-party application. The token expires regularly; you miust get a new token to access the application again. For this, you are provided with a <i>refresh token</i>. Sending the refresh token to the authentication server updates your access token and gives you a new refresh token.</p> -<p><img src="https://onshape-public.github.io/images/APITokenRequestDiagram.png" alt="api token request diagram"></p> -<h3 id="oauth2--onshape">OAuth2 &amp; Onshape</h3> -<p>The first step in the OAuth flow is for the Onshape user to request that Onshape let the third-party application access Onshape.</p> -<p>Once the user has authorized the application, they are redirected to a predefined URL (called a <i>redirect URL</i>) with a code that will requests an access token from Onshape. Therefore, the redirect URL should contain a script that can capture the authorization code.</p> -<p>You will use the access token to authenticate requests to the Onshape API. The token expires after preset amount of time. To get a new valid access token after one has expired, you must use the refresh token to request a new access token. Refreshing the access token also provides you with an updated refresh token to use in the next refresh access token request. Make sure to store both the the access token and the refresh token, and update them with each refresh of the token. The authorization token must accompany any call to the API, this is done by adding the token to an Authorization field in the header of each request:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>Authorization: Bearer &lt;accessToken&gt; -</span></span></code></pre></div><p>If correctly authenticated, most responses from the REST API call return JSON data (though some return binary data), with an HTTP response code of <code>200 Success</code>, <code>204 - No Content</code>, or <code>301 - Permanent Redirect</code>. <code>301</code> responses will include a redirect for you to follow.</p> -<p>In the event that the authorization code is incorrect (for instance, if it expired), you will receive an <strong>HTTP 401</strong> response. This response means that the client request has not been completed, since it lacks valid authentication credentials for the requested resource. In this event, your code for each call to the REST API should include a catch clause for a 401 exception. Once caught, you can refresh the token and make the request again. Pay close attention to the <code>Content-Type</code> header for what data to parse and expect.</p> -<p>When integrating with Onshape, OAuth tokens give third-party applications (such as desktop applications or web services) access to users&rsquo; data as defined by the permissions scope (such as users&rsquo; documents or profile information). Using OAuth terminology, Onshape acts as both the authorization and resource server, while the desktop or web-based application is the client. Resource owners have the option of granting or denying access to applications.</p> -<p>Once obtained, an OAuth token will work for third-party APIs under <code>/api</code>. Do NOT attempt to use an OAuth token to fetch the URLs typically displayed in a web browsers location bar.</p> -<h3 id="more-resources">More resources</h3> -<ul> -<li><a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2">Digital Ocean</a> - A good resource for learning more about OAuth2.</li> -<li><a href="http://tools.ietf.org/html/rfc6749">RFC 6749</a> - The reference for the OAuth framework as a whole. Most of this document describes how to implement the OAuth exchanges described by the reference within the context of Onshape and client applications.</li> -<li><a href="http://tools.ietf.org/html/rfc6750">RFC 6750</a> - Describes the exchange of OAuth access tokens between clients and OAuth servers.</li> -</ul> -<h2 id="implement-oauth2">Implement OAuth2</h2> -<p>This OAuth tutorial demonstrates how to recreate the authentication process in Node.js found in the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app</a> sample code. The <a href="#final-code">final code</a> in Node.js and other languages can be found at the end of this page.</p> -<h3 id="1-register-the-app">1: Register the app</h3> -<ol> -<li>Navigate to <a href="https://dev-portal.onshape.com/signin">https://dev-portal.onshape.com/signin</a> and sign in.</li> -<li>In the left sidebar, click <strong>OAuth applications</strong>.</li> -<li>Click the <strong>Create new OAuth application</strong> button.</li> -<li>Fill out the form as follows: -<ul> -<li>Name: <code>gltf-viewer-yourname</code> -<ul> -<li>The application name to display to users.</li> -<li>Should include the name of your company to differentiate it from other possibly similar applications.</li> -</ul> -</li> -<li>Primary format: <code>com.yourname.gltf-viewer</code> -<ul> -<li>String that uniquely identifies your application and is a marker for the data it might store on Onshape servers.</li> -<li>Cannot be changed after the application is registered.</li> -</ul> -</li> -<li>Summary: <code>Onshape OAuth tutorial</code> -<ul> -<li>Description of your application.</li> -<li>Displayed to the user when they’re asked to grant the application permission to access their data.</li> -</ul> -</li> -<li>Redirect URLs: <code>http://localhost:5000/token</code> -<ul> -<li>Your application must specify at least one URL used in the OAuth protocol exchanges.</li> -<li>This URL must also use SSL (a URL that begins with https), with two exceptions applicable for -installed desktop applications: <code>http://localhost:&lt;port&gt;</code> and <code>urn:ietf:wg:oauth:2.0:oob</code>.</li> -<li>e.g., <code>https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthRedirect</code></li> -</ul> -</li> -<li>Admin team: <code>No Team</code> -<ul> -<li>Optional.</li> -<li>If defined, members of the team can make changes to the definition of this OAuth application.</li> -<li>See the <a href="https://cad.onshape.com/help/Content/teams-enterprise.htm">Help Docs: Teams</a> page for more information on creating teams in Onshape.</li> -</ul> -</li> -<li>OAuth URL: <code>none</code> -<ul> -<li>Should contain the URL of your deployed application.</li> -<li>This is the first URL called from the Onshape Applications page.</li> -<li>The page hosted at this URL should handle the OAuth authentication. Once your application’s server has been authenticated on behalf of the user, that user should be redirected to your applications content.</li> -<li>If you have not deployed your app yet, you can leave this field blank (as shown in this example) for local work and update it later.</li> -<li>e.g., <code>https://app-gltf-viewer-yourname-c11f263794bc.herokuapp.com/oauthSignin</code></li> -</ul> -</li> -<li>Settings: check <strong>Supports collaboration</strong></li> -<li>Permissions: -<ul> -<li>This is also called application scope, and it defines what access rights your application has to the user’s data.</li> -<li><strong>Application can read your profile information</strong> - Enable your application to access the Onshape user profile. Check this option.</li> -<li><strong>Application can read your documents</strong> - Onshape documents created by this user can be accessed with read privileges only. Check this option.</li> -<li><strong>Application can write to your documents</strong> - The user-owned Onshape documents can be modified by this application. Check this option.</li> -<li><strong>Application can delete documents and workspaces</strong> - Your application will be able to delete a workspace within a document or the complete Onshape document. Do not check this option for this example.</li> -<li><strong>Application can request Purchases on Your behalf</strong> - The application will have access to make purchases if required. Do not check this option for this example.</li> -<li><strong>Application can share and unshare documents on your behalf</strong> - Onshape’s document sharing capabilities are very powerful; they enable other parties to access your shared documents with -predefined rights. If this option is checked, the application can automatically share a document with other people. Do not check this option for this example.</li> -</ul> -</li> -</ul> -</li> -<li>Click <strong>Create application</strong>.</li> -<li><font style="color: red"><b>COPY THE OAUTH SECRET FROM THE POP-UP WINDOW.<b></font> -<ul> -<li>You will not be able to access this secret again.</li> -<li>This secret is unique to you and your app and should be protected like any sensitive password. For example, it should <em>NOT</em> be checked in to source code control systems.</li> -</ul> -</li> -<li>Click <strong>Close</strong>.</li> -<li>Copy the <strong>OAuth client identifier</strong> from the app Details page that opens. -<ul> -<li>These OAuth secret and client ID keys will be used in your code for requesting a one-time user authorization code from Onshape.</li> -</ul> -</li> -</ol> -<p>Your application is now registered with Onshape and you have options to -modify the application definition through this portal.</p> -<img src="https://onshape-public.github.io/images/dev-portal-app-details-01.png" alt="the gltf-viewer app in the onshape dev portal app details screen" /> -<h3 id="2-get-the-user-authorization-code">2: Get the user authorization code</h3> -<p>We’ll start by loading the basic libraries required to run this sample. We&rsquo;ll use Passport to authenticate requests through plugins known as strategies. In this example, we&rsquo;ll use an Onshape-developed plugin called <code>passport-onshape</code>, but you can define your own strategy to use with Passport, if you prefer. You can find more information on <a href="https://www.npmjs.com/package/passport">Passport here</a>.</p> -<ol> -<li>Create a directory for your app, and then install Passport and passport-onshape:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>npm install passport -</span></span><span style="display:flex;"><span>npm install passport-onshape -</span></span></code></pre></div><ol start="2"> -<li>Next, create a file calls <code>app.js</code> and add the following definitions to the top of the file:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// App definitions -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> path = require(<span style="color:#a50">&#39;path&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> uuid = require(<span style="color:#a50">&#39;uuid&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> express = require(<span style="color:#a50">&#39;express&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> session = require(<span style="color:#a50">&#39;express-session&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> bodyParser = require(<span style="color:#a50">&#39;body-parser&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> passport = require(<span style="color:#a50">&#39;passport&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> OnshapeStrategy = require(<span style="color:#a50">&#39;passport-onshape&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> config = require(<span style="color:#a50">&#39;./config&#39;</span>); -</span></span></code></pre></div><ol start="3"> -<li>Next, tell Express to use Passport and initialize it. Note: you can replace the Express code with code for the web server of your choice.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// Tell Express to use Passport, and initialize it. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> app = express(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;dist&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(bodyParser.json()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.set(<span style="color:#a50">&#39;trust proxy&#39;</span>, <span style="color:#099">1</span>); <span style="color:#aaa;font-style:italic">// To allow to run correctly behind Heroku when deployed -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span>app.use(session({ -</span></span><span style="display:flex;"><span> secret: config.sessionSecret, -</span></span><span style="display:flex;"><span> saveUninitialized: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> resave: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> cookie: { -</span></span><span style="display:flex;"><span> name: <span style="color:#a50">&#39;app-gltf-viewer&#39;</span>, -</span></span><span style="display:flex;"><span> sameSite: <span style="color:#a50">&#39;none&#39;</span>, -</span></span><span style="display:flex;"><span> secure: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> httpOnly: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> path: <span style="color:#a50">&#39;/&#39;</span>, -</span></span><span style="display:flex;"><span> maxAge: <span style="color:#099">1000</span> * <span style="color:#099">60</span> * <span style="color:#099">60</span> * <span style="color:#099">24</span> <span style="color:#aaa;font-style:italic">// 1 day -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span>})); -</span></span><span style="display:flex;"><span>app.use(passport.initialize()); -</span></span><span style="display:flex;"><span>app.use(passport.session()); -</span></span></code></pre></div><ol start="4"> -<li>Next, we&rsquo;ll store the Onshape user information so it can be retrieved from <code>req.user</code> in -each call. Passport uses the <code>serializeUser</code> function to persist user data (after successful -authentication) into the session. The function <code>deserializeUser</code> is used -to retrieve user data from session.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Store the Onshape user information -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.serializeUser((user, done) =&gt; done(<span style="color:#00a">null</span>, user)); -</span></span><span style="display:flex;"><span>passport.deserializeUser((obj, done) =&gt; done(<span style="color:#00a">null</span>, obj)); -</span></span></code></pre></div><ol start="6"> -<li>Initialize Passport with the Onshape Strategy:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Initialize Passport with the Onshape Strategy -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.use(<span style="color:#00a">new</span> OnshapeStrategy({ -</span></span><span style="display:flex;"><span> clientID: config.oauthClientId, -</span></span><span style="display:flex;"><span> clientSecret: config.oauthClientSecret, -</span></span><span style="display:flex;"><span> callbackURL: config.oauthCallbackUrl, -</span></span><span style="display:flex;"><span> authorizationURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/authorize`</span>, -</span></span><span style="display:flex;"><span> tokenURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/token`</span>, -</span></span><span style="display:flex;"><span> userProfileURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/api/users/sessioninfo`</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> (accessToken, refreshToken, profile, done) =&gt; { -</span></span><span style="display:flex;"><span> profile.accessToken = accessToken; -</span></span><span style="display:flex;"><span> profile.refreshToken = refreshToken; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> done(<span style="color:#00a">null</span>, profile); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>)); -</span></span></code></pre></div><ol start="7"> -<li>Open your environment variables file (e.g.,<code>.env</code>, <code>.bashrc</code>, <code>.bash_profile</code>, <code>.zshrc,</code> etc.) and add the following environment variables, then save and close the file.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>authorizationURL : https://oauth.onshape.com/oauth/authorize -</span></span><span style="display:flex;"><span>tokenURL : https://oauth.onshape.com/oauth/token -</span></span><span style="display:flex;"><span>userProfileURL : https://cad.onshape.com/api/users/sessioninfo -</span></span></code></pre></div><p>The callback function will provide us with the <code>accessToken</code>, the <code>refreshToken</code>, and the user’s Onshape profile once authentication has been successfully passed. We can now use this to update our database with user-specific information.</p> -<p>Note that if you store the <code>accessToken</code> and <code>refreshToken</code> in the database along with the user record, you must update it each time that the access codes are refreshed.</p> -<ol start="8"> -<li>Next, we define our endpoint where the authorization flow starts (in this case, <code>/oauthSignin</code>). This is the endpoint that we previously defined in the Onshape application setup. This will redirect to an Onshape page in order for the user to confirm (or deny) the applications access to theOnshape resources.</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Define the Onshape API endpoint -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthSignin&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* These 5 lines are specific to the glTF Viewer sample app. You can replace them with the input for whatever Onshape endpoints you are using in your app */</span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> state = { -</span></span><span style="display:flex;"><span> docId: req.query.documentId, -</span></span><span style="display:flex;"><span> workId: req.query.workspaceId, -</span></span><span style="display:flex;"><span> elId: req.query.elementId -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> req.session.state = state; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { state: uuid.v4(state) })(req, res); -</span></span><span style="display:flex;"><span>}, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> }); -</span></span></code></pre></div><h3 id="3-exchange-the-code-for-an-access-token">3: Exchange the code for an access token</h3> -<p>Fortunately, if you are using Passport, there isn’t much to do once the user grants authorization. The return URL will contain the one-time authorization token, which Passport will extract and exchange for an access token and a refresh token, which are available in Passport callback function.</p> -<ol> -<li>Add the following code to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Exchange the code for an access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthRedirect&#39;</span>, passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { failureRedirect: <span style="color:#a50">&#39;/grantDenied&#39;</span> }), (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* This code is specific to the glTF Viewer sample app. You can replace it with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> res.redirect(<span style="color:#a50">`/?documentId=</span><span style="color:#a50">${</span>req.session.state.docId<span style="color:#a50">}</span><span style="color:#a50"> -</span></span></span><span style="display:flex;"><span><span style="color:#a50">&amp;workspaceId=</span><span style="color:#a50">${</span>req.session.state.workId<span style="color:#a50">}</span><span style="color:#a50">&amp;elementId= -</span></span></span><span style="display:flex;"><span><span style="color:#a50"> </span><span style="color:#a50">${</span>req.session.state.elId<span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span>}); -</span></span></code></pre></div><ol start="2"> -<li>If the user clicks <strong>Deny</strong> instead of <strong>Authorize Application</strong>, they are taken to a page that notifies them that access to the application was denied. We can see that in the <code>failureRedirect</code> argument. Add the following to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Handle denied access -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/grantDenied&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;grantDenied.html&#39;</span>)); -</span></span><span style="display:flex;"><span>}) -</span></span></code></pre></div><p>Now we have received the access token, and it can be accessed from <code>res.user.accessToken</code> on this page or from <code>req.user.accessToken</code> from any other page you redirect to from here.</p> -<h3 id="4-use-the-access-token">4: Use the access token</h3> -<ol> -<li>Add the following to the bottom of <code>app.js</code>. You can see that the access token is used as an Authorization header:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Use the access token as an Authorization header -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>makeOnshapeAPICall: <span style="color:#00a">async</span> (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">try</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> apiUrl = <span style="color:#a50">&#34;https://cad.onshape.com/api/documents?ownerType=1&amp;sortColumn=createdAt&amp;sortOrder=desc&amp;offset=0&amp;limit=20&#34;</span>; <span style="color:#aaa;font-style:italic">//You can replace this with any Onshape API endpoint URL. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">const</span> resp = <span style="color:#00a">await</span> fetch(normalizedUrl, { headers: { Authorization: <span style="color:#a50">`Bearer </span><span style="color:#a50">${</span>req.user.accessToken<span style="color:#a50">}</span><span style="color:#a50">`</span> }}); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> data = <span style="color:#00a">await</span> resp.text(); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> contentType = resp.headers.get(<span style="color:#a50">&#39;Content-Type&#39;</span>); -</span></span><span style="display:flex;"><span> res.status(resp.status).contentType(contentType).send(data); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">catch</span> (err) { -</span></span><span style="display:flex;"><span> res.status(<span style="color:#099">500</span>).json({ error: err }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><p>Note: in the glTF Viewer sample app, this code appears in <code>utils.js</code> instead of <code>app.js</code>.</p> -<h3 id="5-refresh-the-token">5: Refresh the token</h3> -<p>When the access token expires, it must be refreshed by making another <code>POST</code> request to <code>https://oauth.onshape.com/oauth/token</code> with the following URL-encoded form body (with <code>Content-Type application/x-www-form-urlencoded</code>):</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#a00">grant_type</span>=refresh_token&amp;<span style="color:#a00">refresh_token</span>=<span style="color:#a50">\&lt;</span>refresh_token<span style="color:#a50">\&gt;</span>&amp;<span style="color:#a00">client_id</span>=<span style="color:#a50">\&lt;</span>client_id<span style="color:#a50">\&gt;</span>&amp;<span style="color:#a00">client_secret</span>=<span style="color:#a50">\&lt;</span>client_secret<span style="color:#a50">\&gt;</span> -</span></span></code></pre></div><p>As with the authorization code data, the parameters in the form body must be URL-encoded. The response to this <code>POST</code> request will be a JSON-encoded structure with a new <code>access_token</code> value that can be used for the next 60 minutes.</p> -<p>Refresh tokens are valid for the lifetime of the user’s grant. If a user who previously granted access to your application decides to revoke the grant, the refresh token is invalidated. If the user decides to re-grant application access, a new refresh token is generated and returned along with the access token.</p> -<ol> -<li>Add the following to <code>app.js</code>:</li> -</ol> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** After landing on the home page, we check if a user had already signed in. If no user has signed in, we redirect the request to the OAuth sign-in page. If a user had signed in previously, we will attempt to refresh the access token of the user. After successfully refreshing the access token, we will simply take the user to the landing page of the app. If the refresh token request fails, we will redirect the user to the OAuth sign-in page again. */</span> -</span></span><span style="display:flex;"><span>app.get(<span style="color:#a50">&#39;/&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (!req.user) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> refreshAccessToken(req.user).then((tokenJson) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Dereference the user object and update the access token and refresh token in the in-memory object. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">let</span> usrObj = JSON.parse(JSON.stringify(req.user)); -</span></span><span style="display:flex;"><span> usrObj.accessToken = tokenJson.access_token; -</span></span><span style="display:flex;"><span> usrObj.refreshToken = tokenJson.refresh_token; -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Update the user object in PassportJS. No redirections will happen here, this is a purely internal operation. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> req.login(usrObj, () =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;index.html&#39;</span>)); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> }).<span style="color:#00a">catch</span>(() =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Refresh token failed, take the user to OAuth sign in page. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Refresh the access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> refreshAccessToken = <span style="color:#00a">async</span> (user) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> body = <span style="color:#a50">&#39;grant_type=refresh_token&amp;refresh_token=&#39;</span> + user.refreshToken + <span style="color:#a50">&#39;&amp;client_id=&#39;</span> + config.oauthClientId + <span style="color:#a50">&#39;&amp;client_secret=&#39;</span> + config.oauthClientSecret; -</span></span><span style="display:flex;"><span> <span style="color:#00a">let</span> res = <span style="color:#00a">await</span> fetch(config.oauthUrl + <span style="color:#a50">&#34;/oauth/token&#34;</span>, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;POST&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/x-www-form-urlencoded&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> body: body -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (res.ok) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#00a">await</span> res.json(); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">throw</span> <span style="color:#00a">new</span> <span style="color:#0aa">Error</span>(<span style="color:#a50">&#34;Could not refresh access token, please sign in again.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/api&#39;</span>, require(<span style="color:#a50">&#39;./api&#39;</span>)); -</span></span><span style="display:flex;"><span>module.exports = app; -</span></span></code></pre></div><ol start="2"> -<li>Save the file.</li> -<li>To see the authentication working in practice, you can follow the instructions in the <a href="https://github.com/onshape-public/app-gltf-viewer#readme">glTF Viewer README</a> to deploy the glTF Viewer app.</li> -</ol> -<h3 id="6-grant-authorization">6: Grant authorization</h3> -<p>For apps published in the Onshape App Store, the Onshape user must grant authorization to your application to access the Onshape data. This must be done by each user of your app.</p> -<p>To grant the application access to a user&rsquo;s data in Onshape, the <em>Onshape user</em> must follow the steps below:</p> -<ol> -<li>Sign in to <code>cad.onshape.com</code>. -<ul> -<li>Note: Use <code>https://companyName.onshape.com</code> for Enterprise accounts. See <a href="#enterprise-users">Enterprise users</a> below for more information.</li> -</ul> -</li> -<li>Click their name in the top-right corner of the Onshape window, and then click <strong>My account</strong> in the dropdown menu. -</br><img src="https://onshape-public.github.io/images/myaccountdropdown.png" alt="drawing" width="300"/></li> -<li>Click <strong>Applications</strong> in the left sidebar. -<ul> -<li>Note that the gltf-viewer app will not appear in this list until it has been deployed and subscribed to as described in the <a href="https://github.com/onshape-public/app-gltf-viewer#readme">glTF Viewer README</a>.</li> -</ul> -</li> -<li>Click <strong>Grant</strong> next to your app name to grant it access to their Onshape data. The Onshape user can click <strong>Revoke</strong> at any time to prevent your app from accessing their Onshape data.</li> -<li>The user will see the Authorize application screen shown below and will need to confirm their authorization grant by clicking <strong>Authorize application</strong>. The user is then redirected to the Redirect URL you specified in your code. Your app can now access the user&rsquo;s Onshape resources and profile.</li> -</ol> -<h2 id="notes">Notes</h2> -<h3 id="installed-desktop-applications">Installed desktop applications</h3> -<p>OAuth is designed for interactions between two servers using a browser. However, it can also be used by an installed desktop (or mobile) application. The application must perform a similar role to that of a third party server: it must exchange the code for an access token structure.</p> -<p>To enable this, Onshape allows two special forms of redirect URI to be registered:</p> -<ul> -<li><code>http://localhost:&lt;port&gt;</code> Causes the browser to attempt to load a page from the host upon which it is running. The code parameter will be supplied exactly the same as outlined above. If the application can listen on the registered port and behave as a simple web server for the redirect URL, it can retrieve the code in the same way as a deployed web server.</li> -<li><code>urn:ietf:wg:oauth:2.0:oob</code> Causes the browser to display a simple page after a request has been granted instead of going to a new URL. The page contains simple instructions to copy and paste code into an application field. The browser will also update the title of the window to contain the code. An application could also look for browsers with window titles containing the string <code>Success code=&lt;code&gt;</code> and automatically grab the code from the browser window title. If an error occurs (e.g., the grant is denied), the browser window title will contain <code>Error description=&lt;error string&gt;</code>.</li> -</ul> -<h3 id="enterprise-users">Enterprise users</h3> -<p>When a user authorizes an OAuth app to access Onshape on their behalf, they get a bearer token that corresponds to their session and the allowed scopes.</p> -<p>However, if the user has a seat in the Enterprise, additional information is needed to determine whether to allow the bearer token to access enterprise data for the user or simply return non-enterprise data. We use the <code>companyId</code> field for this distinction.</p> -<p>There are two ways of setting the <code>companyId</code> correctly to access enterprise data:</p> -<ul> -<li>During the authorization process, select the name and URL of the enterprise instead of <code>cad.onshape.com</code>. This will correctly associate your bearer token with the <code>companyId</code>.</li> -<li>If you have an integrated app, call the <a href="https://cad.onshape.com/glassworks/explorer/#/Company/findCompany">Company/findCompany</a> endpoint to obtain the <code>companyId</code>. Append this <code>companyId</code> as a query parameter to the <code>/authorize</code> URL while initiating the OAuth workflow. (Note: you may be asked to authenticate yourself again.)</li> -</ul> -<h3 id="3rd-party-cookies">3rd-party cookies</h3> -<p>3rd-party cookies must be enabled in the browser for Onshape apps to work correctly.</p> -<h3 id="debugging">Debugging</h3> -<p>Debugging OAuth can be a little tricky. Some tips are below:</p> -<ol> -<li>Make sure you are correctly URL encoding the values supplied to the oauth/authorize and oauth/token endpoints.</li> -<li>Use a <code>GET /oauth/authorize</code> but a <code>POST /oauth/token</code> and make sure that the GET uses query parameters but that the <code>POST</code> uses a URL-encoded form body.</li> -<li>If you supply a <code>redirect_uri</code> to <code>/oauth/authorize</code>, you must also supply it as an additional parameter in the <code>POST</code> to <code>/oauth/token</code></li> -<li>Use a tool such as <a href="https://portswigger.net/burp">Burp</a> or <a href="http://charlesproxy.com">Charles</a> to deliberately &lsquo;man-in-the-middle&rsquo; the connection requests between your server and Onshape, and verify that you are performing the correct REST operations (GET vs. POST) and correctly URL-encoding the parameter values.</li> -</ol> -<h2 id="final-code">Final Code</h2> -<p>The above example uses Node.js to authenticate an Onshape app. This section includes the code for using OAuth2 with other coding languages.</p> -<h3 id="nodejs">Node.js</h3> -<p><strong>Prerequisites</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>npm install passport -</span></span><span style="display:flex;"><span>npm install passport-onshape -</span></span></code></pre></div><p><strong>Environment variables</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>authorizationURL : &lt;https://oauth.onshape.com/oauth/authorize&gt; -</span></span><span style="display:flex;"><span>tokenURL : &lt;https://oauth.onshape.com/oauth/token&gt; -</span></span><span style="display:flex;"><span>userProfileURL : &lt;https://cad.onshape.com/api/users/sessioninfo&gt; -</span></span></code></pre></div><p><strong>app.js</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//App definitions -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> path = require(<span style="color:#a50">&#39;path&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> uuid = require(<span style="color:#a50">&#39;uuid&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> express = require(<span style="color:#a50">&#39;express&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> session = require(<span style="color:#a50">&#39;express-session&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> bodyParser = require(<span style="color:#a50">&#39;body-parser&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> passport = require(<span style="color:#a50">&#39;passport&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> OnshapeStrategy = require(<span style="color:#a50">&#39;passport-onshape&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> config = require(<span style="color:#a50">&#39;./config&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Tell Express to use Passport, and initialize it. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> app = express(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(express.<span style="color:#00a">static</span>(path.join(__dirname, <span style="color:#a50">&#39;dist&#39;</span>))); -</span></span><span style="display:flex;"><span>app.use(bodyParser.json()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.set(<span style="color:#a50">&#39;trust proxy&#39;</span>, <span style="color:#099">1</span>); <span style="color:#aaa;font-style:italic">// To allow to run correctly behind Heroku when deployed. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span>app.use(session({ -</span></span><span style="display:flex;"><span> secret: config.sessionSecret, -</span></span><span style="display:flex;"><span> saveUninitialized: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> resave: <span style="color:#00a">false</span>, -</span></span><span style="display:flex;"><span> cookie: { -</span></span><span style="display:flex;"><span> name: <span style="color:#a50">&#39;app-gltf-viewer&#39;</span>, -</span></span><span style="display:flex;"><span> sameSite: <span style="color:#a50">&#39;none&#39;</span>, -</span></span><span style="display:flex;"><span> secure: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> httpOnly: <span style="color:#00a">true</span>, -</span></span><span style="display:flex;"><span> path: <span style="color:#a50">&#39;/&#39;</span>, -</span></span><span style="display:flex;"><span> maxAge: <span style="color:#099">1000</span> * <span style="color:#099">60</span> * <span style="color:#099">60</span> * <span style="color:#099">24</span> <span style="color:#aaa;font-style:italic">// 1 day -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span>})); -</span></span><span style="display:flex;"><span>app.use(passport.initialize()); -</span></span><span style="display:flex;"><span>app.use(passport.session()); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Store the Onshape user information -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.serializeUser((user, done) =&gt; done(<span style="color:#00a">null</span>, user)); -</span></span><span style="display:flex;"><span>passport.deserializeUser((obj, done) =&gt; done(<span style="color:#00a">null</span>, obj)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Initialize Passport with the Onshape Strategy -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>passport.use(<span style="color:#00a">new</span> OnshapeStrategy({ -</span></span><span style="display:flex;"><span> clientID: config.oauthClientId, -</span></span><span style="display:flex;"><span> clientSecret: config.oauthClientSecret, -</span></span><span style="display:flex;"><span> callbackURL: config.oauthCallbackUrl, -</span></span><span style="display:flex;"><span> authorizationURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/authorize`</span>, -</span></span><span style="display:flex;"><span> tokenURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/oauth/token`</span>, -</span></span><span style="display:flex;"><span> userProfileURL: <span style="color:#a50">`</span><span style="color:#a50">${</span>config.oauthUrl<span style="color:#a50">}</span><span style="color:#a50">/api/users/sessioninfo`</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> (accessToken, refreshToken, profile, done) =&gt; { -</span></span><span style="display:flex;"><span> profile.accessToken = accessToken; -</span></span><span style="display:flex;"><span> profile.refreshToken = refreshToken; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> done(<span style="color:#00a">null</span>, profile); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>)); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Define the Onshape API endpoint -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.use(<span style="color:#a50">&#39;/oauthSignin&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* These 5 lines are specific to the glTF Viewer sample app. You can replace them with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> state = { -</span></span><span style="display:flex;"><span> docId: req.query.documentId, -</span></span><span style="display:flex;"><span> workId: req.query.workspaceId, -</span></span><span style="display:flex;"><span> elId: req.query.elementId -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> req.session.state = state; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { state: uuid.v4(state) })(req, res); -</span></span><span style="display:flex;"><span>}, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/oauthRedirect&#39;</span>, passport.authenticate(<span style="color:#a50">&#39;onshape&#39;</span>, { failureRedirect: <span style="color:#a50">&#39;/grantDenied&#39;</span> }), (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">/* This code is specific to the glTF Viewer sample app. You can replace it with the input for whatever Onshape endpoints you are using in your app. */</span> -</span></span><span style="display:flex;"><span> res.redirect(<span style="color:#a50">`/?documentId=</span><span style="color:#a50">${</span>req.session.state.docId<span style="color:#a50">}</span><span style="color:#a50">&amp;workspaceId=</span><span style="color:#a50">${</span>req.session.state.workId<span style="color:#a50">}</span><span style="color:#a50">&amp;elementId=</span><span style="color:#a50">${</span>req.session.state.elId<span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Handle denied access -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/grantDenied&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;grantDenied.html&#39;</span>)); -</span></span><span style="display:flex;"><span>}) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** After landing on the home page, we check if a user had already signed in. If no user has signed in, we redirect the request to the OAuth sign-in page. If a user had signed in previously, we will attempt to refresh the access token of the user. After successfully refreshing the access token, we will simply take the user to the landing page of the app. If the refresh token request fails, we will redirect the user to the OAuth sign-in page again. */</span> -</span></span><span style="display:flex;"><span>app.get(<span style="color:#a50">&#39;/&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (!req.user) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> refreshAccessToken(req.user).then((tokenJson) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Dereference the user object, and update the access token and refresh token in the in-memory object. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">let</span> usrObj = JSON.parse(JSON.stringify(req.user)); -</span></span><span style="display:flex;"><span> usrObj.accessToken = tokenJson.access_token; -</span></span><span style="display:flex;"><span> usrObj.refreshToken = tokenJson.refresh_token; -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Update the user object in PassportJS. No redirections will happen here, this is a purely internal operation. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> req.login(usrObj, () =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> res.sendFile(path.join(__dirname, <span style="color:#a50">&#39;public&#39;</span>, <span style="color:#a50">&#39;html&#39;</span>, <span style="color:#a50">&#39;index.html&#39;</span>)); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> }).<span style="color:#00a">catch</span>(() =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Refresh token failed, take the user to OAuth sign in page. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">return</span> res.redirect(<span style="color:#a50">`/oauthSignin</span><span style="color:#a50">${</span>req._parsedUrl.search ? req._parsedUrl.search : <span style="color:#a50">&#34;&#34;</span><span style="color:#a50">}</span><span style="color:#a50">`</span>); -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Refresh the access token -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">const</span> refreshAccessToken = <span style="color:#00a">async</span> (user) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> body = <span style="color:#a50">&#39;grant_type=refresh_token&amp;refresh_token=&#39;</span> + user.refreshToken + <span style="color:#a50">&#39;&amp;client_id=&#39;</span> + config.oauthClientId + <span style="color:#a50">&#39;&amp;client_secret=&#39;</span> + config.oauthClientSecret; -</span></span><span style="display:flex;"><span> <span style="color:#00a">let</span> res = <span style="color:#00a">await</span> fetch(config.oauthUrl + <span style="color:#a50">&#34;/oauth/token&#34;</span>, { -</span></span><span style="display:flex;"><span> method: <span style="color:#a50">&#39;POST&#39;</span>, -</span></span><span style="display:flex;"><span> headers: { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;Content-Type&#39;</span>: <span style="color:#a50">&#39;application/x-www-form-urlencoded&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> body: body -</span></span><span style="display:flex;"><span> }); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (res.ok) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> <span style="color:#00a">await</span> res.json(); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">throw</span> <span style="color:#00a">new</span> <span style="color:#0aa">Error</span>(<span style="color:#a50">&#34;Could not refresh access token, please sign in again.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app.use(<span style="color:#a50">&#39;/api&#39;</span>, require(<span style="color:#a50">&#39;./api&#39;</span>)); -</span></span><span style="display:flex;"><span>module.exports = app; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//Use the access token in an Authorization header. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>makeOnshapeAPICall: <span style="color:#00a">async</span> (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">try</span> { -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> apiUrl = <span style="color:#a50">&#34;https://cad.onshape.com/glassworks/explorer/#/Document/getDocuments&#34;</span>; <span style="color:#aaa;font-style:italic">//You can replace this with any Onshape API endpoint URL. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">const</span> resp = <span style="color:#00a">await</span> fetch(normalizedUrl, { headers: { Authorization: <span style="color:#a50">`Bearer </span><span style="color:#a50">${</span>req.user.accessToken<span style="color:#a50">}</span><span style="color:#a50">`</span> }}); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> data = <span style="color:#00a">await</span> resp.text(); -</span></span><span style="display:flex;"><span> <span style="color:#00a">const</span> contentType = resp.headers.get(<span style="color:#a50">&#39;Content-Type&#39;</span>); -</span></span><span style="display:flex;"><span> res.status(resp.status).contentType(contentType).send(data); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">catch</span> (err) { -</span></span><span style="display:flex;"><span> res.status(<span style="color:#099">500</span>).json({ error: err }); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><h3 id="python">Python</h3> -<p>This Python code only works on a local machine. To deploy the code, you can replace the Flask code with the web server of your choice.</p> -<p><strong>Prerequisites</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>pip3 install flask -</span></span><span style="display:flex;"><span>pip3 install requests_oauthlib -</span></span></code></pre></div><p><strong>app.py</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">flask</span> <span style="color:#00a">import</span> Flask, request, redirect, session, url_for -</span></span><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">flask.json</span> <span style="color:#00a">import</span> jsonify -</span></span><span style="display:flex;"><span><span style="color:#00a">from</span> <span style="color:#0aa;text-decoration:underline">requests_oauthlib</span> <span style="color:#00a">import</span> OAuth2Session -</span></span><span style="display:flex;"><span><span style="color:#00a">import</span> <span style="color:#0aa;text-decoration:underline">os</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>app = Flask(__name__) -</span></span><span style="display:flex;"><span>app.secret_key = <span style="color:#a50">b</span><span style="color:#a50">&#39;F</span><span style="color:#a50">\xf5\xe5\xc0\xbe\t</span><span style="color:#a50">g</span><span style="color:#a50">\x7f\xac\x89\x87</span><span style="color:#a50">e</span><span style="color:#a50">\xc2</span><span style="color:#a50">4</span><span style="color:#a50">\xe8</span><span style="color:#a50">m</span><span style="color:#a50">\x1c\xd9\xda\x96</span><span style="color:#a50">G,</span><span style="color:#a50">\x90</span><span style="color:#a50">i&#39;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>os.environ[<span style="color:#a50">&#39;OAUTHLIB_INSECURE_TRANSPORT&#39;</span>] = <span style="color:#a50">&#34;1&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>client_id = &lt;Client ID of your application&gt; -</span></span><span style="display:flex;"><span>client_secret = &lt;Client Secret of your application&gt; -</span></span><span style="display:flex;"><span>authorization_base_url = <span style="color:#a50">&#34;https://oauth.onshape.com/oauth/authorize&#34;</span> -</span></span><span style="display:flex;"><span>token_url = <span style="color:#a50">&#34;https://oauth.onshape.com/oauth/token&#34;</span> -</span></span><span style="display:flex;"><span>redirect_url = <span style="color:#a50">&#34;http://localhost:5000&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/&#39;</span>) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">home</span>(): -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> auth_url, state = onshape.authorization_url(authorization_base_url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_state&#39;</span>] = state -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> redirect(auth_url) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/token&#39;</span>, methods=[<span style="color:#a50">&#34;GET&#34;</span>]) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">token</span>(): -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, state=session[<span style="color:#a50">&#39;oauth_state&#39;</span>], redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> token = onshape.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_token&#39;</span>] = token -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> redirect(url_for(<span style="color:#a50">&#39;.documents&#39;</span>)) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#888">@app.route</span>(<span style="color:#a50">&#39;/documents&#39;</span>, methods=[<span style="color:#a50">&#34;GET&#34;</span>]) -</span></span><span style="display:flex;"><span><span style="color:#00a">def</span> <span style="color:#0a0">documents</span>(): -</span></span><span style="display:flex;"><span> extra = { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;client_id&#39;</span>: client_id, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;client_secret&#39;</span>: client_secret, -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> onshape = OAuth2Session(client_id, token=session[<span style="color:#a50">&#39;oauth_token&#39;</span>], redirect_uri=redirect_url) -</span></span><span style="display:flex;"><span> session[<span style="color:#a50">&#39;oauth_token&#39;</span>] = onshape.refresh_token(token_url, **extra) -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> jsonify(onshape.get(<span style="color:#a50">&#39;https://cad.onshape.com/api/v6/documents?q=Untitled&amp;ownerType=1&amp;sortColumn=createdAt&amp;sortOrder=desc&amp;offset=0&amp;limit=20&#39;</span>).json()) -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">if</span> __name__ == <span style="color:#a50">&#34;__main__&#34;</span>: -</span></span><span style="display:flex;"><span> app.run() -</span></span><span style="display:flex;"><span> -</span></span></code></pre></div>Docs: API Keyshttps://onshape-public.github.io/docs/auth/apikeys/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/auth/apikeys/ -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a> page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.</p> -</blockquote> -<h2 id="why-api-keys">Why API Keys?</h2> -<p>API keys are useful for small applications meant for personal use, allowing developers to avoid the overhead of the OAuth workflow. Creating an app is very easy with API keys: create an API key with the Developer Portal, set up a function to build your API key header as in the samples, and make your API calls! There&rsquo;s no need to deal with OAuth redirects or things like that.</p> -<p>We&rsquo;ve moved over to using API keys for authenticating requests instead of using cookies for several reasons.</p> -<ol> -<li>Security: Each request is signed with unique headers so that we can be sure it&rsquo;s coming from the right place.</li> -<li>OAuth: The API key system we&rsquo;re now using for HTTP requests is the same process developers follow when building full-blown OAuth applications; there&rsquo;s no longer a disconnect between the two.</li> -</ol> -<p>Once you create an API key, it will only be valid in the stack on which it was created. An API key created on the partner stack, for example, will not function on the production stack.</p> -<p>If you need information or have a question unanswered in this documentation, feel free to chat with us by sending an email to <a href="mailto:api-support@onshape.com">api-support@onshape.com</a> or by checking out the <a href="https://forum.onshape.com" target="_blank">forums</a>. If you are a member of the DevPartners group (see the Development help page for information) more detailed instructions and code examples are in the apikey sample repo.</p> -<h2 id="1-create-api-keys">1. Create API Keys</h2> -<ol> -<li>Go to <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</li> -<li>In the left pane, click <code>API keys</code>.</li> -<li>Click the <code>Create new API key</code> button.</li> -<li>Select the desired permissions for your app.</li> -<li>Click the <code>Create API key</code> button. </br> -<img src="https://onshape-public.github.io/images/CreateNewAPIKey.png" alt="image"></li> -<li>Copy both the <strong>access key</strong> and <strong>secret key</strong> from the pop-up window, save them somewhere, then click the <code>Close</code> button. -</br><strong>IMPORTANT NOTE: You will not be able to find the secret key again, so save it somewhere safe!</strong></br> -<img src="https://onshape-public.github.io/images/APIKeySecretKey.png" alt="image"></li> -<li>The details for your application appear. </br> -<img src="https://onshape-public.github.io/images/DevPortalKeys.png" alt="image"></li> -<li>Now that you have a key pair, see <a href="#generating-a-request-signature">Generate a Request Signature</a> for information on signing your requests to use our API.</li> -</ol> -<p>Once you have your access key and secret, you will want to avoid giving others access to them, since they&rsquo;re tied directly to your personal Onshape account. Think of your API key as a username and password pair. Do not place them directly in the code for your application, especially if others might see it. The samples we provide here use a separate configuration file to contain this information, but there are other ways to keep the access key and secret safe, like setting them as environment variables.</p> -<h3 id="scopes">Scopes</h3> -<p>There are several scopes available for API keys (equivalent to OAuth scopes):</p> -<ul> -<li><code>OAuth2Read</code> - Read non-personal information (documents, parts, etc.)</li> -<li><code>OAuth2ReadPII</code> - Read personal information (name, email, etc.)</li> -<li><code>OAuth2Write</code> - Create and edit documents, etc.</li> -<li><code>OAuth2Delete</code> - Delete documents, etc.</li> -<li><code>OAuth2Purchase</code> - Authorize purchases from account</li> -</ul> -<h2 id="2-select-an-authentication-option">2. Select an Authentication Option</h2> -<p>Please select an option for authentication:</p> -<ul> -<li><a href="#local-authorization">Basic Authorization</a>: Lowest security. For local testing only.</li> -<li><a href="#request-signature">Request Signature</a>: Medium security. For testing and internal use.</li> -<li><a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>: Highest security. Required for all Onshape Apps.</li> -</ul> -<h2 id="basic-authorization">Basic Authorization</h2> -<p>For local testing, you can provide a basic authentication via your API Keys.</p> -<ol> -<li>Open your terminal and run the following command, replacing <code>ACCESS_KEY</code> and <code>SECRET_KEY</code> with the <strong>access key</strong> and <strong>secret key</strong> you created earlier. Remember to include the colon (<code>:</code>) between the keys. <em>You will receive a long, base-64-encoded string as output.</em> -<ul> -<li><strong>MacOS</strong>: -<pre tabindex="0"><code>printf ACCESS_KEY:SECRET_KEY | base64 -</code></pre></li> -<li><strong>Windows</strong>: -<pre tabindex="0"><code>powershell &#34;[convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\&#34;ACCESS_KEY:SECRET_KEY\&#34;))&#34; -</code></pre></li> -</ul> -</li> -<li>Add the authorization header to your code, replacing <code>CREDENTIALS</code> with the string you receieved in Step 1: -<pre tabindex="0"><code>-H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -</ol> -<p>See our <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start Guide</a> for an example of using Basic Authorization in an app.</p> -<h2 id="request-signature">Request Signature</h2> -<p>For additional security, you can include your API Keys as part of a request signature. This provides more security than the Basic Authorization above, but less security than OAuth2.</p> -<p>To ensure that a request is coming from you, we have a process for signing requests that you must follow for API calls to work. Everything is done via HTTP headers that you&rsquo;ll need to set:</p> -<ol> -<li><em>Date</em>: A standard date header giving the time of the request; must be accurate within <strong>5 minutes</strong> of request. Example: <code>Mon, 11 Apr 2016 20:08:56 GMT</code></li> -<li><em>On-Nonce</em>: A string that satisfies the following requirements (see the code for one possible way to generate it): -<ul> -<li>At least 16 characters</li> -<li>Alphanumeric</li> -<li>Unique for each request</li> -</ul> -</li> -<li><em>Authorization</em>: This is where the API keys come into play. You&rsquo;ll sign the request by implementing this algorithm: -<ul> -<li><strong>Input</strong>: Method, URL, On-Nonce, Date, Content-Type, AccessKey, SecretKey</li> -<li><strong>Output</strong>: String of the form: <code>On &lt;AccessKey&gt;:HmacSHA256:&lt;Signature&gt;</code></li> -<li><strong>Steps to generate the signature portion</strong>: -<ol> -<li>Parse the URL and get the following: -<ol> -<li>The path, e.g. <code>/api/documents</code> (no query params!)</li> -<li>The query string, e.g. <code>a=1&amp;b=2</code> -<ul> -<li>NOTE: If no query paramaters are present, use an empty string</li> -</ul> -</li> -</ol> -</li> -<li>Create a string by appending the following information in order. Each field should be separated by a newline (<code>\n</code>) character, and the string must be converted to lowercase: -<ol> -<li>HTTP method</li> -<li>On-Nonce header value</li> -<li>Date header value</li> -<li>Content-Type header value</li> -<li>URL pathname</li> -<li>URL query string</li> -</ol> -</li> -<li>Using SHA-256, generate an <a href="https://en.wikipedia.org/wiki/Hash-based_message_authentication_code" target="_blank">HMAC digest</a>, using the API secret key first and then the above string, then encode it in Base64.</li> -<li>Create the <code>On &lt;AccessKey&gt;:HmacSHA256:&lt;Signature&gt;</code> string and use that in the Authorization header in your request.</li> -</ol> -</li> -</ul> -</li> -</ol> -<p>Below is an example function to generate the authorization header, using Node.js&rsquo;s standard <code>crypto</code> and <code>url</code> libraries:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">// ...at top of file -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span><span style="color:#00a">var</span> u = require(<span style="color:#a50">&#39;url&#39;</span>); -</span></span><span style="display:flex;"><span><span style="color:#00a">var</span> crypto = require(<span style="color:#a50">&#39;crypto&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">/** -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* Generates the &#34;Authorization&#34; HTTP header for using the Onshape API -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} method - Request method; GET, POST, etc. -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} url - The full request URL -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} nonce - 25-character nonce (generated by you) -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} authDate - UTC-formatted date string (generated by you) -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} contentType - Value of the &#34;Content-Type&#34; header; generally &#34;application/json&#34; -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} accessKey - API access key -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @param {string} secretKey - API secret key -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">* @return {string} Value for the &#34;Authorization&#34; header -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">*/</span> -</span></span><span style="display:flex;"><span><span style="color:#00a">function</span> createSignature(method, url, nonce, authDate, contentType, accessKey, secretKey) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlObj = u.parse(url); -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlPath = urlObj.pathname; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> urlQuery = urlObj.query ? urlObj.query : <span style="color:#a50">&#39;&#39;</span>; <span style="color:#aaa;font-style:italic">// if no query, use empty string -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> str = (method + <span style="color:#a50">&#39;\n&#39;</span> + nonce + <span style="color:#a50">&#39;\n&#39;</span> + authDate + <span style="color:#a50">&#39;\n&#39;</span> + contentType + <span style="color:#a50">&#39;\n&#39;</span> + -</span></span><span style="display:flex;"><span> urlPath + <span style="color:#a50">&#39;\n&#39;</span> + urlQuery + <span style="color:#a50">&#39;\n&#39;</span>).toLowerCase(); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> hmac = crypto.createHmac(<span style="color:#a50">&#39;sha256&#39;</span>, secretKey) -</span></span><span style="display:flex;"><span> .update(str) -</span></span><span style="display:flex;"><span> .digest(<span style="color:#a50">&#39;base64&#39;</span>); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> signature = <span style="color:#a50">&#39;On &#39;</span> + accessKey + <span style="color:#a50">&#39;:HmacSHA256:&#39;</span> + hmac; -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span> signature; -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h3 id="redirects">Redirects</h3> -<p>Some API endpoints return 307 redirects. You must generate an Authorization header for the redirect as well, but please note that the server portion of the URL might be different, the redirect URL may contain query parameters that must be encoded in the Authorization header, etc.</p>Docs: Assemblieshttps://onshape-public.github.io/docs/api-adv/assemblies/Tue, 13 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/assemblies/ -<p>This page describes the APIs Onshape provides for working with assemblies.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/createInstance">Assembly/createInstance</a>: Insert an instance of a part, sketch, assembly, or Part Studio into an assembly: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/assemblies/d/{targetDid}/w/{targetWid}/e/{targetEid}/instances&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; --d &#39;{ -&#34;configuration&#34;: &#34;string&#34;, -&#34;documentId&#34;: &#34;{sourceDid}&#34;, -&#34;elementId&#34;: &#34;{sourceEid}&#34;, -&#34;featureId&#34;: &#34;string&#34;, -&#34;includePartTypes&#34;: [ -&#34;PARTS&#34; -], -&#34;isAssembly&#34;: true, -&#34;isHidden&#34;: true, -&#34;isSuppressed&#34;: true, -&#34;isWholePartStudio&#34;: true, -&#34;microversionId&#34;: &#34;string&#34;, -&#34;partId&#34;: &#34;string&#34;, -&#34;partNumber&#34;: &#34;string&#34;, -&#34;revision&#34;: &#34;string&#34;, -&#34;versionId&#34;: &#34;{sourceEid}&#34; -}&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="insert-a-part-into-an-assembly">Insert a part into an assembly</h3> -<ol> -<li>Open the Part Studio that contains the part you want to insert into an assembly. Make a note of the following in the URL: -<ul> -<li><code>documentId</code> - we&rsquo;ll refer to this as our <code>sourceDid</code> for this example</li> -<li><code>elementId</code> of the Part Studio that contains the part - this is our <code>sourceEid</code></li> -<li><code>versionId</code> - this is our <code>sourceVId</code>, if one exists</li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> endpoint to get the part&rsquo;s <code>partId</code>: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/parts/d/{did}/w/{wid}/e/{eid}?withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>Now open the assembly you want to insert the part into. Make a note of the following from the URL: -<ul> -<li><code>documentId</code> - we&rsquo;ll refer to this as our <code>targetDid</code></li> -<li><code>workspaceId</code> - this is our <code>targetWId</code></li> -<li><code>elementId</code> of the assembly - this is our <code>targetEid</code></li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/createInstance">Assembly/createInstance</a> endpoint on the assembly to insert an instance of the part into the assembly: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/assemblies/d/{targetDid}/w/{targetWid}/e/{targetEid}/instances&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;documentId&#34;: &#34;{sourceDid}&#34;, -&#34;elementId&#34;: &#34;{sourceEid}&#34;, -&#34;includePartTypes&#34;: [ -&#34;PARTS&#34; -], -&#34;partId&#34;: &#34;{partId}&#34; -}&#39; -</code></pre><ul> -<li>Note: you can add <code>&quot;versionId&quot;: &quot;{sourceVid}&quot;</code> to the request body if needed.</li> -</ul> -</li> -<li>Refresh your assembly and confirm the part is included.</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly">API Explorer: Assemblies</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/assembly.htm">Onshape Help: Assemblies</a></li> -</ul>Docs: Associativityhttps://onshape-public.github.io/docs/api-adv/associativity/Mon, 18 May 2020 20:28:26 -0400https://onshape-public.github.io/docs/api-adv/associativity/ -<p>Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be:</p> -<ol> -<li>Read the tessellated model data.</li> -<li>Select the face of interest.</li> -<li>Store the Face ID and Document Microversion ID for the face.</li> -<li>[ user changes model ]</li> -<li>Call the REST API to translate from the known Face ID to an ID in the new model.</li> -<li>Re-apply application-specific data to the face(s) in the new model. Note that a face may become zero, one or multiple faces in the new model, depending on what changes the user made.</li> -</ol> -<h2 id="associativity-example">Associativity Example</h2> -<ol> -<li>Create a cube in Onshape:</br> -<img src="https://onshape-public.github.io/images/associativityimage03.png" alt="image alt text"></li> -<li>Get the document microversion ID from the URL: <code>https://cad.onshape.com/api/d/&lt;docid&gt;/w/&lt;wid&gt;/microversionId</code>.</li> -<li>Use the appropriate REST API to get the tessellated faces (<code>getPartStudioFaces</code>) -and edges (<code>getPartStudioEdges</code>}. Note the ids: -<ul> -<li>Part ID: <code>JHD</code></li> -<li>Front face ID: <code>JHO</code></li> -<li>Top edge of the front face ID: <code>JHd</code></li> -<li>Right edge of the top face ID: <code>JHt</code></li> -</ul> -</li> -<li>Split cube with the Front plane and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage00.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span> ] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;SPLIT&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>, <span style="color:#a50">&#34;JIH&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHO&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHd&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;SPLIT&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JI5&#34;</span>, <span style="color:#a50">&#34;JI9&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;78bc7f3fcf82475085c2f3ab&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><ol start="4"> -<li>Delete one of the parts, and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage01.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span>] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;FAILED_TO_RESOLVE&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;FAILED_TO_RESOLVE&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JI5&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;52aa74d34b624f3aaef33204&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><ol start="5"> -<li>Roll back the delete and the split, and translate the IDs:</li> -</ol> -<p><img src="https://onshape-public.github.io/images/associativityimage02.png" alt="image alt text"></p> -<p><strong>POST</strong></p> -<pre tabindex="0"><code>https://cad.onshape.com/api/partstudios/d/&lt;docid&gt;/w/&lt;wid&gt;/e/&lt;eid&gt;/idtranslations -</code></pre><p><strong>Body</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span> : <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span> : [<span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#a50">&#34;JHt&#34;</span>] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>Response</strong>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;748d6e850c9248328189922b&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;042a6fa54e79451e8076463d&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;sourceDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;47e75ab2ee8b4356a76ebd47&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;ids&#34;</span>: [ -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHD&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JID&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHO&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHO&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHd&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHd&#34;</span>] }, -</span></span><span style="display:flex;"><span> { <span style="color:#1e90ff;font-weight:bold">&#34;source&#34;</span>: <span style="color:#a50">&#34;JHt&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;status&#34;</span>: <span style="color:#a50">&#34;OK&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;target&#34;</span>: [<span style="color:#a50">&#34;JHt&#34;</span>] } -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;targetDocumentMicroversion&#34;</span>: <span style="color:#a50">&#34;52aa74d34b624f3aaef33204&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div>Docs: Billinghttps://onshape-public.github.io/docs/api-adv/billing/Mon, 18 May 2020 20:29:36 -0400https://onshape-public.github.io/docs/api-adv/billing/ -<p>This document describes APIs that will allow partners to interact with the Onshape billing system.</p> -<p>Please address questions to &ldquo;<a href="mailto:api-support@onshape.com">api-support@onshape.com</a>&rdquo; for the fastest response.</p> -<h2 id="overview">Overview</h2> -<p>All billing is done through &ldquo;plans&rdquo; that are created in the Developer Portal. A “plan” has the following attributes:</p> -<table> -<tr> -<td>Name (also called SKU)</td> -<td>A unique (within your company) plan name</td> -</tr> -<tr> -<td>Description</td> -<td>A user-visible description of the plan</td> -</tr> -<tr> -<td>Amount</td> -<td>The cost of the plan (may be one-time or recurring, depending on the type)</td> -</tr> -<tr> -<td>Type</td> -<td>Monthly, One-time or Consumable</td> -</tr> -</table> -<p>Onshape defines three kinds of plans:</p> -<table> -<tr> -<td>Plan type</td> -<td>Description</td> -</tr> -<tr> -<td>Recurring -(Monthly Subscription)</td> -<td>A plan that is renewed monthly at a fixed cost. All Apps in the app store must have a Free monthly plan (which is created by default), and may have additional paid plans.</td> -</tr> -<tr> -<td>One-time</td> -<td>A plan that is purchased once (not renewed monthly). A user may purchase these multiple times.</td> -</tr> -<tr> -<td>Consumable</td> -<td>A plan that represents a consumable unit, such as "hours of rendering" or “simulation runs”. Consumable plans are not fully implemented at this time, but the consumable functionality can be implemented using One-time Purchase plans as described below.</td> -</tr> -</table> -<p>Users may purchase plans through the App Store interface. In addition, if your application has the OAuth Purchase Scope, your application can initiate &ldquo;in-app&rdquo; purchases by calling Onshape to request a purchase.</p> -<p>The basic steps for interacting with Onshape Billing:</p> -<ol> -<li>Define one or more plans using the Developer Portal interface</li> -<li>Use the Onshape API to determine the current user’s plan</li> -<li>Provide features and/or limits based on the current plan</li> -</ol> -<h2 id="using-the-onshape-billing-api">Using the Onshape Billing API</h2> -<p><code>GET /api/accounts/purchases</code></p> -<p>Returns a list of purchase made by the current user for plans owned by the current application. Use this information to determine what capabilities or features the user is entitled to use.</p> -<p><code>DELETE /api/accounts/purchases/&lt;purchase id&gt;</code></p> -<p>Cancel a recurring purchase.</p> -<p><code>POST /api/accounts/purchases/&lt;purchase id&gt;/consume</code></p> -<p>Indicate the use of a consumable. (Not fully implemented at this time)</p> -<p><code>GET /api/billing/plans/client/&lt;client id&gt;</code></p> -<p>Get a list of the billing plans defined for this client.</p> -<h2 id="initiating-a-purchase-from-an-application-in-app-purchases">Initiating a purchase from an application (in-app purchases)</h2> -<p>To initiate a purchase of a subscription or one time item you must set the browser’s location to particular URL within the Onshape stack:</p> -<p><code>https://cad.onshape.com/billing/purchase?redirectUri=RRRR&amp;clientId=CCCC&amp;sku=SSSS&amp;userId=UUUU</code></p> -<p>Each of the query parameters should be URL encoded. The clientId is your application’s OAuth Client ID, the sku is the name/sku field for an item (you can find this in the developer portal or it’s retrievable through the /api/billing/plans REST endpoints). The user Id should be the Onshape user Id for the current user and is available through the /api/users/session REST endpoint. The redirectUri is the URI the user will be returned to within your website when the purchase is finished.</p> -<p>When the browser’s location is changed to this pattern the Onshape stack will serve content to confirm the users identity, confirm the details of what is being purchased (or obtained if the item is free) and then after the user agrees to the purchase will confirm the transaction (with our payment processor if the item is not free) and then redirect the user back to the supplied redirectUri (the browser location will be changed to the redirectUri). Additionally Onshape will add a <code>success=true</code> or <code>success=false</code> query parameter to the redirectURI indicating whether the user completed successfully (payment was taken if required etc.) or failed, either due to cancelling the purchase or an issue with payment.</p> -<p>When the browser fetches the redirectUri your application must call back through the <code>/api/account/purchases</code> API to get confirmation of the purchase - do NOT assume that a fetch of the redirectUri with a <code>success=true</code> query parameter actually indicates a purchase has occurred. Query the Onshape stack with the <code>/api/account/purchases</code> API to ensure that the required item has actually been bought.</p> -<h2 id="consumable-items">Consumable Items</h2> -<p>A detailed description of the interface for managing consumable purchases will be provided shortly. You can use one-time plans to achieve similar results:</p> -<ol> -<li> -<p>Define a one-time purchase plan with a description indicating the nature of the purchase, for example:</p> -<p>RENDER-10 Ten rendering hours $100</p> -</li> -<li> -<p>Keep track of the number of hours that the user has consumed. You can store and retrieve this information in Onshape using the following APIs. These APIs allow you to store and retrieve arbitrary information on a per-user basis.</p> -<p>POST /applications/clients/:cid/settings/users/:uid -GET /applications/clients/:cid/settings/users/:uid</p> -</li> -<li> -<p>Check the number of available &ldquo;units&rdquo; by getting the purchases and the record of consumables. Be sure to include UI in your application that the user can use to see their remaining quantity.</p> -</li> -<li> -<p>Alternately, you can store the consumption data in your own system; you do not need to use the Onshape API to manage that data.</p> -</li> -</ol> -<p>Onshape intends to provide a richer set of APIs that help track the purchase and consumption of consumables in the near future.</p> -<h2 id="other-billing-models">Other billing models</h2> -<p>You can use these mechanisms to implement other models. For example, a time-limited trial could be implemented by scanning purchases for the first &ldquo;purchase&rdquo; and denying service if it is more than a defined number of days in the past. A “fixed number of uses per month” could be implemented as a monthly subscription, string usage data with the settings API, and denying service after a fixed number of uses.</p> -<h2 id="samples">Samples</h2> -<p>Onshape will provide sample code for both desktop and integrated applications demonstrating the use of the billing APIs and workflow. If you are subscribed to the Onshape Github Partner group, you will have access to those samples as soon as they are posted.</p> -<h2 id="testing">Testing</h2> -<p>Please contact <a href="mailto:api-support@onshape.com">api-support@onshape.com</a> to discuss details of testing billing &amp; subscriptions.</p>Docs: Configurationshttps://onshape-public.github.io/docs/api-adv/configs/Fri, 05 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/configs/ -<p>This page describes the APIs Onshape provides for working with <a href="https://cad.onshape.com/help/Content/configurations.htm">Configurations</a>.</p> -<p>You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing. You can also create your own Configurations for an Assembly, regardless of any existing Part Studio Configurations. Assembly Configurations work the same way as Part Studio Configurations, but are limited to configuring Mates (<em>not</em> Mate connectors), instances, and patterns.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a>: Get the configuration data for a Part Studio or Assembly. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/updateConfiguration">Element/updateConfiguration</a>: Update the configuration data for a Part Studio or Assembly. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ }&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/decodeConfiguration">Element/decodeConfiguration</a>: Process an encoded configuration file. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/wvm/{wvmid}/e/{eid}/configurationencodings/{encodingId}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a>: Create an encoded map of configurations. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;{configValue}&#34; -} -] -}&#39; -</code></pre></li> -</ul> -<h3 id="encoded-configuration-strings">Encoded Configuration Strings</h3> -<p>The <a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a> and <a href="https://cad.onshape.com/glassworks/explorer/#/Element/decodeConfiguration">Element/decodeConfiguration</a> APIs convert parameters from JSON to a URL-encoded string in the following format: <code>&quot;configuration=parameterId%3DparameterValue&quot;</code></p> -<p>For example,</p> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;List_izOjbm5HCRXEld&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -} -</code></pre><p>encodes to:</p> -<pre tabindex="0"><code>&#34;configuration=List_izOjbm5HCRXEld%3D_500_mm&#34; -</code></pre><p>and:</p> -<pre tabindex="0"><code>&#34;configuration=List_izOjbm5HCRXEld%3DDefault&#34; -</code></pre><p>decodes to:</p> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;List_izOjbm5HCRXEld&#34;, -&#34;parameterValue&#34;: &#34;Default&#34; -} -] -} -</code></pre><h2 id="sample-workflows">Sample Workflows</h2> -<p>These sample workflows all build off one another. Completing all of the workflows will take you step-by-step through the process of getting Configuration information, encoding the information for use, and using the encoded configuration to create a configured export. You can also watch the <a href="#workflow-video">video</a> to see the entire workflow in the Glassworks API Explorer.</p> -<h3 id="get-a-configuration">Get a Configuration</h3> -<p>In this example, we&rsquo;ll use the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a> endpoint to get the Configuration information from a Part Studio.</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID.</li> -<li>Click the Configurations dropdown in the Features list, and observe that there are two options for the drillbit length, <code>250 mm</code> and <code>500 mm</code>. -</br></br><img src="https://onshape-public.github.io/images/configs-example-ui.png" alt=" " width=550></li> -<li>Set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/getConfiguration">Element/getConfiguration</a> endpoint to get the Configuration for the Part Studio. Don&rsquo;t forget to replace the URL parameters with the IDs from your copy of the document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/w/{wid}/e/{eid}/configuration&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -<li>Review the Configuration information detailed in the response. You can see that the Part Studio contains one configuration (<code>Drill_Bit_Length</code>) with two options (<code>250 mm</code> and <code>500 mm</code>): -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTConfigurationResponse-2019&#34;, -&#34;currentConfiguration&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;namespace&#34;: &#34;&#34;, -&#34;nodeId&#34;: &#34;{nodeId1}&#34;, -&#34;value&#34;: &#34;Default&#34;, -&#34;enumName&#34;: &#34;{paramId_conf}&#34;, -&#34;parameterId&#34;: &#34;{paramId}&#34; -} -], -&#34;configurationParameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMConfigurationParameterEnum-105&#34;, -&#34;defaultValue&#34;: &#34;Default&#34;, -&#34;enumName&#34;: &#34;{enumName}&#34;, -&#34;namespace&#34;: &#34;&#34;, -&#34;options&#34;: [ -{ -&#34;btType&#34;: &#34;BTMEnumOption-592&#34;, -&#34;optionName&#34;: &#34;250 mm&#34;, -&#34;option&#34;: &#34;Default&#34;, -&#34;nodeId&#34;: &#34;{nodeId2}&#34; -}, -{ -&#34;btType&#34;: &#34;BTMEnumOption-592&#34;, -&#34;optionName&#34;: &#34;500 mm&#34;, -&#34;option&#34;: &#34;_500_mm&#34;, -&#34;nodeId&#34;: &#34;{nodeId3}&#34; -} -], -&#34;isCosmetic&#34;: false, -&#34;parameterId&#34;: &#34;{paramId}&#34;, -&#34;parameterName&#34;: &#34;Drill_Bit_Length&#34;, -&#34;nodeId&#34;: &#34;{nodeId4}&#34; -} -], -&#34;serializationVersion&#34;: &#34;1.2.0&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 2296 -} -</code></pre></li> -</ol> -<h3 id="encode-a-configuration-string">Encode a configuration string</h3> -<p>In this example, we&rsquo;ll encode a Configuration so it can be used as part of a translation (i.e., an export). Please read the <a href="#encoded-configuration-strings">Encoded Configuration Strings</a> section before beginning this example.</p> -<ol> -<li>This example builds off the previous one. Please complete the <a href="#get-a-configuration">Get a Part Studio Configuration</a> workflow to obtain the raw Configuration output for the Part Studio.</li> -<li>Set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/Element/encodeConfigurationMap">Element/encodeConfigurationMap</a> endpoint. Don&rsquo;t forget to replace the URL parameters with the IDs from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ }&#39; -</code></pre></li> -<li>Now we need to create our JSON body for the request. Note the structure of the body: -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;string&#34;, -&#34;parameterValue&#34;: &#34;string&#34; -} -], -&#34;standardContentParametersId&#34;: &#34;string&#34; -} -</code></pre>Fill out the request body with our information: -<ul> -<li>We&rsquo;re not using a standard content part, so we can delete the second key/value pair.</li> -<li>The parameterId can be found in the response from the previous example. It usually begins with (<code>List_</code>)</li> -<li>For the parameter value, we&rsquo;ll enter one of our configuration options from the previous example. In this case, we&rsquo;ll use <code>_500_mm</code> to export a 500 mm drillbit part.</li> -</ul> -<pre tabindex="0"><code>{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -} -</code></pre></li> -<li>Now we can make our call: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/elements/d/{did}/e/{eid}/configurationencodings&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;parameters&#34;: [ -{ -&#34;parameterId&#34;: &#34;{parameterId}&#34;, -&#34;parameterValue&#34;: &#34;_500_mm&#34; -} -] -}&#39; -</code></pre></li> -<li>The call responds with two values: the ID of the encoding, and the encoded configuration string. We can use this configuration string (returned in the <code>queryParam</code> field) any time we want to specify the 500 mm drillbit length. -<pre tabindex="0"><code>{ -&#34;encodedId&#34;: &#34;{encodedId}&#34;, -&#34;queryParam&#34;: &#34;configuration={configString}&#34; -} -</code></pre></li> -</ol> -<h3 id="export-a-configured-part">Export a configured part</h3> -<p>In this example, we will export a configured part. We have a drillbit with two configurations: <code>250 mm</code> and <code>500 mm</code> lengths. To export a 500 mm drillbit, we can specify the configuration as part of the export.</p> -<ol> -<li>This example builds off the previous two. Please complete this exercise after the <a href="#encode-a-configuration">Encode a configuration</a> workflow.</li> -<li>Next, set up a call to the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportParasolid">PartStudio/exportParasolid</a> endpoint. Don&rsquo;t forget to replace the URL parameters with the IDs from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. Note that this endpoint includes an optional <code>configuration</code> parameter. This is where we&rsquo;ll enter the configuration string we found in the previous example. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/parasolid?version=0&amp;includeExportIds=false&amp;configuration={configString}&amp;binaryExport=false&#39; \ --H &#39;Accept: */*&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre></li> -<li>This endpoint returns a redirect URL. Navigate to the returned URL in your browser to download the export. -<ul> -<li>Hint: The URL will look something like this, but with different IDs:</li> -</ul> -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851/parasolid?version=0&amp;includeExportIds=false&amp;configuration=List_izOjbm5HCRXEld%253D_500_mm&amp;binaryExport=false -</code></pre></li> -<li>Now we need to import our Parasolid to confirm the correct configuration was used. Open your document in the Onshape UI, click the Insert new tab button, and then select Import. -</br><img src="https://onshape-public.github.io/images/configs-insert-menu.png" alt="Insert new tab menu with Import highlighted in Onshape UI" width=250></li> -<li>Navigate to the export you downloaded (with the <code>.x_t</code> extension) and import it into Onshape.</li> -<li>Use the measure tool to confirm the length of the imported drillbit is 500 mm. -</br><img src="https://onshape-public.github.io/images/configs-measure-tool.png" alt="Measure tool in Onshape UI showing drill length as 500 mm" width=400></li> -</ol> -<h2 id="workflow-video">Workflow Video</h2> -<p>This video demonstrates how to complete the above tutorials in the Onshape API Explorer. -</br></p> -<p> -<div class="wistia_responsive_padding" style="padding:77.08% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><iframe src="https://fast.wistia.net/embed/iframe/o4pvoyjwuk?seo=true&videoFoam=true" title="configs-export-example Video" allow="autoplay; fullscreen" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" msallowfullscreen width="100%" height="100%"></iframe></div></div> -<script src="https://fast.wistia.net/assets/external/E-v1.js" async></script> -</p> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Element">API Explorer: Configurations</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/configurations.htm">Onshape Help: Configurations</a></li> -</ul>Docs: Drawingshttps://onshape-public.github.io/docs/api-adv/drawings/Thu, 12 Oct 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/drawings/ -<p>This page describes the APIs Onshape provides for creating and manipulating Onshape drawings.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<p>To create drawings, Onshape allows you to send all drawing data points and information through the API as part of the request body JSON.</p> -<p>The following endpoints are available:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Create a drawing</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON request body options from the BTDrawingParams schema&gt; -}&#39; -</code></pre>Specify the document in which to create the drawing in the URL, and pass any additional options as part of the request body. You can provide a name for the drawing, manipulate the drawing graphics area, specify a part or template to create the drawing from, and more. -<ul> -<li>See documentation for all available options in the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">API Explorer</a>.</li> -<li>For instructions on viewing the documentation for the request body schemas, see our <a href="https://onshape-public.github.io/docs/api-intro/explorer#view-request-body-docs">API Explorer</a> page. -Check out the <a href="#sample-workflows">Sample Workflows</a> section below for some practical examples.<p></br> -<img src="https://onshape-public.github.io/images/BTDrawingParamsSchema.png" alt="BTDrawingParams schema in the createDrawingAppElement endpoint"></br></p></li> -</ul> -</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Modify a drawing</a> -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Description of the modification.&#34;, -&#34;jsonRequests&#34;: [ -{ -&lt;JSON request body options from the jsonRequests schema&gt; -} -] -}&#39; -</code></pre>Specify the drawing to modify in the URL, and pass the information on the modification in the request body. Note that the <code>jsonRequests</code> schema is not defined in the Glassworks API Explorer; see the <a href="https://github.com/onshape-public/onshapedrawingjson">OnshapeDrawingJson</a> repository for this information, and check out the <a href="#sample-workflows">Sample Workflows</a> section below for some practical examples.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Get the drawing modification status</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/modify/status/{mrid} --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre>Provide the modification ID (from the <code>modifyDrawing</code> response body) to get the status of the modification.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Translate a drawing</a>: See the <a href="https://onshape-public.github.io/docs/api-adv/translation#export-a-drawing-as-a-json">Translations API Guide</a>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Get drawing translation formats</a>: See the <a href="https://onshape-public.github.io/docs/api-adv/translation#export-a-drawing-as-a-json">Translations API Guide</a>.</li> -</ul> -<h3 id="viewing-drawing-errors">Viewing drawing errors</h3> -<p>You can <a href="https://onshape-public.github.io/docs/api-adv/translation.md#export-a-drawing-as-a-json">export your drawing to a JSON</a> to find errors with your drawing. Each <code>view</code> in the JSON includes an <code>errorState</code> for reporting drawing errors.</p> -<h2 id="sample-app">Sample App</h2> -<p>Please see the <a href="https://github.com/onshape-public/onshape-ts-drawing-client">Onshape TypeScript Drawing Client</a> for a working example of using the Onshape Drawing APIs in an application.</p> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="create-a-drawing-from-a-part">Create a drawing from a part</h3> -<p>In this example, we&rsquo;ll create a drawing from the <strong>FLYWHEEL</strong> part in <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/v/405ba186c3a70e0227ab2941/e/6bed6b43463f6a46a37b4a22">this public document</a>.</p> -<ol> -<li>Create or open an Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with the document ID and workspace ID of your document (i.e., the <em>target</em> document), and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add the request body information: -<ul> -<li>Add <code>flywheelDrawing</code> as the <code>drawingName</code> field.</li> -<li>We must specify the <em>source</em> document&rsquo;s document and version IDs. Note that since our target document and source document are different, we use the <code>external</code> document and version ID fields.</li> -<li>We must also provide the ID of the part to create the drawing from, and the ID of the element (i.e., tab) in which the part lives. -</br> -(Hint: You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> to get a list of part IDs in an element.)</br> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;flywheelDrawing&#34;, -&#34;externalDocumentId&#34;: &#34;e60c4803eaf2ac8be492c18e&#34;, -&#34;externalDocumentVersionId&#34;: &#34;405ba186c3a70e0227ab2941&#34;, -&#34;elementId&#34;: &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;partId&#34;: &#34;JiD&#34; -}&#39; -</code></pre></li> -</ul> -</li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>flywheelDrawing</code> element containing the drawing: -</br><img src="https://onshape-public.github.io/images/flywheelDrawingExample1.png" alt="new drawing created from a part in an external document" width=650></li> -</ol> -<h3 id="create-a-drawing-from-a-template">Create a drawing from a template</h3> -<p>In this example, we&rsquo;ll create a drawing from the standard ANSI template in <a href="https://cad.onshape.com/documents/cbe6e776694549b5ba1a3e88/w/24d08acf10234dbc8d3ab585/e/17eef7862b224f6fb12cbc46">this public document</a>.</p> -<ol> -<li>Open any Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with the document ID and workspace ID of your document (i.e., the <em>target</em> document), and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add the request body information: -<ul> -<li>Add <code>templateAnsiDrawing</code> as the <code>drawingName</code> field.</li> -<li>We must specify the <em>source</em> document&rsquo;s document ID and workspace ID.</li> -<li>We must also provide the ID of the element (i.e., tab) in which the template lives.</li> -<li>Note that we use the <code>template</code> document, workspace, and element ID fields when referring to a specific template for drawing creation. -</br> -<pre tabindex="0"><code>curl &#39;https://cad.onshape.com/api/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json, text/plain, */*&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;templateAnsiDrawing&#34;, -&#34;templateDocumentId&#34;:&#34;cbe6e776694549b5ba1a3e88&#34;, -&#34;templateWorkspaceId&#34;:&#34;24d08acf10234dbc8d3ab585&#34;, -&#34;templateElementId&#34;:&#34;17eef7862b224f6fb12cbc46&#34; -}&#39; -</code></pre></li> -</ul> -</li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>templateAnsiDrawing</code> element containing the empty drawing template.</li> -</ol> -<h3 id="create-a-drawing-in-a-custom-graphics-area">Create a drawing in a custom graphics area</h3> -<ol> -<li>Open any Onshape document in which to create your drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingAppElement">Drawings/createDrawingAppElement</a> call. Replace <code>{did}</code> and <code>{wid}</code> in the URL below with your document, and replace <code>CREDENTIAL</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the drawings area. In this example, we&rsquo;ll add an additional column and row to the drawings area, a title block, and add a border around it. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/create&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;drawingName&#34;: &#34;customGraphicsArea&#34;, -&#34;border&#34;: &#34;true&#34;, -&#34;numberHorizontalZones&#34;: &#34;3&#34;, -&#34;numberVerticalZones&#34;: &#34;3&#34; -&#34;titleblock&#34;: true -}&#39; -</code></pre></li> -<li>Call the endpoint and open your document. Confirm that you see the new <code>customGraphicsArea</code> element: -</br><img src="https://onshape-public.github.io/images/customDrawingArea.png" alt="new drawing created with border and extra column and row" width=550></li> -</ol> -<h3 id="add-a-note-to-a-drawing">Add a note to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll create an <code>Onshape::Note</code> on the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the contents and size of the annotation. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a note to the drawing.&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;type&#34;: &#34;Onshape::Note&#34;, -&#34;note&#34;: { -&#34;position&#34;: { -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;coordinate&#34;: [ -1, -10, -0 -] -}, -&#34;contents&#34;: &#34;This is a note&#34;, -&#34;textHeight&#34;: 0.2, -&#34;logicalId&#34;: &#34;note1&#34; -} -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new note. Note that your drawing may not match this image exactly, depending on your drawing and document properties. This sample document uses Inches for units. -</br><img src="https://onshape-public.github.io/images/drawings-addnote.png" alt="drawing with note annotation" width=550></li> -</ol> -<h3 id="add-a-callout-to-a-drawing">Add a callout to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Callout</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the contents and size of the annotation: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a callout to the drawing.&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;callout&#34;: -{ -&#34;borderShape&#34;: &#34;Circle&#34;, -&#34;borderSize&#34;: 0, -&#34;contents&#34;: &#34;Example Callout&#34;, -&#34;contentsBottom&#34;: &#34;bottom&#34;, -&#34;contentsLeft&#34;: &#34;left&#34;, -&#34;contentsRight&#34;: &#34;right&#34;, -&#34;contentsTop&#34;: &#34;top&#34;, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -2.5, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -}, -&#34;textHeight&#34;: 0.12, -&#34;logicalId&#34;: &#34;callout1&#34; -}, -&#34;type&#34;: &#34;Onshape::Callout&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new callout. -</br><img src="https://onshape-public.github.io/images/drawings-addcallout.png" alt="callout added to drawing" width=550></li> -</ol> -<h3 id="add-a-centerline-to-a-drawing">Add a centerline to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Centerline</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the coordinates of the centerline ends.</li> -</ol> -<ul> -<li>Note: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.</li> -<li>Note: if you have access, you can refer to the <a href="https://docs.opendesign.com/td/">ODA documentation</a> for more detailed formatting information. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a centerline to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;pointToPointCenterline&#34;: { -&#34;point1&#34;: { -&#34;coordinate&#34;: [ -2, -4, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point1&#34;, -&#34;viewId&#34;: &#34;51fa8b6040e411dfd17a4cda&#34; -}, -&#34;point2&#34;: { -&#34;coordinate&#34;: [ -7, -6, -1 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point2&#34;, -&#34;viewId&#34;: &#34;ay6a8b6020e4h7dfdnn1499i&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Centerline::PointToPoint&#34; -} -] -}] -}&#39; -</code></pre></li> -</ul> -<ol start="4"> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new centerline.</li> -</ol> -<h3 id="add-a-dimension-to-a-drawing">Add a dimension to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Dimension</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the coordinates and formatting options for the dimension. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a dimension to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;radialDimension&#34;: { -&#34;centerPoint&#34;: { -&#34;coordinate&#34;: [ -0.2800021171569824, -0.014964947476983043, -0.079502 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point1&#34;, -&#34;viewId&#34;: &#34;e11c38795c04ca55047f7ea7&#34; -}, -&#34;chordPoint&#34;: { -&#34;coordinate&#34;: [ -0.2920149764955524, -0.010030535983985095, -0.079502 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;point2&#34;, -&#34;viewId&#34;: &#34;e11c38795c04ca55047f7ea7&#34; -}, -&#34;formatting&#34;: { -&#34;dimdec&#34;: 2, -&#34;dimlim&#34;: false, -&#34;dimpost&#34;: &#34;R&lt;&gt;&#34;, -&#34;dimtm&#34;: 0, -&#34;dimtol&#34;: false, -&#34;dimtp&#34;: 0, -&#34;type&#34;: &#34;Onshape::Formatting::Dimension&#34; -}, -&#34;logicalId&#34;: &#34;dimension1&#34;, -&#34;textOverride&#34;: &#34;&#34;, -&#34;textPosition&#34;: { -&#34;coordinate&#34;: [ -191.80537349378181, -89.76274130852224, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Dimension::Radial&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new dimension.</li> -</ol> -<h3 id="add-a-geometric-tolerance-to-a-drawing">Add a geometric tolerance to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::GeometricTolerance</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the frames and position of the annotation: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add a geometric tolerance to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;geometricTolerance&#34;: { -&#34;frames&#34;: [ -&#34;{\\fDrawing Symbols Sans;◎}%%v{\\fDrawing Symbols Sans;∅}tol1{\\fDrawing Symbols Sans;Ⓜ}%%v%%v%%v%%v%%v\n&#34;, -&#34;{\\fDrawing Symbols Sans;⌖}%%vto2{\\fDrawing Symbols Sans;Ⓛ}%%v%%v%%v%%v%%v\n&#34; -], -&#34;logicalId&#34;: &#34;geometricTolerance1&#34;, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -6, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::GeometricTolerance&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new annotation. -</br><img src="https://onshape-public.github.io/images/drawings-addtolerance.png" alt="new drawing created with border and extra column and row" width=550></li> -</ol> -<h3 id="add-an-inspection-symbol-to-a-drawing">Add an inspection symbol to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::InspectionSymbol</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the shape and position of the inspection symbol. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates and handles.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;Add an inspection symbol to the drawing&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;inspectionSymbol&#34;: { -&#34;borderShape&#34;: &#34;Circle&#34;, -&#34;borderSize&#34;: 2, -&#34;logicalId&#34;: &#34;inspection1&#34;, -&#34;parentAnnotation&#34;: &#34;h:10000577&#34;, -&#34;parentLineIndex&#34;: 0.0, -&#34;position&#34;: { -&#34;coordinate&#34;: [ -2.6, -6, -0 -], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -}, -&#34;textHeight&#34;: 2 -}, -&#34;type&#34;: &#34;Onshape::InspectionSymbol&#34; -} -] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new inspection symbol.</li> -</ol> -<h3 id="add-a-table-to-a-drawing">Add a table to a drawing</h3> -<ol> -<li>Open an existing (or create a new) Onshape document with a drawing.</li> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add an <code>Onshape::Table::GeneralTable</code> to the drawing. We must specify the <code>messageName</code> and <code>formatVersion</code> for the modification, and then provide the location, number of rows, and number of columns for the table. (Hint: you can <a href="https://onshape-public.github.io/docs/api-adv/translation/#export-a-drawing-as-a-json">Export a Drawing to JSON</a> to get a list of valid coordinates.) -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;description&#34;: &#34;New table&#34;, -&#34;jsonRequests&#34;: [ { -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;annotations&#34;: [ -{ &#34;table&#34;: { -&#34;cells&#34;: [ -{ -&#34;column&#34;: 0, -&#34;content&#34;: &#34;1.1&#34;, -&#34;row&#34;: 0 -}, -{ -&#34;column&#34;: 0, -&#34;content&#34;: &#34;2.1&#34;, -&#34;row&#34;: 1 -}, -{ -&#34;column&#34;: 1, -&#34;content&#34;: &#34;1.2&#34;, -&#34;row&#34;: 0 -}, -{ -&#34;column&#34;: 1, -&#34;content&#34;: &#34;2.2&#34;, -&#34;row&#34;: 1 -} -], -&#34;columns&#34;: 2, -&#34;rows&#34;: 2, -&#34;showHeaderRow&#34;: false, -&#34;showTitleRow&#34;: false, -&#34;position&#34;: { -&#34;coordinate&#34;: [100.0, 400.0, 0.0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Table::GeneralTable&#34; -}] -}] -}&#39; -</code></pre></li> -<li>Make the call, and then get <code>id</code> from the response body. You&rsquo;ll need this to poll the modification status to figure out when the modification has completed.</li> -<li>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getModificationStatus">Drawings/getModificationStatus</a> call. Replace <code>{mrid}</code> with the <code>id</code> from the last step, and replace <code>CREDENTIALS</code> with your credentials. Poll the modification status until the response returns <code>&quot;requestState&quot;: &quot;DONE&quot;</code>. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.doc/api/v6/drawings/modify/status/{mrid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li>Open your drawing and confirm that you see the new table.</li> -</ol> -<h3 id="specify-a-snap-point">Specify a snap point</h3> -<p>You can use the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> to choose the snap points for annotations. Available types of snap points are:</p> -<pre tabindex="0"><code> ModeApint // Apparent intersection -ModeCenter // Center point -ModeEnd // End point -ModeIns // Insertion point -ModeIntersec // Intersection -ModeMid // Midpoint -ModeNear // Nearest point -ModeNode // Node -ModePar // Parallel -ModePerp // Perpendicular -ModeQuad // Quadrant -ModeStart // Start point -ModeTan // Tangent point -</code></pre><ol> -<li>Create a sketch in Onshape with two circles, then extrude both circles.</li> -<li>Create a drawing of the part&rsquo;s front view. We&rsquo;ll use the Drawings API to a point to point centerline snapped to the centers of the holes. -</br><img src="https://onshape-public.github.io/images/drawings-snap-before-01.png" alt="drawing front view of a box with two holes" width=350></li> -<li>Next, we&rsquo;ll need to get the view ID of the drawing. Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingViews_1">Drawing/getDrawingViews_1</a> endpoint on your document to get a list of all views in the drawing, and copy the <code>viewId</code> from the response:</li> -</ol> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/views&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre><ol start="4"> -<li>Use the <code>viewId</code> from the last step to get the <code>uniqueId</code> (or <code>edgeId</code>) of each circle&rsquo;s center from the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingViewJsonGeometry_1">Drawing/getDrawingViewJsonGeometry_1)</a> endpoint:</li> -</ol> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/views/{viewId}/jsongeometry&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre><ol start="5"> -<li>Start to form the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/modifyDrawing">Drawings/modifyDrawing</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code></code></pre></li> -<li>Add information about the modification. In this example, we&rsquo;ll add a <code>pointToPointCenterline</code> to the drawing. Make sure to update the request body values as followis:</li> -</ol> -<ul> -<li><code>messageName</code>: <code>&quot;onshapeCreateAnnotation&quot;</code></li> -<li><code>formatVersion</code>: <code>&quot;2021-01-01&quot;</code></li> -<li><code>uniqueId</code>: From Step 4</li> -<li><code>viewId</code>: From Step 3</li> -<li><code>coordinates</code>: The values must be sent as part of the request, but are ignored. -<pre tabindex="0"><code> curl -X &#39;POST \ -&#39;https://cad.onshape.doc/api/v8/drawings/d/{did}/w/{wid}/e/{eid}/modify&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \s --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d { -&#34;description&#34;: &#34;creating a snap point&#34;, -&#34;jsonRequests&#34;: [ { -&#34;messageName&#34;: &#34;onshapeCreateAnnotations&#34;, -&#34;formatVersion&#34;: &#34;2021-01-01&#34;, -&#34;annotations&#34;: [ -{ -&#34;pointToPointCenterline&#34;: { -&#34;point1&#34;: { -&#34;coordinate&#34;: [0,0,0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;{uniqueId1}&#34;, -&#34;viewId&#34;: &#34;{viewId}&#34;, -&#34;snapPointType&#34;: &#34;ModeCenter&#34; -}, -&#34;point2&#34;: { -&#34;coordinate&#34;: [0,0,0], -&#34;type&#34;: &#34;Onshape::Reference::Point&#34;, -&#34;uniqueId&#34;: &#34;{uniqueId2}&#34;, -&#34;viewId&#34;: &#34;{viewId}&#34;, -&#34;snapPointType&#34;: &#34;ModeCenter&#34; -} -}, -&#34;type&#34;: &#34;Onshape::Centerline::PointToPoint&#34; -} -] -}] -} -</code></pre></li> -</ul> -<ol start="7"> -<li>Return to your document and see that the centerline has been added to the document at the snap points. -</br><img src="https://onshape-public.github.io/images/drawings-snap-after-01.png" alt="drawing front view of a box with two holes with a centerline between the hole centers" width=350></li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://onshape-public.github.io/docs/api-intro//#onshape-api-request">Guide to Onshape APIs</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">Guide to the API Explorer</a></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing">API Explorer: Drawings</a></li> -<li><a href="https://cad.onshape.com/help/Content/drawings.htm">Onshape Help: Drawings</a></li> -</ul>Docs: Featureshttps://onshape-public.github.io/docs/api-adv/featureaccess/Mon, 18 May 2020 20:37:28 -0400https://onshape-public.github.io/docs/api-adv/featureaccess/ -<p>This page describes the APIs Onshape provides for creating and manipulating features and the Feature List in a Part Studio.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {vid}, {mid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, version, microversion, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong>cad</strong> in all Onshape URLs with your company domain. -https://<strong>cad</strong>.onshape.com &gt; https://<strong>companyName</strong>.onshape.com</li> -</ul> -</blockquote> -<h2 id="featurescript-vs-rest-api">FeatureScript vs REST API</h2> -<p>When working with complex geometry, you might find working directly in FeatureScript easier than working with the Onshape REST API. <a href="https://cad.onshape.com/FsDoc/">Click here to see the FeatureScript documentation.</a></p> -<h2 id="endpoints">Endpoints</h2> -<p>The following endpoints are available for working with features and the Feature List:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features?rollbackBarIndex=-1&amp;includeGeometryIds=true&amp;noSketchGeometry=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">Add a Feature</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{wid}/features&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;&#34;, -&#34;name&#34;: &#34;&#34;, -&#34;parameters&#34;: [] -} -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updatePartStudioFeature">Update a Feature</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;parameters&#34;: [] -} -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updateFeatures">Update Multiple Features</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/updates&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTUpdateFeaturesCall-1748&#34;, -&#34;features&#34;: [ -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid1}&#34;, -&#34;parameters&#34;: [] -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureId&#34;: &#34;{fid2}&#34;, -&#34;parameters&#34;: [] -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/deletePartStudioFeature">Delete a Feature</a> -<pre tabindex="0"><code>curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -</ul> -<h3 id="json-encoding">JSON encoding</h3> -<p>Instead of providing a translation layer between a feature&rsquo;s internal and external formats, these APIs present the internal format of the feature definitions to the user. The best way to familiarize yourself with the formats involved is by calling the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> endpoint on existing Part Studios.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>Onshape REST API parameters may change at any time. The documentation on this page is accurate for v8 of the Onshape API. The quickest way to verify what parameters are needed for a call is to create the sketch/feature in the Onshape UI, then call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">Get the Feature List</a> API and see what parameters are returned for the feature.</li> -</ul> -</blockquote> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>Default values are sometimes omitted in the encoded output. These defaults are: -<ul> -<li>String: <code>&quot;&quot;</code></li> -<li>Boolean: <code>false</code></li> -<li>Numeric: <code>0</code></li> -</ul> -</li> -<li>The JSON encoding uses a special tagging system to manage polymorphic data structures. Objects are generally by enclosing them within another object that declares the type information for the enclosed object.</li> -</ul> -</blockquote> -<h3 id="feature-types">Feature types</h3> -<p>Below, find the available types for working with features in the API.</p> -<ul> -<li><code>BTMFeature-134</code> - General feature type</li> -<li><code>BTMSketch-151</code> - Feature type for sketches</li> -</ul> -<h3 id="parameter-types">Parameter types</h3> -<p>All parameters have the following fields in common:</p> -<ul> -<li><code>parameterId</code> - Unique ID of the parameter</li> -<li><code>nodeId</code> - Unique ID of the parameter node</li> -</ul> -<p>The parameter types available for use in the API are:</p> -<ul> -<li><code>BTMParameterQuantity-147</code> -<ul> -<li><code>expression</code> - Define the value for the parameter</li> -</ul> -</li> -<li><code>BTMParameterQueryList-148 </code> - defined by one of the following: -<ul> -<li><code>SBTMIndividualQuery-138</code> -<ul> -<li><code>geometryIds</code> - List of geometry IDs the feature applies to</li> -</ul> -</li> -<li><code>SBTMIndividualSketchRegionQuery-140</code> -<ul> -<li><code>featureId</code> - Feature ID of the sketch for which to include all regions</li> -</ul> -</li> -</ul> -</li> -<li><code>BTMParameterBoolean-144</code> -<ul> -<li><code>value</code> - <code>true | false</code></li> -</ul> -</li> -<li><code>BTMParameterEnum-145</code> -<ul> -<li><code>enumName</code> - Name of the enum type that the value is a member of</li> -<li><code>value</code> - The enum member</li> -</ul> -</li> -</ul> -<h3 id="sketch-plane-ids">Sketch plane IDs</h3> -<p>The following string can be sent along with the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/evalFeatureScript">PartStudios/featurescript</a> API to get the plane ID. You can then use that ID to specify the plane on which to create a sketch.</p> -<pre tabindex="0"><code>function(context is Context, queries) { -return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;{planeName}\&#34;), EntityType.FACE))); -} -</code></pre><p>For example, to get the ID of the Top plane, you would make the following call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;script&#34;: &#34;function(context is Context, queries) { return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;Top\&#34;), EntityType.FACE))); }&#34; -}&#39; -</code></pre><h2 id="sample-workflows">Sample Workflows</h2> -<p>Below are several examples of how the API can be used in order to help you get started. The calls could be executed using your preferred software environment but interactive use in a REST-aware tool is likely the easiest way to try the examples.</p> -<h3 id="get-the-list-of-features-in-a-part-studio">Get the list of features in a Part Studio</h3> -<p>One of the best ways to familiarize yourself with the Onshape Feature APIs is to view the API details for existing features in a Part Studio. In this example, we&rsquo;ll add three features to a Part Studio, and then call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">PartStudio/getPartStudioFeatures</a> API on the Part Studio. We&rsquo;ll then be able to view the structure of the way features are represented in the API.</p> -<ol> -<li>Create a new document or open an existing one.</li> -<li>Create a new sketch in the document, and draw a long rectangle.</li> -<li>Extrude the rectangle.</li> -<li>Add a fillet to one edge of the part.</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">PartStudio/getPartStudioFeatures</a> API. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;GET \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features?rollbackBarIndex=-1&amp;includeGeometryIds=true&amp;noSketchGeometry=false&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>Review the JSON returned in the response body. A lot of information is returned, but it will look something like the truncated snippet below. Notice that there are objects returned for each feature in the Part Studio&ndash; the sketch, the extrude, the fillet, and the chamfer. Each default plane and the origin in the Part Studio also appear in the <code>defaultFeatures</code> object. The Standard Geometry library is listed as an import, and the response also includes the state of each feature. : -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureListResponse-2457&#34;, -&#34;isComplete&#34;: true, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;rollbackIndex&#34;: 4, -&#34;features&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;entities&#34;: [...], -&#34;constraints&#34;: [...], -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid1}&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;subFeatures&#34;: [...], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...] -&#34;featureId&#34;: &#34;{fid2}&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;subFeatures&#34;: [], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Fillet 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid3}&#34;, -&#34;featureType&#34;: &#34;fillet&#34;, -&#34;subFeatures&#34;: [...], -&#34;returnAfterSubfeatures&#34;: false -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Chamfer 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [...], -&#34;featureId&#34;: &#34;{fid4}&#34;, -} -], -&#34;featureStates&#34;: { -&#34;{fid1}&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -... -}, -&#34;defaultFeatures&#34;: [ -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Origin&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Top&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Front&#34;, -}, -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Right&#34;, -} -], -&#34;imports&#34;: [ -{ -&#34;btType&#34;: &#34;BTMImport-136&#34;, -&#34;path&#34;: &#34;onshape/std/geometry.fs&#34;, -&#34;version&#34;: &#34;2232.0&#34; -} -], -&#34;libraryVersion&#34;: 2232 -} -</code></pre></li> -</ol> -<h3 id="create-a-cube-feature">Create a cube feature</h3> -<p>In this example we will create a cube using the <code>cube</code> feature. The feature accepts a single parameter (the length of a side) and creates a cube with a corner at the origin and aligned with the three default planes.</p> -<ol> -<li>Create a new document or open an existing one. We&rsquo;ll create the cube feature in this document.</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. This is a call to the same endpoint as in the previous example, but is a <code>POST</code> instead of a <code>GET</code>. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>Add the following as the JSON body. -<ul> -<li>Note the <code>btType</code> defines this as a Feature.</li> -<li>We&rsquo;ve named the feature <code>cube</code> and inserted an instance of the feature named <code>Cube 1</code> into the Part Studio.</li> -<li>The <code>cube</code> feature has one parameter&ndash; the cube <code>sideLength</code> in inches, which is set to 1 by default.</li> -</ul> -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -} -</code></pre></li> -<li>Confirm your call matches the following, and then make the call: -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -}&#39; -</code></pre></li> -<li>Return to your console to review the endpoint response. The output returns: -<ul> -<li>The feature definition that we provided as input with <code>nodeId</code>s and a <code>featureId</code>. Make a note of the <code>featureId</code>; we&rsquo;ll use it in the next example.</li> -<li>Information that the feature executed correctly</li> -<li>The serialization version and microversion of the document that resulted from the feature addition</li> -</ul> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionResponse-1617&#34;, -&#34;featureState&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;value&#34;: 0, -&#34;units&#34;: &#34;&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;nodeId&#34;: &#34;{nid1}&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;nodeId&#34;: &#34;{nid2}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;returnAfterSubfeatures&#34;: false, -&#34;subFeatures&#34;: [], -&#34;namespace&#34;: &#34;&#34; -}, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 0 -} -</code></pre></li> -<li>Open your document and confirm that the cube has been inserted into the Part Studio. -</br><img src="https://onshape-public.github.io/images/features-cube-example.png" alt="cube added to part studio via features api" width=550></li> -<li>Double-click <code>Cube 1</code> in the Feature List to open the Cube 1 dialog. Change the sideLength to 3 and click the checkbox. Note that the size of the cube changes automatically. -</br><img src="https://onshape-public.github.io/images/features-cube-example-02.png" alt="cube parameter updated to 3 inches" width=550></li> -</ol> -<h3 id="create-a-sketch">Create a sketch</h3> -<p>In this example, we&rsquo;ll create a circular sketch feature with the following properties:</p> -<ul> -<li>While other features use a <code>btType</code> of <code>BTMFeature-141</code>, sketches have their own special type: <code>BTMSketch-151</code></li> -<li>Sketches must use the <code>newSketch</code> featureType</li> -<li>Sketch plane ID: Front</li> -<li>Radius: 0.025 inches</li> -<li>Location: (0.05, 0.05)</li> -</ul> -<ol> -<li>Open a new PartStudio. Note the following: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (of the Part Studio tab)</li> -</ul> -</li> -<li>We want to create the circle on the Front plane, so we&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/evalFeatureScript">PartStudios/featurescript</a> endpoint to get its ID: -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;script&#34;: &#34;function(context is Context, queries) { return transientQueriesToStrings(evaluateQuery(context, qCreatedBy(makeId(\&#34;Front\&#34;), EntityType.FACE))); }&#34; -}&#39; -</code></pre>The call returns the following, identifying the plane as <code>JCC</code>. -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureScriptEvalResponse-1859&#34;, -&#34;result&#34;: { -&#34;btType&#34;: &#34;com.belmonttech.serialize.fsvalue.BTFSValueArray&#34;, -&#34;value&#34;: [ -{ -&#34;btType&#34;: &#34;com.belmonttech.serialize.fsvalue.BTFSValueString&#34;, -&#34;value&#34;: &#34;JCC&#34;, -&#34;typeTag&#34;: &#34;&#34; -} -], -&#34;typeTag&#34;: &#34;&#34; -} -} -</code></pre></li> -<li>Now we&rsquo;ll create the JSON structure for our sketch. <em>All sketches must be created with the <code>BTMSketch-151</code> btType and the <code>newSketch</code> featureType.</em> Note how we&rsquo;ve specified the plane to use in the <code>sketchPlane</code> parameter, and the <code>geometry</code> details. -<pre tabindex="0"><code>{ -&#34;feature&#34; : { -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualQuery-138&#34;, -&#34;deterministicIds&#34;: [ &#34;JCC&#34; ] -} -], -&#34;parameterId&#34;: &#34;sketchPlane&#34; -} -], -&#34;entities&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketchCurve-4&#34;, -&#34;geometry&#34;: { -&#34;btType&#34;: &#34;BTCurveGeometryCircle-115&#34;, -&#34;radius&#34;: 0.025, -&#34;xcenter&#34;: 0.05, -&#34;ycenter&#34;: 0.05, -&#34;xdir&#34;: 1, -&#34;ydir&#34;: 0, -&#34;clockwise&#34;: false -}, -&#34;centerId&#34;: &#34;circle-entity.center&#34;, -&#34;entityId&#34;: &#34;circle-entity&#34; -} -], -&#34;constraints&#34;: [ -] -} -} -</code></pre></li> -<li>Now we&rsquo;ll add the JSON structure to the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> endpoint. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{wid}/features&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;feature&#34; : { -&#34;btType&#34;: &#34;BTMSketch-151&#34;, -&#34;featureType&#34;: &#34;newSketch&#34;, -&#34;name&#34;: &#34;Sketch 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualQuery-138&#34;, -&#34;deterministicIds&#34;: [ &#34;JCC&#34; ] -} -], -&#34;parameterId&#34;: &#34;sketchPlane&#34; -} -], -&#34;entities&#34;: [ -{ -&#34;btType&#34;: &#34;BTMSketchCurve-4&#34;, -&#34;geometry&#34;: { -&#34;btType&#34;: &#34;BTCurveGeometryCircle-115&#34;, -&#34;radius&#34;: 0.025, -&#34;xcenter&#34;: 0.05, -&#34;ycenter&#34;: 0.05, -&#34;xdir&#34;: 1, -&#34;ydir&#34;: 0, -&#34;clockwise&#34;: false -}, -&#34;centerId&#34;: &#34;circle-entity.center&#34;, -&#34;entityId&#34;: &#34;circle-entity&#34; -} -], -&#34;constraints&#34;: [ -] -} -}&#39; -</code></pre></li> -<li>Find the new sketch&rsquo;s <code>featureId</code> in the call response. You&rsquo;ll need this for the <a href="#create-a-cylinder">Create a cylinder</a> tutorial.</li> -<li>Open your Part Studio and confirm that the sketch has been added: -</br></br><img src="https://onshape-public.github.io/images/features-create-sketch.png" alt="circle sketch created via features api" width=550></li> -</ol> -<h3 id="create-a-cylinder">Create a cylinder</h3> -<p>In this tutorial, we&rsquo;ll extrude an sketch with the following properties: -</br></br><img src="https://onshape-public.github.io/images/features-extrude-dialog.png" alt="Extrude dialog in Onshape UI" width=350></p> -<ol> -<li>This tutorial expands on the <a href="#create-a-sketch">Create a sketch</a> tutorial. You&rsquo;ll need the following from the document containing your circular sketch: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID of the tab containing the sketch</li> -<li>Feature ID of the sketch -<ul> -<li>If you need to get this <code>featureId</code> again, you can call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document.</li> -</ul> -</li> -</ul> -</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/addPartStudioFeature">PartStudio/addPartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>We&rsquo;ll start by initializing an extrude in the JSON with the <code>btType</code> and <code>featureType</code> shown below:</li> -</ol> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: -{ -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -] -} -} -</code></pre><ol start="4"> -<li>Now, we&rsquo;ll add values for the options we want to our <code>parameters</code> block. Don&rsquo;t forget to replace <code>{featureId}</code> in the code below with the feature ID of the sketch.</li> -</ol> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;SOLID&#34;, -&#34;enumName&#34;: &#34;ExtendedToolBodyType&#34;, -&#34;parameterId&#34;: &#34;bodyType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;NEW&#34;, -&#34;enumName&#34;: &#34;NewBodyOperationType&#34;, -&#34;parameterId&#34;: &#34;operationType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualSketchRegionQuery-140&#34;, -&#34;featureId&#34;: &#34;{featureId}&#34; -} -], -&#34;parameterId&#34;: &#34;entities&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;BLIND&#34;, -&#34;enumName&#34;: &#34;BoundingType&#34;, -&#34;parameterId&#34;: &#34;endBound&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;depth&#34; -} -</code></pre><ol start="5"> -<li>Now our JSON is complete, and we can make our call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;featureType&#34;: &#34;extrude&#34;, -&#34;name&#34;: &#34;Extrude 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;SOLID&#34;, -&#34;enumName&#34;: &#34;ExtendedToolBodyType&#34;, -&#34;parameterId&#34;: &#34;bodyType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;NEW&#34;, -&#34;enumName&#34;: &#34;NewBodyOperationType&#34;, -&#34;parameterId&#34;: &#34;operationType&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQueryList-148&#34;, -&#34;queries&#34;: [ -{ -&#34;btType&#34;: &#34;BTMIndividualSketchRegionQuery-140&#34;, -&#34;featureId&#34;: &#34;{featureId}&#34; -} -], -&#34;parameterId&#34;: &#34;entities&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterEnum-145&#34;, -&#34;value&#34;: &#34;BLIND&#34;, -&#34;enumName&#34;: &#34;BoundingType&#34;, -&#34;parameterId&#34;: &#34;endBound&#34; -}, -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;expression&#34;: &#34;1 in&#34;, -&#34;parameterId&#34;: &#34;depth&#34; -} -], -&#34;returnAfterSubfeatures&#34;: false, -&#34;suppressed&#34;: false -} -}&#39; -</code></pre><ol start="6"> -<li>Open your document and confirm that the sketch has been extruded into a cylinder. -</br></br><img src="https://onshape-public.github.io/images/features-extrude-example.png" alt="circle sketch created via features api" width=550></li> -</ol> -<h3 id="update-a-feature">Update a feature</h3> -<p>In this example we&rsquo;ll update our cube feature.</p> -<ol> -<li>Open the document in which you created the cube feature in <a href="#create-a-cube-feature">this example</a>. You will need the following from this document: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (for the element that contains the cube feature)</li> -<li>Feature ID (ID of the cube feature, returned in the API response in the previous example) -<ul> -<li>If you need to get this <code>featureId</code> again, you can call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document.</li> -</ul> -</li> -</ul> -</li> -<li>Begin to create the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/updatePartStudioFeature">PartStudio/updatePartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&lt;JSON of feature data&gt; -}&#39; -</code></pre></li> -<li>Add the following as the JSON body. -<ul> -<li>Note the <code>btType</code> defines this as a Feature.</li> -<li>We specify the <code>featureId</code> again in the request body. This must match the <code>featureId</code> sent in the URL exactly.</li> -<li>We must also specify the feature&rsquo;s <code>featureType</code> and <code>name</code> in this call; if we don&rsquo;t send those fields, the call will attempt to change these values to empty strings, resulting in errors.</li> -<li>The <code>cube</code> feature has one parameter&ndash; the cube <code>sideLength</code> in inches, which we will update to 2 inches:</li> -</ul> -<pre tabindex="0"><code>{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -] -} -} -</code></pre></li> -<li>Confirm your call matches the following, and then make the call: -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;btType&#34;: &#34;BTFeatureDefinitionCall-1406&#34;, -&#34;feature&#34;: { -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -] -} -}&#39; -</code></pre></li> -<li>Return to your console to review the endpoint response. The output returns: -<ul> -<li>The updated feature definition</li> -<li>Information that the feature executed correctly</li> -<li>The serialization version and microversion of the document that resulted from the feature update</li> -</ul> -<pre tabindex="0"><code> { -&#34;btType&#34;: &#34;BTFeatureDefinitionResponse-1617&#34;, -&#34;featureState&#34;: { -&#34;btType&#34;: &#34;BTFeatureState-1688&#34;, -&#34;featureStatus&#34;: &#34;OK&#34;, -&#34;inactive&#34;: false -}, -&#34;feature&#34;: { -&#34;btType&#34;: &#34;BTMFeature-134&#34;, -&#34;name&#34;: &#34;Cube 1&#34;, -&#34;suppressed&#34;: false, -&#34;parameters&#34;: [ -{ -&#34;btType&#34;: &#34;BTMParameterQuantity-147&#34;, -&#34;value&#34;: 0, -&#34;units&#34;: &#34;&#34;, -&#34;isInteger&#34;: false, -&#34;expression&#34;: &#34;2 in&#34;, -&#34;nodeId&#34;: &#34;{nid1}&#34;, -&#34;parameterId&#34;: &#34;sideLength&#34; -} -], -&#34;featureId&#34;: &#34;{fid}&#34;, -&#34;nodeId&#34;: &#34;{nid2}, -&#34;featureType&#34;: &#34;cube&#34;, -&#34;returnAfterSubfeatures&#34;: false, -&#34;subFeatures&#34;: [], -&#34;namespace&#34;: &#34;&#34; -}, -&#34;serializationVersion&#34;: &#34;1.2.4&#34;, -&#34;sourceMicroversion&#34;: &#34;{mid}&#34;, -&#34;microversionSkew&#34;: false, -&#34;rejectMicroversionSkew&#34;: false, -&#34;libraryVersion&#34;: 0 -} -</code></pre></li> -<li>Open your document and confirm that the cube has a side length of 2 inches. -</br><img src="https://onshape-public.github.io/images/features-cube-example-03.png" alt="cube added to part studio via features api" width=550></li> -</ol> -<h3 id="delete-a-feature">Delete a feature</h3> -<ol> -<li>Create a new document and add a cube feature to it. See <a href="#create-a-cube-feature">Create a cube feature</a> for instructions. Make a note of the following: -<ul> -<li>Document ID</li> -<li>Workspace ID</li> -<li>Element ID (for the element containing the cube feature)</li> -</ul> -</li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioFeatures">getPartStudioFeatures</a> endpoint on the document to get the <code>featureId</code> of the cube feature. See <a href="#get-the-list-of-features-in-a-part-studio">Get the Feature list</a> for instructions.</li> -<li>Create and execute the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/deletePartStudioFeature">PartStudio/deletePartStudioFeature</a> call. Replace the URL parameters with the values from your document, and replace <code>CREDENTIALS</code> with your authorization credentials. -<pre tabindex="0"><code>curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v8/partstudios/d/{did}/w/{wid}/e/{eid}/features/featureid/{fid}&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Confirm that the cube feature has been removed from your document.</li> -</ol>Docs: Evaluating FeatureScripthttps://onshape-public.github.io/docs/api-adv/fs/Thu, 15 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/fs/ -<p>This page describes some of the APIs Onshape provides for evaluating <a href="https://cad.onshape.com/FsDoc/">FeatureScript</a>.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --d &#39;{ -&#34;libraryVersion&#34;: 2144, -&#34;script&#34;: &#34;&#34; -} -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="calculate-a-tight-bounding-box">Calculate a tight bounding box</h3> -<p>Though the Onshape API offers a <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/getPartStudioBoundingBoxes">PartStudio/getPartStudioBoundingBoxes</a> endpoint, it does not result in a tight bounding box. The values returned are meant for graphics and visualization, and are approximate. To calculate a more accurate bounding box, we&rsquo;ll use the <a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a> endpoint.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer#/PartStudio/evalFeatureScript">PartStudio/evalFeatureScript</a>. Replace the URL parameters with the IDs from the Part Studio you&rsquo;re working with, and replace <code>CREDENTIALS</code> with your authorization credentials. The endpoint will return a tight bounding box in the response. -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/featurescript?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --d &#39;{ &#34;libraryVersion&#34;: 2144, -&#34;script&#34;: &#34;function(context is Context, definition is map) {const boundingBoxTight = evBox3d(context, { \n \&#34;topology\&#34; : qConstructionFilter(qEverything(), ConstructionObject.NO),\n \&#34;tight\&#34; : true\n}); \n return (boundingBoxTight);}&#34; -}&#39; -</code></pre></li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/FsDoc/">FeatureScript</a></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio">API Explorer: Part Studio</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -</ul>Docs: Import & Exporthttps://onshape-public.github.io/docs/api-adv/translation/Wed, 27 Sep 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/translation/ -<p>This page describes the APIs Onshape provides for importing files to Onshape and exporting files from Onshape into different formats. We refer to the process of importing and exporting files from one format to another as <em>translating</em> the files.</p> -<p>Onshape provides several APIs to support this format translation. These fall into three categories:</p> -<ul> -<li><a href="#synchronous-exports">Synchronous exports</a> - Export Onshape content to glTF, STL, or Parasolid format.</li> -<li><a href="#asynchronous-exports">Asynchronous exports</a> - Export Onshape content into a variety of other formats.</li> -<li><a href="#imports">Import to Onshape</a> - Import a translatable file by uploading it to an Onshape blob element.</li> -</ul> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="synchronous-exports">Synchronous exports</h2> -<p>Onshape provides a simple way to export content to common formats (glTF, Parasolid, and STL). Most of the interfaces defined here operate by requesting an HTTP redirect to a different URL where the request is fulfilled. Applications must explicitly handle the redirect and attachment authentication headers to the follow-up request, or it will fail.</p> -<p>The following endpoints are available. We&rsquo;ve included an example curl with each one.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPartGltf">Export Part to glTF</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}/e/{eid}/partid/{partid}/gltf?rollbackBarIndex=-1&amp;outputSeparateFaceNodes=false&amp;outputFaceAppearances=false&#39; \ --H &#39;accept: model/gltf-binary;qs=0.08&#39; \ -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPS">Export Part to Parasolid</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}?elementId={eid}&amp;withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportStl">Export Part to STL</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/{did}/w/{wid}/e/{eid}/partid/{partid}/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: application/octet-stream&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioGltf">Export PartStudio to glTF</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/gltf?rollbackBarIndex=-1&amp;outputSeparateFaceNodes=false&amp;outputFaceAppearances=false&#39; \ --H &#39;accept: model/gltf-binary;qs=0.08&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportParasolid">Export PartStudio to Parasolid</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/parasolid?version=0&amp;includeExportIds=false&amp;binaryExport=false&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioStl">Export PartStudio to STL</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/{did}/w/{wid}/e/{eid}/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Document/export2Json">Export Document to JSON</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/documents/d/{did}/w/{wid}/e/{eid}/export&#39; \ --H &#39;accept: application/octet-stream&#39; \ -</code></pre></li> -</ul> -<h2 id="asynchronous-exports">Asynchronous exports</h2> -<p>The exports in the last section perform the format translation synchronously, returning the output immediately after some processing delay. Other format conversions are more complex and time-consuming, and in many cases, cannot be completed quickly enough to prevent connection errors. Note that the source format for an export is currently always automatically detected by Onshape. Part Studios and Assemblies are known to be <code>ONSHAPE</code> format. File uploads have their type determined by the filename suffix. For example, a file named <em>part7.step</em> is assumed to be in <code>STEP</code> format.</p> -<p>The following asynchronous translation APIs are available:</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/createBlobTranslation">BlobElement/createBlobTranslation</a>: Export a Blob Element to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudios/createPartStudioTranslation</a>: Export a Part Studio to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a>: Export an Assembly to the specified <code>formatName</code>.</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a>: Export a Drawing to the specified <code>formatName</code>.</li> -</ul> -<p>These asynchronous exports include a few additional steps, which are explained in more detail in the <a href="#async-export-steps">next section</a>:</p> -<ol> -<li>See what formats are available for exporting your content with <strong><a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a></strong>.</li> -</ol> -<ul> -<li><strong>Note:</strong> Parts with mesh data cannot be exported to ACIS, IGES, or OBJ format.</li> -</ul> -<ol start="2"> -<li>Call the desired <strong>translation API</strong>. -<ul> -<li>Specify the target <strong><code>formatName</code></strong> in the request body JSON.</li> -<li>Specify <strong><code>storeInDocument=false</code></strong> (default) to export the content to new file.</li> -<li>Specify <strong><code>storeInDocument=true</code></strong> to export the content to a blob element in the source document.</li> -</ul> -</li> -<li>Poll the <strong><code>requestState</code></strong> in the translation response and wait for a result of <strong><code>DONE</code></strong>.</li> -<li>To retrieve the exported results: -<ul> -<li>External files: call <strong><a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Document/downloadExternalData</a></strong> on the <code>resultExternalDataIds</code> from the translation response.</li> -<li>Blob elements: call <strong><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a></strong> on the <code>resultElementIds</code> from the translation response.</li> -</ul> -</li> -</ol> -<h3 id="async-export-details">Async export details</h3> -<p>To export your Onshape content to another format:</p> -<ol> -<li>Determine what export format file types are available for your content by calling: <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translations/getAllTranslatorFormats</a>. -<ul> -<li>Note that Drawings have their own API for this call: <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Drawing/getDrawingTranslatorFormats</a></li> -</ul> -</li> -<li>Next, initiate the export by calling one of the asynchronous translation APIs. -<ul> -<li>Note that each of these APIs takes a JSON for specifying options for the export as part of the request body. Refer to the <a href="https://onshape-public.github.io/docs/api-intro/explorer">API Explorer</a> page for help viewing these JSON docs.</li> -<li>The target file format <strong>must be specified in the <code>formatName</code> field</strong> in the request body, and must match a valid format found in Step 1.</li> -<li>By default, <code>storeInDocument</code> is set to <code>false</code> in the request body to export to a single data file (or a zip of multiple files). Set to <code>true</code> to export as blob elements.</li> -</ul> -</li> -<li>Wait for the translation to complete. You can either register a webhook and wait to receive a notifcation that the translation is complete (see <a href="https://onshape-public.github.io/docs/app-dev/webhook/">Webhook Notifications</a>), or you can poll the translation&rsquo;s <code>requestState</code>: -<ul> -<li>You can poll the <code>requestState</code> from the initial translation&rsquo;s response, or you can call <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getTranslation">Translation/getTranslation</a> on the <code>translationId</code> from the initial translation&rsquo;s response.</li> -<li>When a translation is complete, <code>requestState</code> will change from <code>ACTIVE</code> to either <code>DONE</code> or <code>FAILED</code>.</li> -<li>When <code>requestState=DONE</code>, results are available to be used.</li> -</ul> -</li> -<li>Retrieve the exported results: -<ul> -<li>If you exported to an external file, call <a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Documents/downloadExternalData</a> to retrieve the exported result. -<ul> -<li>Note that this API takes the source document ID and a &ldquo;foreign ID&rdquo; as required parameters.</li> -<li>Use the <code>resultExternalDataIds</code> from the translation response as the foreign ID (<code>fid</code>).</li> -<li>External data is associated with, but external to, the document used as translation context. This data is not versioned like with in-document data.</li> -</ul> -</li> -<li>If your translation request body specified <code>storeInDocument=true</code>, retrieve the blob element data with <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a>. -<ul> -<li>The element IDs for the new blob elements can be found in the <code>resultElementIds</code> field in the translation response.</li> -</ul> -</li> -</ul> -</li> -</ol> -<h2 id="imports">Imports</h2> -<p>Files can be imported to Onshape as blob elements. When uploading a file to a blob element, either as a new element or an update to an existing element, if the file is a recognized format for import, it will be translated into <code>ONSHAPE</code> format by default. This behavior can be overridden by the application, if desired.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Translation/createTranslation">Translation/createTranslation</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;flattenAssemblies=true --F &#39;file=@/path/filename.ext&#39; --F &#39;formatName=&#39; \ -... -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/uploadFileCreateElement">BlobElement/uploadFileCreateElement</a> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;file=@/path/filename.ext&#39; --F &#39;formatName=&#39; \ -... -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/uploadFileUpdateElement">BlobElement/uploadFileUpdateElement</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;storeInDocument=true&#39; \ --F &#39;locationElementId=&#39; \ --F &#39;file=@/path/filename.ext&#39; -... -</code></pre></li> -</ul> -<p>Note that these endpoints require you to specify the target document ID and workspace ID. You must also include the file to import. These APIs also includes a request body JSON for specifying options for the import.</p> -<ul> -<li>Override the translation to <code>ONSHAPE</code> format by specifying a valid format in the <code>formatName</code> field. Get a list of valid import formats by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a>.</li> -<li>Specify <code>storeInDocument=true</code> to import the data as a blob element into the target document. Change to <code>false</code> to only create an external data file.</li> -<li>If the source file contains an assembly and <code>flattenAssemblies=true</code>, the assembly structure is removed and a single part studio is created.</li> -<li>Note that when using cURL, you must begin the path to the file with an <code>@</code> symbol.</li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="export-a-partstudio-to-stl">Export a PartStudio to STL</h3> -<p>We will export the <code>CRANK</code> PartStudio from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to an STL file.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/exportPartStudioStl">Part Studios/exportPartStudioStl</a> endpoint on the document: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch&#39; \ --H &#39;accept: */*&#39; -</code></pre></li> -<li>Navigate to the request URL to download the resulting STL file: -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/stl?mode=text&amp;grouping=true&amp;scale=1&amp;units=inch -</code></pre></li> -<li>Open the <em>CRANK.stl</em> file from wherever your downloads are saved.</li> -</ol> -<h3 id="export-a-part-to-parasolid">Export a Part to Parasolid</h3> -<p>We will export the <code>FLYWHEEL</code> part from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to an STL file.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMV">Part/getPartsWMV</a> endpoint on your document and get all the part IDs: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62?elementId=6bed6b43463f6a46a37b4a22&amp;withThumbnails=false&amp;includePropertyDefaults=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Locate the part to export (hint: look for <code>name = yourPartName</code>) in the response body. Get the part ID from the <code>partId</code> field. In the example below, <code>partId = JiD</code> for <code>name=FLYWHEEL</code>: -<pre tabindex="0"><code>[ -... -{ -&#34;name&#34; : &#34;FLYWHEEL&#34;, -&#34;state&#34; : &#34;IN_PROGRESS&#34;, -&#34;propertySourceTypes&#34; : { -&#34;57f3fb8efa3416c06701d60f&#34; : 3, -&#34;57f3fb8efa3416c06701d60d&#34; : 3, -&#34;57f3fb8efa3416c06701d61e&#34; : 3, -&#34;57f3fb8efa3416c06701d60e&#34; : 3, -&#34;57f3fb8efa3416c06701d60c&#34; : 3 -}, -&#34;defaultColorHash&#34; : &#34;FzHLKqGeuTBFjmY_2_0&#34;, -&#34;ordinal&#34; : 1, -&#34;isMesh&#34; : false, -&#34;description&#34; : &#34;Flywheel&#34;, -&#34;microversionId&#34; : &#34;bdb504d2d4c948493a87ccf3&#34;, -&#34;partNumber&#34; : &#34;PRT-10241&#34;, -&#34;elementId&#34; : &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;partId&#34; : &#34;JiD&#34;, -&#34;bodyType&#34; : &#34;solid&#34;, -&#34;customProperties&#34; : { -&#34;57f3fb8efa3416c06701d61e&#34; : &#34;false&#34; -} -... -] -</code></pre></li> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/exportPS">Part/exportPS</a> endpoint on the FLYWHEEL part: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/partid/JiD/parasolid?version=0&#39; \ --H &#39;accept: application/octet-stream&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li>Navigate to the request URL to download the resulting file: -<pre tabindex="0"><code>https://cad.onshape.com/api/v6/parts/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/partid/JiD/parasolid?version=0 -</code></pre></li> -<li>Open the <em>CRANK.x_t</em> file from your downloads. Note that the file is automatically named after the PartStudio to which the part belongs.</li> -</ol> -<h3 id="export-a-partstudio-to-solidworks">Export a PartStudio to SOLIDWORKS</h3> -<p>We will export the <code>CRANK</code> PartStudio from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22">this public document</a> to a SOLIDWORKS file.</p> -<ol> -<li>Validate that SOLIDWORKS is a supported export file type by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validDestinationFormat=true</code> for <code>translatorName=SOLIDWORKS</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;SOLIDWORKS&#34;, -&#34;translatorName&#34;: &#34;solidworks&#34;, -&#34;couldBeAssembly&#34;: true -} -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudio/createPartStudioTranslation</a>. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/partstudios/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;formatName&#34;: &#34;SOLIDWORKS&#34;, -&#34;storeInDocument&#34;: false, -&#34;translate&#34;: true -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>In this example, we&rsquo;ve just shown a snippet of the entire JSON.</li> -<li>A <code>formatName</code> string must be specified that matches one of the valid formats you found in the last step. In this example, we set <code>formatName</code> to <code>SOLIDWORKS.</code></li> -<li>We want to export this to a new file, so we&rsquo;ll leave <code>storeInDocument</code> set to <code>false</code>.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">PartStudio/createPartStudioTranslation</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;documentId&#34;: &#34;e60c4803eaf2ac8be492c18e&#34;, -&#34;requestElementId&#34;: &#34;6bed6b43463f6a46a37b4a22&#34;, -&#34;requestState&#34;: &#34;DONE&#34;, -&#34;resultExternalDataIds&#34;: &#34;[{resultId}]&#34;, -... -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/Document/downloadExternalData">Documents/downloadExternalData</a> to retrieve the exported result. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/documents/d/e60c4803eaf2ac8be492c18e/externaldata/{fid}&#39; -</code></pre><ul> -<li>Use the <code>resultExternalDataIds</code> value from the translation response as the foreign ID (<code>fid</code>).</li> -<li>The new SOLIDWORKS file is returned as the response and will be downloaded to wherever the API call is made.</li> -</ul> -</li> -</ol> -<h3 id="export-an-assembly-to-step">Export an Assembly to STEP</h3> -<p>In this example, we&rsquo;ll export an assembly from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/23a9385cd48c50167c32d6d1">this public document</a> to a STEP file.</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/23a9385cd48c50167c32d6d1">this public document</a> so you can export the assembly. Make a note of the documentId, workspaceId, and elementId of the assembly in your new document.</li> -<li>Validate that STEP is a supported export file type for assemblies by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validDestinationFormat=true</code> and <code>couldBeAssembly=true</code> for <code>translatorName=STEP</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;STEP&#34;, -&#34;translatorName&#34;: &#34;step&#34;, -&#34;couldBeAssembly&#34;: true -}, -... -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a>. Replace <code>{did}</code>, <code>{wid}</code>, and <code>{eid}</code> with the document, workspace, and element IDs from your copied document. Do NOT include the curly braces (<code>{}</code>) in the final call. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/assemblies/d/{did}/w/{wid}/e/{eid}/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;allowFaultyParts&#34;: true, -&#34;angularTolerance&#34;: 0.001, -&#34;formatName&#34;: &#34;STEP&#34;, -&#34;storeInDocument&#34;: true -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>In the example above, we&rsquo;ve just shown a snippet of the entire JSON where we allow faulty parts to be exported and set the angular tolerance to 0.001.</li> -<li>A <code>formatName</code> string must be specified that matches one of the valid formats you found in the last step. In this example, we set <code>formatName</code> to <code>STEP.</code></li> -<li>Set <code>storeInDocument</code> to <code>true</code> to upload the STEP file as a blob element in your document.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/translateFormat">Assembly/translateFormat</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;resultDocumentId&#34; : &#34;{did}&#34;, -&#34;resultWorkspaceId&#34; : &#34;{wid}&#34;, -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;requestElementId&#34; : &#34;{eid}&#34;, -&#34;resultExternalDataIds&#34; : [ &#34;{resultExternalId}&#34; ], -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : {resulteid}, -&#34;name&#34; : &#34;GEARBOX_CHUCK&#34;, -&#34;id&#34; : &#34;{translationId}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v6/translations/{translationId}&#34; -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we make a note of the <code>resultElementId</code> in the response. This is the elementId of the STEP blob.</li> -<li>Now, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a> to retrieve the exported results. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{resulteid}&#39; \ --H &#39;accept: application/octet-stream&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><ul> -<li>Use the <code>resultElementIds</code> value from the translation response as the element ID (<code>{resulteid}</code>).</li> -<li>Note that you can also open your document, click the <code>GEARBOX_CHUCK.STEP</code> tab, and download the file from there.</li> -</ul> -</li> -</ol> -<h3 id="export-a-drawing-as-a-json">Export a Drawing as a JSON</h3> -<p>In this example, we&rsquo;ll export a Drawing from <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/15b07287508246ccd038e31e">this public document</a> to a JSON file. Exporting a Drawing to JSON is useful when you need to gather information about that drawing (for example, finding valid coordinates on which to place an inspection symbol).</p> -<ol> -<li>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/15b07287508246ccd038e31e">this public document</a> so you can export the assembly. Make a note of the documentId, workspaceId, and elementId of the assembly in your new document.</li> -<li>Validate that JSON is a supported export file type for Drawings by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/getDrawingTranslatorFormats">Drawing/getDrawingTranslatorFormats</a> and confirming that <code>&quot;name&quot;: &quot;DRAWING_JSON&quot;</code> appears in the response for the drawing element in your copied document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><pre tabindex="0"><code>[ -{ -&#34;name&#34;: &#34;DRAWING_JSON&#34;, -&#34;translatorName&#34;: &#34;drawing_json&#34;, -&#34;couldBeAssembly&#34;: false -}, -... -] -</code></pre></li> -<li>Initialize the export by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a>. Replace <code>{did}</code>, <code>{wid}</code>, and <code>{eid}</code> with the document, workspace, and element IDs from your copied document. Do NOT include the curly braces (<code>{}</code>) in the final call. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/drawings/d/{did}/w/{wid}/e/{eid}/translations&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;formatName&#34;: &#34;DRAWING_JSON&#34; -}&#39; -</code></pre><ul> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the export.</li> -<li>The only required JSON field is <code>formatName</code>, in which we&rsquo;ve specified the format as found in the <code>getDrawingTranslatorFormats</code> response body.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Drawing/createDrawingTranslation">Drawing/createDrawingTranslation</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;resultDocumentId&#34; : &#34;{did}&#34;, -&#34;resultWorkspaceId&#34; : &#34;{wid}&#34;, -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;requestElementId&#34; : &#34;{eid}&#34;, -&#34;resultExternalDataIds&#34; : [ &#34;{resultExternalId}&#34; ], -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : {eid}, -&#34;name&#34; : &#34;GEARBOX_CHUCK&#34;, -&#34;id&#34; : &#34;{translationId}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v6/translations/{translationId}&#34; -} -</code></pre><ul> -<li>Note that you can also call the <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getTranslation">Translation/getTranslation</a> endpoint on the <code>translationId</code> to see all in-progress translation information.</li> -</ul> -</li> -<li>Once <code>requestState=DONE</code>, we make a note of the <code>&quot;resultElementIds&quot; : {resulteid},</code> in the response. This is the element ID of the JSON blob.</li> -<li>Now, we can call <a href="https://cad.onshape.com/glassworks/explorer/#/BlobElement/downloadFileWorkspace">BlobElement/downloadFileWorkspace</a> to retrieve the exported results. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/blobelements/d/{did}/w/{wid}/e/{resulteid}&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;accept: application/octet-stream&#39; -</code></pre><ul> -<li>Use the <code>{resultExternalId}</code> value from the translation response as the element ID (<code>{resulteid}</code>). Do not include the curly braces in your call.</li> -<li>Note that you can also open your document, click the <code>GEARBOX_CHUCK.JSON</code> tab, and download the file from there.</li> -</ul> -</li> -</ol> -<h3 id="import-a-parasolid-file-as-a-part">Import a Parasolid file as a Part</h3> -<p>In this example, we&rsquo;ll import the <em>FLYWHEEL</em> part from the <em>CRANK.x_t</em> file we created in the <a href="#export-a-part-to-parasolid">Export a Part to Parasolid</a> example.</p> -<ol> -<li>Open or create a new Onshape document in which to import the Part. Make a note of the documentId and workspaceId of your document.</li> -<li>Validate that Parasolid is a supported export file type for imports by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getAllTranslatorFormats">Translation/getAllTranslatorFormats</a> and confirming that <code>validSourceFormat=true</code> for <code>translatorName=parasolid</code>. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/translationformats&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre><pre tabindex="0"><code>[ -{ -&#34;validSourceFormat&#34;: true, -&#34;validDestinationFormat&#34;: true, -&#34;name&#34;: &#34;PARASOLID&#34;, -&#34;translatorName&#34;: &#34;parasolid&#34;, -&#34;couldBeAssembly&#34;: true -} -]s -</code></pre></li> -<li>Initialize the import by calling <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/createTranslation">Translation/createTranslation</a>. In this example, the filename is <code>CRANK.x_t</code>. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/translations/d/{did}/w/{wid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39;s \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: multipart/form-data&#39; \ --F &#39;formatName=&#39; \ --F &#39;flattenAssemblies=true&#39; \ --F &#39;translate=true&#39; \ --F &#39;file=@/pathToFile/CRANK.x_t&#39; \ -</code></pre><ul> -<li>Replace <code>{did}</code> and <code>{wid}</code> in the URL with the document and workspace IDs for the document you want to import the part to.</li> -<li>Note that when using cURL, you must begin the path to the file with an <code>@</code> symbol.</li> -<li>Note that the API takes a JSON as part of the request body, in which you can specify options for the import.</li> -<li>When importing files, the API assumes we are importing to the <code>ONSHAPE</code> file type. You can override this and import to a different file type using the <code>formatName</code> field. In this case, we can leave the <code>formatName</code> field blank to import to the <code>ONSHAPE</code> file type.</li> -</ul> -</li> -<li>Next, we poll the <a href="https://cad.onshape.com/glassworks/explorer/#/Translation/getDocumentTranslations">Translation/getDocumentTranslations</a> response until <code>requestState</code> changes from <code>ACTIVE</code> to <code>DONE</code> or <code>FAILED</code>. -<pre tabindex="0"><code>{ -&#34;requestState&#34; : &#34;DONE&#34;, -&#34;documentId&#34; : &#34;{did}&#34;, -&#34;workspaceId&#34; : &#34;{wid}&#34;, -&#34;resultElementIds&#34; : [ &#34;{resulteid}&#34; ], -&#34;name&#34; : &#34;FLYWHEEL&#34;, -&#34;id&#34; : &#34;{id}&#34;, -&#34;href&#34; : &#34;https://cad.onshape.com/api/v1/translations/{tid}&#34; -} -</code></pre></li> -<li>Once <code>requestState=DONE</code>, we can view the imported file as a Part in our Onshape document. The <code>FLYWHEEL</code> part appears in a new PartStudio named <code>CRANK</code> in our document.</li> -</ol> -<h3 id="export-a-configured-part">Export a configured part</h3> -<p>See the <a href="https://onshape-public.github.io/docs/api-adv/configs">Configurations API Guide</a> for examples.</p> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/help/Content/translation.htm">Onshape Help: Translation</a></li> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">Onshape Help: Webhooks</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/webhook">API Guide: Webhook Notifications</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Explorer</a></li> -</ul>Docs: Metadatahttps://onshape-public.github.io/docs/api-adv/metadata/Wed, 20 Dec 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/metadata/ -<p>This page describes the APIs Onshape provides for working with document metadata.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="endpoints">Endpoints</h2> -<h3 id="get-metadata">Get Metadata</h3> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWVMetadata">getWVMetadata</a>: Get metadata for a workspace or version. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEsMetadata">getWMVEsMetadata</a>: Get metadata for all elements in a document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">getWMVEMetadata</a>: Get metadata for an element. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPMetadata">getWMVEPMetadata</a>: Get metadata for a part. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/p/{pid}?rollbackBarIndex=-1&amp;inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPsMetadata">getWMVEPsMetadata</a>: Get metadata for all parts in a document. -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/p?inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39;\ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getVEOPStandardContentMetadata">getVEOPStandardContentMetadata</a>: Get metadata for a standard content part. -<ul> -<li><code>{linkedDocumentId}</code>: ID of the document into which the standard content part is inserted.</li> -<li>You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/getAssemblyDefinition">getAssemblyDefinition</a> to get the other values needed for the call: -<ul> -<li><code>{did}</code>: ID of the document in which the standard content part lives.</li> -<li><code>{vid}</code>: ID of the version in which the standard content part lives.</li> -<li><code>{eid}</code>: ID of the element tab in which the standard content part lives.</li> -<li><code>{pid}</code>: Part ID of the standard content part.</li> -<li><code>{config}</code>: Encoded configuration string.</li> -</ul> -</li> -</ul> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/metadata/standardcontent/d/{did}/v/{vid}/e/{eid}/p/{pid}?configuration={config}&amp;linkDocumentId={linkDocument}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -</ul> -<h3 id="update-metadata">Update Metadata</h3> -<p>To update metadata, you send a JSON in the API request body. This JSON block must include a <code>jsonType</code> value and a <code>properties</code> object array. Each object in the <code>properties</code> array includes a <code>propertyId</code> and the metadata key/value pairs.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVMetadata">updateWVMetadata</a>: Update workspace or version metadata. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: (&#34;metadata-workspace&#34; | &#34;metadata-version&#34;) , -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId1&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -}, -{ -&#34;propertyId&#34;: &#34;propertyId2&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEMetadata">updateWVEMetadata</a>: Update element metadata. -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEPMetadata">updateWVEPMetadata</a>: Update part metadata -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/wv/{wvid}/e/{eid}/{iden}/{pid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;properties&#34;: [ -{ -&#34;propertyId&#34;: &#34;propertyId&#34;, -&#34;key1&#34;: &#34;value&#34;, -&#34;key2&#34;: &#34;value -} -] -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateVEOPStandardContentPartMetadata">updateVEOPStandardContentPartMetadata</a>: Update standard content part metadata. -<ul> -<li><code>{linkedDocumentId}</code>: ID of the document into which the standard content part is inserted.</li> -<li>You can call <a href="https://cad.onshape.com/glassworks/explorer/#/Assembly/getAssemblyDefinition">getAssemblyDefinition</a> to get the other values needed for the call: -<ul> -<li><code>{did}</code>, <code>{vid}</code>, <code>{eid}</code>: IDs of the document, version, and element in which the standard content part lives.</li> -<li><code>{companyId}</code>: ID of the company that owns the standard content part. All metadata changes to this standard content part will populate for the entire company.</li> -<li><code>{pid}</code>: Part ID of the standard content part.</li> -<li><code>{config}</code>: Encoded configuration string.</li> -</ul> -</li> -<li>For each <code>items.properties</code> object, include a unique <code>propertyId</code> and at least one key/value metadata pair.</li> -<li>Updates made to standard content are global for all users and documents within the company.</li> -</ul> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/standardcontent/d/{did}?linkDocumentId={linkDocumentId}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;items&#34;: [ -{ -&#34;href&#34;: &#34;https://cad.onshape.com/api/metadata/standardcontent/d/did/v/vid/e/eid/c/companyId/p/pid?configuration=config&amp;linkDocumentId=linkDocumentId&amp;applyToAllConfigs=true&#34;, -&#34;properties&#34;: [ -{ -&#34;key&#34;: &#34;value&#34;, -&#34;propertyId&#34;: &#34;propertyId1&#34; -}, -{ -&#34;key&#34;: &#34;value&#34;, -&#34;propertyId&#34;: &#34;propertyId2&#34; -} -] -} -] -}&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="get-a-part-property">Get a part property</h3> -<p>In this example we&rsquo;ll get the name of a part by getting the metadata from the <code>DRILL_BIT</code> element in <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>.</p> -<ol> -<li>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">Metadata/getWMVEMetadata</a> endpoint. Replace <code>CREDENTIALS</code> with your authentication credentials: -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851?inferMetadataOwner=false&amp;depth=1&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li>In the response body, confirm that for <code>properties.name=Name</code>, <code>properties.value=DRILL_BIT</code>. -<pre tabindex="0"><code>{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;elementType&#34;: 0, -&#34;mimeType&#34;: &#34;onshape/partstudio&#34;, -&#34;elementId&#34;: &#34;958bceb5a2511b572dbbe851&#34;, -&#34;properties&#34;: [ -{ -&#34;name&#34;: &#34;Name&#34;, -&#34;value&#34;: &#34;DRILL_BIT&#34;, -&#34;defaultValue&#34;: null, -&#34;computedPropertyError&#34;: null, -&#34;propertySource&#34;: 0, -... -</code></pre></li> -</ol> -<h3 id="update-a-part-property">Update a part property</h3> -<p>In this example we will update a part&rsquo;s description by getting the current metadata for the part, and then posting an update to that metadata.</p> -<ol> -<li> -<p>Get your document information:</p> -<p>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/958bceb5a2511b572dbbe851">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID.</p> -</li> -<li> -<p>Get the ID of the part to update:</p> -<p>Call the <a href="https://cad.onshape.com/glassworks/explorer/#/Part/getPartsWMVE">Part/getPartsWMVE</a> API on your copied document to get a list of part IDs in the element. Only one part exists in the document, with a part ID of <code>JHD</code>.</p> -<pre tabindex="0"><code>{ -&#34;name&#34;: &#34;Main&#34;, -... -&#34;microversionId&#34;: &#34;{mid}&#34;, -&#34;partNumber&#34;: null, -&#34;elementId&#34;: &#34;{eid}&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;bodyType&#34;: &#34;sheet&#34;, -... -} -</code></pre></li> -<li> -<p>Get the metadata of the part:</p> -<p>We&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEPMetadata">Metadata/getWMVEPMetadata</a> endpoint to get the current metadata JSON for the part. Don&rsquo;t forget to replace the URL parameters with the IDs from your copied document, and replace <code>CREDENTIALS</code> with your authorization credentials.</p> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&amp;inferMetadataOwner=false&amp;includeComputedProperties=true&amp;includeComputedAssemblyProperties=false&amp;thumbnail=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li> -<p>Locate the property to update in the response:</p> -<p>The call returns a response body in JSON format. Scroll to the <code>Description</code> properties block of the JSON response, and notice that the <code>value</code> field is an empty string.</p> -<pre tabindex="0"><code>... -{ -&#34;name&#34;: &#34;Description&#34;, -&#34;value&#34;: &#34;&#34;, -&#34;defaultValue&#34;: null, -&#34;computedPropertyError&#34;: null, -&#34;propertySource&#34;: 3, -&#34;validator&#34;: { }, -&#34;required&#34;: false, -&#34;editable&#34;: true, -&#34;propertyId&#34;: &#34;{propertyId}&#34;, -&#34;editableInUi&#34;: true, -&#34;dateFormat&#34;: null, -&#34;valueType&#34;: &#34;STRING&#34;, -&#34;enumValues&#34;: null, -&#34;multivalued&#34;: false, -&#34;computedAssemblyProperty&#34;: false, -&#34;computedProperty&#34;: false, -&#34;propertyOverrideStatus&#34;: 0 -}, -... -</code></pre></li> -<li> -<p>Find the metadata&rsquo;s property ID:</p> -<p>Copy Description&rsquo;s <code>propertyId</code>. We&rsquo;ll need this ID to update the metadata.</p> -</li> -<li> -<p>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEPMetadata">Metadata/updateWVEPMetadata</a> call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li> -<p>Add the request JSON to the call:</p> -<p>Note that we need to include the <code>jsonType</code>, the <code>partId</code>, the <code>propertyId</code>, and the value to update.</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Add the new property information:</p> -<p>In the request JSON, change the empty Description <code>value</code> string to <code>&quot;Drill bit&quot;</code>:</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;Drill bit&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>POST the new metadata:</p> -<p>Don&rsquo;t forget to replace the URL parameters and <code>CREDENTIALS</code> with your information.</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}/p/JHD?rollbackBarIndex=-1&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;jsonType&#34;: &#34;metadata-part&#34;, -&#34;partId&#34;: &#34;JHD&#34;, -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;Drill bit&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Confirm your changes:</p> -<p>Repeat steps 3 and 4 to confirm that the Description <code>value</code> for the part is now <code>Drill bit</code>.</p> -</li> -</ol> -<h3 id="update-a-tab-name">Update a tab name</h3> -<p>In this example we will update an element&rsquo;s tab name by getting the current metadata for the element, and then posting an update to that metadata. Remember that in Onshape, an element is typically represented as a tab in the Onshape UI.</p> -<ol> -<li> -<p>Get your document information:</p> -<p>Make a copy of <a href="https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/4561b91a53c595c0010d5cdb">this public document</a>. Make a note of the new document&rsquo;s document ID, workspace ID, and element ID. Note the tab name of the element is &ldquo;NEW_PART&rdquo;.</p> -<p></br><img src="https://onshape-public.github.io/images/metadata-update-tab-before.png" alt="Onshape document with NEW_PART tab name" width=950></p> -</li> -<li> -<p>Get the metadata of the element:</p> -<p>We&rsquo;ll call the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/getWMVEMetadata">Metadata/getWMVEMetadata</a> endpoint to get the current metadata JSON for the element. Don&rsquo;t forget to replace the URL parameters with the IDs from your copied document, and replace <code>CREDENTIALS</code> with your authorization credentials.</p> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; -</code></pre></li> -<li> -<p>Locate the property to update in the response:</p> -<p>The call returns a response body in JSON format. Scroll to the <code>Name</code> properties block of the JSON response, and notice that the <code>value</code> field matches our current tab name, &ldquo;NEW_PART&rdquo;.</p> -<pre tabindex="0"><code>{ -&#34;jsonType&#34;: &#34;metadata-element&#34;, -&#34;elementType&#34;: 0, -&#34;mimeType&#34;: &#34;onshape/partstudio&#34;, -&#34;elementId&#34;: &#34;{eid}&#34;, -&#34;properties&#34;: [ -{ -&#34;name&#34;: &#34;Name&#34;, -&#34;value&#34;: &#34;NEW_PART&#34;, -&#34;validator&#34;: {}, -&#34;required&#34;: true, -&#34;editable&#34;: true, -&#34;propertyId&#34;: &#34;{propertyId}&#34;, -}, -... -], -... -} -</code></pre></li> -<li> -<p>Find the metadata&rsquo;s property ID:</p> -<p>Copy the Name block&rsquo;s <code>propertyId</code> in the response. We&rsquo;ll need this ID to update the metadata.</p> -</li> -<li> -<p>Set up the <a href="https://cad.onshape.com/glassworks/explorer/#/Metadata/updateWVEMetadata">updateWVEMetadata</a> call:</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ -</code></pre></li> -<li> -<p>Add the request JSON to the call:</p> -<p>Note that we need to include the <code>propertyId</code> and the value to update.</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Add the new property information:</p> -<p>In the request JSON, replace <code>{propertyId}</code> with the property ID you found in Step 4, then change the empty <code>value</code> string to <code>&quot;PISTON&quot;</code>:</p> -<pre tabindex="0"><code>-d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;PISTON&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>POST the new metadata:</p> -<p>Don&rsquo;t forget to replace the URL parameters and <code>CREDENTIALS</code> with your information.</p> -<pre tabindex="0"><code>curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/metadata/d/{did}/w/{wid}/e/{eid}&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;properties&#34;: [ -{ -&#34;value&#34;: &#34;PISTON&#34;, -&#34;propertyId&#34;: &#34;{propertyId}&#34; -} -] -}&#39; -</code></pre></li> -<li> -<p>Confirm your changes:</p> -<p>Open your document and confirm that the tab name is now <code>PISTON</code>.</p> -<p></br><img src="https://onshape-public.github.io/images/metadata-update-tab-after.png" alt="Onshape document with NEW_PART tab name" width=950></p> -</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Metadata">API Explorer: Metadata</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -</ul>Docs: Response Codeshttps://onshape-public.github.io/docs/api-adv/errors/Wed, 03 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/errors/ -<p>This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we&rsquo;ve provided a brief description of the response and recommended next steps.</p> -<h2 id="success-2xx">Success (2xx)</h2> -<p>The client call was successful.</p> -<h3 id="200---ok">200 - OK</h3> -<p>The client call was successful. No action needed.</p> -<h3 id="204---no-content">204 - No Content</h3> -<p>The client call was successful, and there&rsquo;s nothing to return in the response body. The empty response body cannot be parsed.</p> -<h2 id="redirect-3xx">Redirect (3xx)</h2> -<h3 id="307---temporary-redirect">307 - Temporary Redirect</h3> -<p>The client call was successful, and a redirection URL was returned. Follow the URL provided in the response.</p> -<h2 id="client-error-4xx">Client Error (4xx)</h2> -<p>There’s an error with the client request. Find the error code below, and follow the instructions for resolution.</p> -<h3 id="400---bad-request">400 - Bad Request</h3> -<p>The request cannot be processed by the server due a client-side error. This could be a malformed request syntax or other issue. Check the request parameters (GET and POST) and request body (POST) to determine the cause of the failure.</p> -<h3 id="401---unauthorized">401 - Unauthorized</h3> -<p>The request failed the authentication/authorization checks. This could mean that the client is not logged in, API keys are invalid, OAuth failed, etc. Make sure the client is <a href="https://onshape-public.github.io/docs/auth/">authenticated</a>.</p> -<h3 id="403---forbidden">403 - Forbidden</h3> -<p>The client doesn’t have the correct permissions to perform this operation. Check that the <a href="https://onshape-public.github.io/docs/auth/">API Keys or OAuth authentication</a> have sufficient permissions to perform the operation. For example, POST operations typically require <code>write</code> scope; if the API Key was created with only <code>read</code> scope, the server will return a 403 error.</p> -<p>You might also need to check document and user permissions. For more details, see <a href="https://cad.onshape.com/help/Content/sharedocuments.htm">Share Documents</a> (for everyone) and <a href="https://cad.onshape.com/help/Content/EnterpriseHelp/Content/permission_schemes.htm">Understanding and Administering Project Roles and Permission Schemes</a> (for Enterprise users and administrators).</p> -<h3 id="404---not-found">404 - Not Found</h3> -<p>The server can’t find what the client is looking for. For example, a 404 error will be returned if the client tries to make a GET request for a document that doesn’t exist.</p> -<h3 id="405---method-not-allowed">405 - Method Not Allowed</h3> -<p>Use of that method is not supported. For example, you cannot perform a DELETE request on a document version, because versions are read-only. Only GET requests on document versions are allowed.</p> -<h3 id="406----not-acceptable">406 - Not Acceptable</h3> -<p>The server cannot provide a response for the media type requested. See <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1">https://datatracker.ietf.org/doc/html/rfc2616#section-6.1.1</a>.</p> -<h3 id="409---conflict">409 - Conflict</h3> -<p>The client call includes duplicate values, causing a conflict. Modify the request to remove any conflicting values.</p> -<h3 id="415---media-type-not-supported">415 - Media Type Not Supported</h3> -<p>The client call includes unsupported data types or invalid JSON. Review the client code. When performing data imports and exports, follow all <a href="https://onshape-public.github.io/docs/api-adv/translation/">Translation guidelines</a> to ensure all media and file types are supported.</p> -<h3 id="429---too-many-requests">429 - Too Many Requests</h3> -<p>The client sent too many requests to a particular endpoint in a given time window. The number of requests allowed per time window vary and are subject to change. Onshape does not publish this information. If the client receives HTTP 429 responses, delay and then retry, or reduce its request rate.</p> -<h3 id="499---timeout">499 - Timeout</h3> -<p>This call is taking too long. Please try again later.</p> -<h2 id="server-error-5xx">Server Error (5xx)</h2> -<p>There’s an error with the Onshape servers. Find the error code below, and follow the instructions for resolution.</p> -<h3 id="500---internal-server-error">500 - Internal Server Error</h3> -<p>The request resulted in an error. Set a limit for the number of retries, and if the request continues to fail, reach out to <a href="api-support@onshape.com">support</a>.</p> -<h3 id="503---service-unavailable">503 - Service Unavailable</h3> -<p>Something is wrong with the Onshape servers. Retry after the delay specified in the response. Set a limit for the number of retries, and if the request continues to fail, reach out to <a href="api-support@onshape.com">support</a>.</p>Docs: Extensionshttps://onshape-public.github.io/docs/app-dev/extensions/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/extensions/ -<p>This page provides information for some of the more common options for -embedding a third-party application into the Onshape interface. Onshape provides many options for embedding commands in various menus, fly-out panels, and elements. In this example, you will embed a custom web page inside a document’s right side fly-out panel. This interface will receive information from Onshape and push information from the panel back to Onshape, providing a complete, bi-directional integration scenario.</p> -<p>Please see also:</p> -<ul> -<li><a href="https://onshape-public.github.io/docs/tutorials/createextension/">Create an Extension tutorial</a>: A step-by-step walkthrough of creating an extension.</li> -<li>Create an Extension Video Sample: -<a href="https://onshape.wistia.com/medias/0ivxxngkjz?embedType=async&seo=false&videoFoam=true&videoWidth=640&wvideo=0ivxxngkjz)"><img src="https://onshape-public.github.io/images/ExtensionsVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></li> -</ul> -<h2 id="extension-types">Extension Types</h2> -<p>We can classify extensions into two high-level types. The first type embeds a UI <em>from</em> the application <em>into</em> the Onshape UI. The embedded UI is an HTTPS page displayed in an iFrame in the Onshape UI. The UI is served from the application, and can choose to make API calls to Onshape for additional information. This is exactly like the traditional tab-based applications in Onshape, except that such extensions exist at different UI locations.</p> -<p>The second type of extension embeds an action that calls a REST API <em>exposed by</em> the application <em>from</em> the Onshape UI (e.g., context menu actions and toolbar actions). These types of extensions rely on External OAuth information to authenticate and make a call where Onshape acts as a client, and the application acts as a server.</p> -<h2 id="extension-attributes">Extension Attributes</h2> -<p>Each extension exists at a specific place in the Onshape UI and works with a specific context or selection. The attributes of an extension are:</p> -<ol> -<li><strong>Name</strong>: This should be short and explicit. It will appear in the Onshape UI as a menu item, a toolbar tooltip, a collapsed panel icon tooltip, or a panel icon. It might be truncated in the UI if it is too long.</li> -<li><strong>Description</strong>: This is where the developer can record a detailed description of the extension. It does not appear in the Onshape UI, but could appear in the grant process.</li> -<li><strong>Location</strong>: This describes where the extension exists in the Onshape UI. Over time, this will cover various panels in the UI, context menus, toolbars, actions in dialogs, etc. You can see the list of currently supported locations <a href="#supported-locations-and-contexts">here</a>. -<ul> -<li>Please note that you can create only one element tab extension per application.</li> -</ul> -</li> -<li><strong>Context</strong> (selection): Some locations will work in the context of a selection. Let’s say the application developer wants to show some information from a third-party system, pertinent only to parts (not assemblies or drawings). In this scenario, the developer would choose a location like ‘Document list info panel’, and the context as ‘Selected part’. If the user searches for something in the document list, some documents, Part Studios, parts, and Assemblies would be returned. This extension will show up in the Info panel only if the selected entity is a part. Using context enables application developers to control when the extension is displayed. Check the list of contexts available for different locations <a href="#supported-locations-and-contexts">here</a>.</li> -<li><strong>Action URL</strong>: Locations that embed a UI use the action URL to define the address of the page to display. The action URL is used to specify the REST endpoint if the location is an action (context menu, toolbar item, action in dialog etc.) and the action type is GET or POST. If the location is an action and the action is ‘Open in new window’, the action URL is the URL to open in the new window.<br> -The action URL can be parameterized to pass information from Onshape to the application. The action URL replaces attributes in the format {$attribute} with the appropriate value. These attributes can be used to identify the selected entity and/or make calls back to Onshape via the API. The currently supported attributes are: -<ul> -<li><code>{$documentId}</code> - The Onshape ID for the current or selected document.</li> -<li><code>{$workspaceOrVersion}</code> - This will be either <code>w</code> or <code>v</code> for workspace or version respectively depending on current opened document state or selection.</li> -<li><code>{$workspaceOrVersionId}</code> - The Onshape ID for the current or selected workspace or version.</li> -<li><code>{$workspaceId}</code> - Use <code>{$workspaceOrVersionId}</code> instead.</li> -<li><code>{$versionId}</code> - Use <code>{$workspaceOrVersionId}</code> instead.</li> -<li><code>{$microversionId}</code> - The Onshape ID for the current or select document microversion.</li> -<li><code>{tabElementId}</code> - The Onshape ID for the current tab.</li> -<li><code>{$elementId}</code> - The Onshape ID for the current or selected element.</li> -<li><strong>Note</strong>: In most cases, <code>tabElementId</code> and <code>elementId</code> will be the same. However, when creating an extension with the <code>Selected instance</code> context, <code>tabElementId</code> indicates the current tab (i.e., the target element), and <code>elementId</code> indicates the tab from which the instance/subassembly was inserted (i.e., the source element).</li> -<li><code>{$partId}</code> - The Onshape ID for the current or selected part.</li> -<li><code>{$partNumber}</code> - The Part number property for the current or selected part, assembly or drawing.</li> -<li><code>{$revision}</code> - The Revision property for the current or selected part, assembly or drawing.</li> -<li><code>{$companyId}</code> - The ID for the company that owns the document.</li> -<li><code>{$mimeType}</code> - The mime type if the current or selected element is a blob.</li> -<li><code>{$featureId}</code> - In case of feature selected in the Feature list in a Part Studio.</li> -<li><code>{$nodeId}</code> - In case of mate or mate feature selected in the Assembly list.</li> -<li><code>{$occurrencePath}</code> - In case of part instances, mates, mate connectors and sub assemblies.</li> -<li><code>{$configuration}</code> - In case of extensions inside the document, this attribute will be replaced by current element active configuration.</li> -</ul> -</li> -</ol> -<p>The attributes can exist as path parameters or query parameters or attributes in the POST body. For example:</p> -<pre tabindex="0"><code>[https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId={$documentId}&amp;workspaceOrVersion={workspaceOrVersion}&amp;workspaceOrVersionId={$workspaceOrVersionId}&amp;elementId={$elementId}&amp;partId={$partId}&amp;server=https://cad.onshape.com&amp;companyId=cad&amp;userId=5f1eba76c14a434817d9c588&amp;locale=en-US](https://whispering-sea-42267.herokuapp.com/oauthSignin?documentId=%7B$documentId%7D&amp;workspaceId=%7B$workspaceId%7D&amp;elementId=%7B$elementId%7D&amp;partId=%7B$partId) -</code></pre><p>or</p> -<pre tabindex="0"><code>[https://cad.onshape.com/api/partstudios/d/{$documentId}/{$workspaceOrVersion}/{$workspaceOrVersionId}/e/{$elementId}/stl?server=https://cad.onshape.com&amp;companyId=cad&amp;userId=5f1eba76c14a434817d9c588&amp;locale=en-US](https://cad.onshape.com/api/partstudios/d/%7B$documentId%7D/w/%7B$workspaceId%7D/e/%7B$elementId%7D/stl) -</code></pre><p>The attributes available for replacement differ by location and context selection. You can see the available attributes for each location <a href="#supported-locations-and-contexts">here</a>.</p> -<p>The <strong>timeout</strong> for <code>action_url</code> of type <code>GET</code> or <code>POST</code> is <strong>180 seconds</strong>.</p> -<ol start="6"> -<li> -<p><strong>Action type</strong>: The action type is only applicable for locations that act as actions and not for locations that embed UIs. Check if action type is valid for a location <a href="#supported-locations-and-contexts">here</a>. The supported action types are:</p> -<ul> -<li><code>GET</code> - This makes a GET API call using the action URL. Parameter replacement is done on the action URL.</li> -<li><code>POST</code> - This makes a POST API call using the action URL and the action body as the post body. Parameter replacement is done on both the action URL and the action body.</li> -<li><code>Open in new window</code> - This opens the action URL in a new browser window. Parameter replacement is done on the action URL.</li> -</ul> -</li> -<li> -<p><strong>Action body</strong>: This is only applicable if the action type is POST. The action body is passed in a POST API call and must be in a valid json format.</p> -</li> -<li> -<p><strong>Show response</strong>: This is only applicable if the action type is GET or POST. If this is checked, the UI will wait for a response and show the response in a dialog in the UI. The response must be in a valid json format.</p> -</li> -<li> -<p><strong>Icon</strong>: The icon will be shown where the extension exists. This can be an icon in an Info panel, context menu action, toolbar button, action button in a dialog, or other supported locations.</p> -</li> -</ol> -<h2 id="supported-locations-and-contexts">Supported Locations and Contexts</h2> -<p>This is the list of supported locations, their valid contexts, and whether they support action types.</p> -<h3 id="element-context-menu">Element context menu</h3> -<p>This is the context menu for elements.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage04.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacements:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$mimeType}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="tree-context-menu">Tree context menu</h3> -<p>This is the context menu for the part tree, assembly tree and feature tree in part studios.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage05.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Sub assembly</code></li> -<li><code>Feature</code></li> -<li><code>Mate</code></li> -<li><code>Mate feature</code></li> -<li><code>Instance</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$featureId}</code></li> -<li><code>{$nodeId}</code></li> -<li><code>{$occurrencePath}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="document-list-context-menu">Document list context menu</h3> -<p>This the context menu available on items in the document list. This is normally documents but can be multiple types based on search results.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage06.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="document-list-info-panel">Document list info panel</h3> -<p>This is the Info panel to the right in the document list. The document list normally contains documents, but can contain other entities as the result of a search.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage07.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Drawing</code></li> -<li><code>Blob element</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partId}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location does NOT support action types.</p> -<h3 id="element-right-panel">Element right panel</h3> -<p>This is the panel inside a document. It currently houses the BOM, configurations, etc. Applications can use this extension location to add items in this panel.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage08.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li><code>Part</code></li> -<li><code>Document</code></li> -<li><code>Part Studio</code></li> -<li><code>Assembly</code></li> -<li><code>Sub assembly</code></li> -<li><code>Feature</code></li> -<li><code>Mate</code></li> -<li><code>Mate feature</code></li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li><code>{$documentId}</code></li> -<li><code>{$workspaceOrVersion}</code></li> -<li><code>{$workspaceOrVersionId}</code></li> -<li><code>{$workspaceId}</code> DEPRECATED</li> -<li><code>{$versionId}</code> DEPRECATED</li> -<li><code>{$elementId}</code></li> -<li><code>{$partNumber}</code></li> -<li><code>{$revision}</code></li> -<li><code>{$featureId}</code></li> -<li><code>{$nodeId}</code></li> -<li><code>{$occurrencePath}</code></li> -<li><code>{$configuration}</code></li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location does NOT support action types.</p> -<h3 id="new-element-tab">New Element tab</h3> -<p>This is the menu option for <code>+ menu -&gt; Add application</code> inside a document . After menu click, a new tab will be created with the action url associated with this extension.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage09.png" alt="image alt text"></p> -<p>Supported contexts:</p> -<ul> -<li>There are no supported contexts.</li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li>Parameter replacement not supported.</li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li><code>documentId</code></li> -<li><code>workspaceId</code></li> -<li><code>versionId</code></li> -<li><code>elementId</code></li> -<li><code>server</code></li> -<li><code>companyId</code> - Default value is ‘cad’. If the document owner is company/enterprise, then the value is company/enterprise ID.</li> -<li><code>userId</code></li> -<li><code>locale</code></li> -<li><code>clientId</code></li> -</ul> -<p>This location supports action types.</p> -<h3 id="part-number-generator">Part number generator</h3> -<p>This extension helps partners to embed their own custom part number generation scheme in Onshape. Each application can have only one extension of this type. Once defined, these extensions are listed as one of the part numbering schemes in the release management configuration in Company settings.</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage10.png" alt="image alt text"></p> -<p>In the above screen shot, ‘Part number generation scheme’ is the user-defined name of the extension.</p> -<p>Supported contexts:</p> -<ul> -<li>There are no supported contexts.</li> -</ul> -<p>Supported parameters for replacement:</p> -<ul> -<li>Parameter replacement is not supported.</li> -</ul> -<p>Default parameters as query string:</p> -<ul> -<li>No default query parameters</li> -</ul> -<p>Action URL defined by the user is assumed to be a POST API. This API should consume a predefined request body as shown below. This definition may have additional attributes in future.</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;id&#34;</span> : &lt;internal part number id&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;documentId&#34;</span> : &lt;documentId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementId&#34;</span> : &lt;elementId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;workspaceId&#34;</span> : &lt;workspaceId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementType&#34;</span> : &lt;elementType&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partId&#34;</span> : &lt;partId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;companyId&#34;</span> : &lt;companyId&gt;, <span style="color:#aaa;font-style:italic">// Id of the company that owns the document, else the text “cad” -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#a50">&#34;partNumber&#34;</span> : &lt;current part number&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;configuration&#34;</span> : &lt;configuration string&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;categories&#34;</span> : &lt;array <span style="color:#00a">of</span> category ids and names&gt; <span style="color:#aaa;font-style:italic">// [ { &#34;id&#34;: &lt;String&gt;, &#34;name&#34;: &lt;string&gt; } ] -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> } -</span></span><span style="display:flex;"><span> ] -</span></span></code></pre></div><p><strong>Note</strong>: Categories are only passed from the Release dialog and properties dialogs for now. They are empty when part number generation is called from the BOM table or configuration table.</p> -<p>Expected response sent to Onshape is as follows:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;id&#34;</span> : &lt;internal part number id&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;documentId&#34;</span> : &lt;documentId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementId&#34;</span> : &lt;elementId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;workspaceId&#34;</span> : &lt;workspaceId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;elementType&#34;</span> : &lt;elementType&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partId&#34;</span> : &lt;partId&gt;, -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;partNumber&#34;</span> : &lt;next part number generated by third party numbering scheme&gt; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> ] -</span></span></code></pre></div><p>Third-party applications can simply fill the <code>&quot;partNumber&quot;</code> attribute with the part number generated by the custom numbering scheme and send it as a response. However, the response should at least contain <code>&quot;id&quot;</code> and <code>&quot;partNumber&quot;</code> as highlighted above; other attributes are optional.</p> -<p>Custom numbering schemes for part generation, once set in the Release management page, can be invoked from all the places where we set part numbers, including the Release candidate dialog shown below:</p> -<p><img src="https://onshape-public.github.io/images/extensionsimage11.png" alt="image alt text"></p> -<h2 id="sample-code">Sample code</h2> -<p>We have provided a sample application that supports the features described in this document.</p> -<p>The source code for this <code>Inventory management</code> application can be found <a href="https://github.com/onshape-public/inventory-oauth2-app">in our public GitHub repository</a>.</p> -<p>The instructions to install and the application are available in the <code>README.md</code> file in the repository.</p> -<p>The application is built on the Passport node module. It is based on this <a href="http://scottksmith.com/blog/2014/05/02/building-restful-apis-with-node/">article</a>. Please read the article before proceeding with this section.</p> -<p>Some structural information about the application:</p> -<ul> -<li>The dependencies are defined in <code>package.json</code></li> -<li>The routing for inbound calls is defined in <code>server.js</code>. This includes routing for OAuth2 calls as well as calls for the rest APIs we expose that Onshape can call via the extensions.</li> -<li>The OAuth2 calls are routed to <code>controllers/oauth2.js</code>. These include calls to authenticate as calls to get the bearer token.</li> -<li><code>controllers/oauth2.js</code> uses <code>controllers/auth.js</code> to interact with Passport to manage the authentication and storage.</li> -<li>Other API calls to get part number, etc, route to the appropriate controller in the controllers directory.</li> -<li>The controllers use the model defined in the model directory.</li> -</ul> -<p>The application is defined in the Developer Portal with extensions that use the exposed APIs.</p> -<p>The following screenshots define the base configuration of the application and some of the sample extensions.</p>Docs: Client Messaginghttps://onshape-public.github.io/docs/app-dev/clientmessaging/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/clientmessaging/ -<p>Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message.</p> -<p><img src="https://onshape-public.github.io/images/javascriptpostmessageimage00.png" alt="image alt text"></p> -<p>Onshape Client Messaging examples can be split into those that are initiated from the <em>application extension</em> and those that are initiated from the <em>Onshape client</em>.</p> -<h2 id="messages-from-the-extension">Messages from the Extension</h2> -<p>These Client Messaging examples can be initiated from the application extension:</p> -<ul> -<li><strong>Click/close flyouts events</strong>: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.) and dropdown menus (profile dropdown menu, document menu) to close. Without this, flyouts and menus might remain open over the application extension.</li> -<li><strong>Shortcut keyboard events</strong>: Shortcut keys (such as <code>?</code>, which opens the Onshape Help dialog), can be handled by the application extension by posting a message to the Onshape client to open the dialog.</li> -<li><strong>keepAlive</strong>: Notify the Onshape client that the user is actively working in the application extension, which triggers the Onshape client to send a message to the server to keep the browser session alive. Without this, the Onshape browser session will timeout and ask the user to sign in again.</li> -<li><strong>Standard Onshape dialogs</strong>: Request from the application extension to the Onshape client to open one of the Onshape standard dialogs and send the user’s choices back to the application extension. For example, if the application extension needs the user to choose a part or assembly to be operated on, the application extension can post a message to the Onshape client requesting that dialog be opened and the selected part or assembly information sent back to the application extension.</li> -<li><strong>UI customization</strong>&quot;: Request from the application extension to the Onshape client to customize the Onshape UI (e.g., add commands to menus, add buttons to the toolbars, etc). When these commands or toolbar buttons are clicked, the Onshape client posts a message to the application extension with the available context. -<ul> -<li><strong>Note</strong>: This is limited to cases where the application extension is made active by the user; application extensions are not automatically loaded when a document is opened. Most UI customizations should be done when you register the application with Onshape, as those change the Onshape client automatically without needing to load the application extension first.</li> -</ul> -</li> -<li><strong>Content/material insertion</strong>: Request from the application extension to insert content into the Onshape document. For example, insert a part into a new or existing Part Studio, apply a material to a part, add a material to a material library, etc.</li> -</ul> -<h2 id="messages-from-onshape">Messages from Onshape</h2> -<p>The following examples can be initiated from the Onshape client:</p> -<ul> -<li><strong>User action notification</strong>: The Onshape client can notify an application extension when various user actions occur. For example, the Onshape client might notify when the user has made the application extension active or inactive (when the user clicks on document tabs). When an application extension is made inactive, it is moved off the edges of the browser, so it cannot be seen, but is still active, preserving its state.</li> -<li><strong>Printing</strong>: The Onshape client can notify an application extension when the user has chosen the <strong>Print</strong> command from the main Onshape document menu, enabling the application extension to perform a print operation.</li> -</ul> -<h2 id="security-considerations">Security Considerations</h2> -<p>To ensure security, an application extension must:</p> -<ul> -<li><strong>Parse for document, workspace, and element IDs</strong>: Parse for the <code>documentId</code>, <code>workspaceId</code>, and <code>elementId</code> that were passed as query parameters within the application extension’s iframe <code>src</code> URL. You must post these back in each <code>POST</code> message.</li> -<li><strong>Parse for the server</strong>: Parse for the <code>server</code> that was passed as a query parameter within the application extension’s iframe <code>src</code> URL. You must use this to validate messages received. -<ul> -<li>If the application extension uses a JavaScript library or framework (e.g., BackboneJS or AngularJS), it can parse the query parameters and maintain state in other ways.</li> -</ul> -</li> -<li><strong>Not redirect to another base URL</strong>: The browser tells the Onshape client the origin base URL from which a <code>POST</code> message is received. The Onshape client ignores messages posted from an origin URL that doesn’t match the original iframe <code>src</code> URL. It is <em>extremely important</em> to the security of your application that you verify that the origin of all messages you receive is the same as the original server query parameter in the iframe <code>src</code> (i.e., <code>if (server === e.origin)</code>). In production operation especially, the message IS NOT SAFE if the message origin does not match the iframe <code>src</code> server query parameter. Application extensions should not redirect to another base URL after the iframe has been opened, or the messages will be ignored.</li> -<li><strong>Post a message on startup</strong>: Onshape will not post messages until a newly started application extension has first posted a valid message to Onshape. This constraint is in effect anytime an application extension is (re)started and exists to avoid posting messages to application extensions that are not ready to handle them, are not fully loaded, etc. After your application extension is fully loaded and ready to receive messages, post a message to Onshape. A <code>keepAlive</code> message is a great first message to send to Onshape. Once Onshape receives a valid message, Onshape will start posting messages to the application extension. If the application extension later sends an invalid message Onshape will stop sending messages until a valid message is posted to Onshape.</li> -</ul> -<p><code>POST</code> messages submitted by application extensions to Onshape will be ignored if any of the following are true:</p> -<ul> -<li>The documentId, workspaceId, or elementId are missing or not valid.</li> -<li>The message name is missing or not recognized.</li> -<li>The origin of the <code>POST</code> message does not match the original iframe <code>src</code> URL.</li> -</ul> -<h2 id="element-tab">Element Tab</h2> -<p>Messages may be sent and received by element tab application extensions.</p> -<p>The following messages can be <strong>sent</strong> by Element tab application extensions:</p> -<table> -<tr> -<td>messageName -(case sensitive)</td> -<td>other message properties?</td> -<td>comment</td> -</tr> -<tr> -<td>applicationInit</td> -<td>yes -<pre><code>notifyWhenSaveRequired: whether Onshape should send a notification to save pending changes during certain operations -(default is false) -</code></pre> -</td> -<td>Send once on application startup.</td> -</tr> -<tr> -<td>closeFlyoutsAndMenus</td> -<td>no</td> -<td>Send when a mouse click or other event happens in the application extension. Closes Onshape flyouts and dropdown menus.</td> -</tr> -<tr> -<td>closeSelectItemDialog</td> -<td>no</td> -<td>Closes the select item dialog.</td> -</tr> -<tr> -<td>connectionLost</td> -<td>no</td> -<td>Displays the standard Onshape connection lost message in a message bubble, forcing the user to either reload the document or return to the documents page.</td> -</tr> -<tr> -<td>errorReload</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Similar to the connectionLost message, but enables an application to specify the first part of the message, which will be used instead of "Onshape is not connected." The user must reload the document or return to the documents page.</td> -</tr> -<tr> -<td>finishedSaving</td> -<td>yes -<pre><code>messageId: the id sent in the corresponding 'saveChanges' message -</code></pre> -</td> -<td>Response to a 'saveChanges' message sent from Onshape. Should be sent after application has cleaned up any pending edits.</td> -</tr> -<tr> -<td>keepAlive</td> -<td>no</td> -<td>Send periodically while while the user is actively working to avoid the session from timing out.</td> -</tr> -<tr> -<td>saveAVersion</td> -<td>no</td> -<td>Send when the user types “Shift-S” in the application extension, the keyboard shortcut for save a version.</td> -</tr> -<tr> -<td>showKeyboardShortcutsHelp</td> -<td>no</td> -<td>Send when the user types “?” (Shift-? on most keyboards) in the application extension, the keyboard shortcut for the keyboard shortcuts help dialog.</td> -</tr> -<tr> -<td>showMessageBubble</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Send when you want to show a string in the blue message bubble at the top of the Onshape app.</td> -</tr> -<tr> -<td>startLoadingSpinner</td> -<td>yes -<pre><code>message: your message -</code></pre> -</td> -<td>Send to start a large spinner in the middle of the browser window with your message underneath it.</td> -</tr> -<tr> -<td>stopLoadingSpinner</td> -<td>no</td> -<td>Send to stop the large spinner.</td> -</tr> -<tr> -<td>startWorkingSpinner</td> -<td>no</td> -<td>Send to start a small spinner in the middle bottom of the browser window.</td> -</tr> -<tr> -<td>stopWorkingSpinner</td> -<td>no</td> -<td>Send to stop the small spinner.</td> -</tr> -<tr> -<td>openSelectItemDialog</td> -<td>yes -<pre><code>dialogTitle: your dialog title -(default is no title), -selectBlobs: true or false -(default is false), -selectParts: true or false -(default is false), -selectPartStudios: true or false -(default is false), -selectAssemblies: true or false -(default is false), -selectMultiple: true or false -(default is false), -selectBlobMimeTypes: ‘comma-delimited string of blob mime types to show in dialog (e.g. “application/dwt,application/dwg”)’ -(default is an empty string) -showBrowseDocuments: true or false - controls whether ‘Other documents’ choice should be available -(default is true) -showStandardContent: true or false - controls whether ‘Standard content’ choice should be available -(default is false) -</code></pre> -</td> -<td>Send when your application wants to open a dialog in which the user will select one or multiple items - blobs, parts, part studios or assemblies. -</td> -</tr> -<tr> -<td>requestCameraProperties</td> -<td>yes -<pre><code>graphicsElementId: string , Element ID of the part studio or assembly -</code></pre> -</td> -<td> -Send to request camera properties of a specific part studio or assembly element. Note: The element should have been opened at least once in the current session. The messageName of the response is cameraProperties -</td> -</tr> -</table> -<p>The following messages can be <strong>received</strong> by Element tab application extensions:</p> -<table> -<tr> -<td>messageName -(case sensitive)</td> -<td>other message properties?</td> -<td>comment</td> -</tr> -<tr> -<td>show</td> -<td>no</td> -<td>Sent when an element tab application extension is shown (made active) within the Onshape client. This message is NOT sent when the element tab application extension is created.</td> -</tr> -<tr> -<td>hide</td> -<td>no</td> -<td>Sent when an element tab application extension is made inactive within the Onshape client. This message is NOT sent when an element tab application extension is deleted.</td> -</tr> -<tr> -<td>itemSelectedInSelectItemDialog</td> -<td>yes -<pre><code>documentId: id of selected item’s document, -workspaceId: id of selected item’s workspace, empty if versionId not empty, -versionId: id of selected item’s version, empty if workspaceId not empty, -elementId: id of element selected or containing the selected part, -elementName: name of element selected or containing the selected part, -elementType: type of element selected or containing the selected part - ‘partstudio’, ‘assembly’ or ‘blob’, -elementMicroversionId: microversion id of the element, -itemType: type of item selected: ‘part’,‘partStudio’ or ‘assembly’, -partName: name of part selected, empty if itemType is not ‘part’, -idTag: id of part, empty if no part selected -</code></pre> -</td> -<td>Sent when the user selects an item (blob, part, part studio or assembly) in the select item dialog that was opened due to an openSelectItemDialog message sent earlier. -When a part is not selected, the partXxx message properties will be empty strings.</td> -</tr> -<tr> -<td>print</td> -<td>no</td> -<td>Sent when the user chooses the Print command while the application is the active element. The application can choose to handle this as either a print or an export to a PDF or other format.</td> -</tr> -<tr> -<td>selectItemDialogClosed</td> -<td>no</td> -<td>Sent when the select item dialog closes, either because the user selected an item and selectMultiple is false, or the user changed the active element or the user closed the dialog with the "X" button.</td> -</tr> -<tr> -<td>startFirstViewCommand</td> -<td>yes -<pre><code>documentId: id of selected item’s document, -workspaceId: id of selected item’s workspace, empty if versionId not empty, -versionId: id of selected item’s version, empty if workspaceId not empty, -elementId: id of element selected or containing the selected part, -elementName: name of element selected or containing the selected part, -elementType: type of element selected or containing the selected part - ‘partstudio’, ‘assembly’ or ‘blob’, -elementMicroversionId: microversion id of the element, -itemType: type of item selected: ‘part’,‘partstudio’ or ‘assembly’, -partName: name of part selected, empty if itemType is not ‘part’, -idTag: id of part -</code></pre> -</td> -<td>Sent to a drawings application extension when the drawing is created with zero views. -<p>If other types of applications need a message posted to them with creation context, contact Onshape and we can discuss using this sort of message for your application also.</td></p> -</tr> -<tr> -<td>export</td> -<td>yes -<pre><code>fileExtension: the file extension of the export type the user chose - “.dwg”, “.dxf” are the types currently supported. -baseFileName: the base portion of the expected output file. This is currently set to “&lt;document name&gt; - &lt;element name&gt;” -</code></pre> -</td> -<td>Sent when the user chooses a command to export the contents of the application to a file.</td> -</tr> -<tr> -<td>cameraProperties</td> -<td>yes -<pre><code>graphicsElementId: string , Element ID of the part studio or assembly -isValid: boolean, Indicates if the properties are valid or not. false if element ID is invalid or element has not been open in the current session -projectionType: string, Denotes the projection method. Values are ‘orthographic’, ‘perspective’ . Empty string ‘’ if isValid is false -viewMatrix: 16 element numeric matrix with elements at index 13, 14, 15 corresponding to position of the camera -projectionMatrix: 16 element numeric matrix -verticalFieldOfView: number, 0 in case of orthographic projection -viewportHeight: number, eight of the viewport -viewportWidth: number, width of the viewport -</code></pre> -</td> -<td>Sent when application posts a requestCameraProperties message</td> -</tr> -<tr> -<td>takeFocus</td> -<td>no</td> -<td>Sent when the Onshape client sets focus on the content window of the element tab application extension.</td> -</tr> -<tr> -<td>saveChanges</td> -<td>yes -<pre><code>messageId: a unique identifier for this message. Should be passed back in the 'finishedSaving' message. -</code></pre> -</td> -<td>Sent if the application specified 'notifyWhenSaveRequired' in the 'applicationInit' message. Indicates that the application should cleanup any pending edits before an Onshape process continues (i.e. version save).</td> -</tr> -</table> -<h2 id="element-right-panel">Element Right Panel</h2> -<p>Most client messaging functionality had been limited to that occurring between the Onshape client and application elements (the <strong>Element tab</strong> location). Limited functionality in now also available for client messaging to work with application extensions in the <strong>Element right panel</strong> location.</p> -<p>Enabled messaging to Element right panel extensions includes the communication of selections that the user makes for the following application extension contexts:</p> -<ul> -<li>Part Studio</li> -<li>Assembly</li> -<li>Document</li> -</ul> -<p>All <a href="#security-considerations">Security Considerations</a> above apply to both Element tab and Element right panel extensions, with the following notes:</p> -<ul> -<li>Initial message from the application extension to the Onshape client, in the form of an <code>applicationInit</code> message (or one of any other messages supported by the element right panel extensions), is required to ensure the Onshape client does not send messages to the extension until it is ready.</li> -<li>Once a valid <code>applicationInit</code> message is received by the Onshape client, it will start sending messages with the <code>messageName</code> value <code>SELECTION</code> upon user selection interactions.</li> -<li>Prior to accepting <em>any</em> message from the Onshape client as secure, the <code>origin</code> attribute value included in incoming messages must be validated as equal to the original <code>server</code> query parameter value used to load the application extension.</li> -</ul> -<h2 id="code-snippets">Code Snippets</h2> -<h3 id="parse-query-parameters">Parse query parameters</h3> -<p>This JavaScript code parses the iframe <code>src</code> query parameters and uses them to post a message:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> <span style="color:#00a">var</span> documentId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> workspaceId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> elementId; -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> server; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Parse query parameters -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">var</span> queryParameters = <span style="color:#0aa">decodeURIComponent</span>(<span style="color:#0aa">window</span>.location.search.substr(<span style="color:#099">1</span>)); -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> queryParametersArray = queryParameters.split(<span style="color:#a50">&#39;&amp;&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">for</span> (<span style="color:#00a">var</span> i = <span style="color:#099">0</span>; i &lt; queryParametersArray.length; i++) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> parameterArray = queryParametersArray[i].split(<span style="color:#a50">&#39;=&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (parameterArray.length === <span style="color:#099">2</span>) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">switch</span> (parameterArray[<span style="color:#099">0</span>]) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;documentId&#39;</span>: -</span></span><span style="display:flex;"><span> documentId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;workspaceId&#39;</span>: -</span></span><span style="display:flex;"><span> workspaceId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;elementId&#39;</span>: -</span></span><span style="display:flex;"><span> elementId = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;server&#39;</span>: -</span></span><span style="display:flex;"><span> server = parameterArray[<span style="color:#099">1</span>]; -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Listen for clicks and post a message to the Onshape client -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#0aa">document</span>.getElementById(<span style="color:#a50">&#39;&lt;id of your topmost element&gt;&#39;</span>). -</span></span><span style="display:flex;"><span> addEventListener(<span style="color:#a50">&#39;click&#39;</span>, <span style="color:#00a">function</span>() { -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> message = {documentId: documentId, -</span></span><span style="display:flex;"><span> workspaceId: workspaceId, -</span></span><span style="display:flex;"><span> elementId: elementId, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;closeFlyoutsAndMenus&#39;</span>}; -</span></span><span style="display:flex;"><span> <span style="color:#0aa">window</span>.parent.postMessage(message, <span style="color:#a50">&#39;*&#39;</span>); -</span></span><span style="display:flex;"><span> }, <span style="color:#00a">true</span>); -</span></span></code></pre></div><h3 id="create-a-message-object">Create a message object</h3> -<p>The message object posted to the Onshape client is of the form:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> documentId: documentId, -</span></span><span style="display:flex;"><span> workspaceId: workspaceId, -</span></span><span style="display:flex;"><span> elementId: elementId, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;&lt;message name&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// … other properties as needed for other message types … -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>} -</span></span></code></pre></div><p>The message data object posted to the application extension is of the form:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;&lt;message name&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// … other properties as needed for other message types … -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>} -</span></span></code></pre></div><p>The message will always have a <code>messageName</code> property.</p> -<h3 id="listen-for-messages">Listen for messages</h3> -<p>To listen for messages from the Onshape client:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// server is one of the iframe src query parameters - see above -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> -</span></span><span style="display:flex;"><span> <span style="color:#00a">var</span> handlePostMessage = <span style="color:#00a">function</span>(e) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Post message received in application extension.&#34;</span>); -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;e.origin = &#34;</span> + e.origin); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// Verify the origin matches the server iframe src query parameter -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">if</span> (server === e.origin) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message safe and can be handled as it is from origin &#39;&#34;</span> -</span></span><span style="display:flex;"><span> + e.origin + -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#34;&#39;, which matches server query parameter &#39;&#34;</span> -</span></span><span style="display:flex;"><span> + server + <span style="color:#a50">&#34;&#39;.&#34;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (e.data &amp;&amp; e.data.messageName) { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message name = &#39;&#34;</span> + e.data.messageName + <span style="color:#a50">&#34;&#39;&#34;</span>); -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message name not found. Ignoring message.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> console.log(<span style="color:#a50">&#34;Message NOT safe and should be ignored.&#34;</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> }; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#0aa">window</span>.addEventListener(<span style="color:#a50">&#39;message&#39;</span>, handlePostMessage, <span style="color:#00a">false</span>); -</span></span></code></pre></div><h3 id="send-and-handle-messages">Send and handle messages</h3> -<p>The following is an example of how one might send an initialization message to, and handle post messages from, the Onshape client.</p> -<blockquote> -<p><em><strong>Note:</strong></em> Proper clean-up of event listeners is not included in the snippet</p> -</blockquote> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#00a">function</span> handlePostMessage(event) { -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// ensure that the event data is from a legit source: -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">if</span>(theServerStringFromActionUrl !== event.origin) { -</span></span><span style="display:flex;"><span> console.error(<span style="color:#a50">&#39;origin of message is not legitimate&#39;</span>); -</span></span><span style="display:flex;"><span> <span style="color:#00a">return</span>; -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#aaa;font-style:italic">// branch based on messageName attribute -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> <span style="color:#00a">switch</span>(event.data.messageName) { -</span></span><span style="display:flex;"><span> <span style="color:#00a">case</span> <span style="color:#a50">&#39;SELECTION&#39;</span>: -</span></span><span style="display:flex;"><span> console.debug(<span style="color:#a50">&#39;SELECTION event data: %o&#39;</span>, event.data); -</span></span><span style="display:flex;"><span> <span style="color:#00a">break</span>; -</span></span><span style="display:flex;"><span> <span style="color:#00a">default</span>: -</span></span><span style="display:flex;"><span> console.debug(<span style="color:#a50">`</span><span style="color:#a50">${</span>event.data.messageName<span style="color:#a50">}</span><span style="color:#a50"> not handled`</span>); -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>} -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">window</span>.addEventListener(<span style="color:#a50">&#39;message&#39;</span>, handlePostMessage); -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#00a">const</span> initMessage = { -</span></span><span style="display:flex;"><span> documentId: theDocumentId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> workspaceId: theWorkspaceId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> elementId: theElementId, <span style="color:#aaa;font-style:italic">// required - parsed from action url -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span> messageName: <span style="color:#a50">&#39;applicationInit&#39;</span> <span style="color:#aaa;font-style:italic">// required -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>}; -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#0aa">window</span>.parent.postMessage(initMessage, <span style="color:#a50">&#39;*&#39;</span>); -</span></span></code></pre></div><h3 id="right-panel-interaction-sequence">Right panel interaction sequence</h3> -<p>The sequence diagram below illustrates the interaction between an Element right panel application extension and the Onshape client:</p> -<pre tabindex="0"><code class="language-mermaid" data-lang="mermaid">%%{ -init: { -&#34;theme&#34;: &#34;default&#34;, -&#34;sequence&#34;: { -&#34;mirrorActors&#34;: false, -&#34;showSequenceNumbers&#34;: false, -&#34;width&#34;: 75, -&#34;height&#34;: 60, -&#34;actorMargin&#34;: 25, -&#34;messageFontSize&#34;: 13, -&#34;messageFontFamily&#34;: &#34;monospace&#34;, -&#34;messageFontWeight&#34;: 2 -} -} -}%% -sequenceDiagram -actor user -participant OSC AS Onshape Client -participant AE AS Application Extension -user-&gt;&gt;+OSC: start element right panel extension -Note right of user: via configured button -OSC-&gt;&gt;+AE: invoke action url (with query params) -AE-&gt;&gt;OSC: postMessage(messageName: &#39;applicationInit&#39;) -loop selection interactions -user-&gt;&gt;OSC: select -OSC-&gt;&gt;AE: postMessage(messageName: &#39;SELECTION&#39;) -end -user-&gt;&gt;OSC: stop element right panel extension -Note right of user: via configured button -deactivate AE -OSC-XAE: destroy -deactivate OSC -</code></pre><h3 id="right-panel-message-exchange">Right panel message exchange</h3> -<p>The following messages are exchanged for application extensions located in the element right panel and configured for Part Studio, Assembly, or Document contexts.</p> -<p>The first message with <code>messageName</code> attribute set to <code>applicationInit</code> is sent to the Onshape client by an application extension once it is loaded and ready to receive and process incoming messages:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> documentId: <span style="color:#a50">&#39;&lt;document id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> workspaceId: <span style="color:#a50">&#39;&lt;workspace id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> elementId: <span style="color:#a50">&#39;&lt;element id&gt;&#39;</span>, -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;applicationInit&#39;</span> -</span></span><span style="display:flex;"><span> } -</span></span></code></pre></div><p>The values <code>&lt;document id&gt;</code>, <code>&lt;workspace id&gt;</code>, <code>&lt;element id&gt;</code>, and <code>&lt;server id&gt;</code>:</p> -<ul> -<li>Are originally included as query parameters in the action URL used to request the content of the application extension</li> -<li>Must be included in messages sent to the Onshape client</li> -</ul> -<p>While initialization is the specific intent of the <code>applicationInit</code> message, other supported <code>messageName</code> attributes have the same initialization effect upon their first receipt by the Onshape client.</p> -<p>Next, as the user interacts with Onshape by selecting various parts of the model, messages with the <code>messageName</code> attribute set to <code>SELECTION</code> are sent to the application extension:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> messageName: <span style="color:#a50">&#39;SELECTION&#39;</span>, -</span></span><span style="display:flex;"><span> selections: [ -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> selectionType: <span style="color:#a50">&#39;ENTITY&#39;</span>, -</span></span><span style="display:flex;"><span> selectionId: <span style="color:#a50">&#39;KRiB&#39;</span>, -</span></span><span style="display:flex;"><span> entityType: <span style="color:#a50">&#39;FACE&#39;</span>, -</span></span><span style="display:flex;"><span> occurrencePath: [ -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;MfOieM8xKIDGHe37c&#39;</span> -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> workspaceMicroversionId: <span style="color:#a50">&#39;a781c53fbd1095e3462d2b70&#39;</span> -</span></span><span style="display:flex;"><span> }, -</span></span><span style="display:flex;"><span> { -</span></span><span style="display:flex;"><span> selectionType: <span style="color:#a50">&#39;ENTITY&#39;</span>, -</span></span><span style="display:flex;"><span> selectionId: <span style="color:#a50">&#39;KRdC&#39;</span>, -</span></span><span style="display:flex;"><span> entityType: <span style="color:#a50">&#39;EDGE&#39;</span>, -</span></span><span style="display:flex;"><span> occurrencePath: [ -</span></span><span style="display:flex;"><span> <span style="color:#a50">&#39;MfOieM8xKIDGHe37c&#39;</span> -</span></span><span style="display:flex;"><span> ], -</span></span><span style="display:flex;"><span> workspaceMicroversionId: <span style="color:#a50">&#39;a781c53fbd1095e3462d2b70&#39;</span> -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span> ] -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h2 id="notes">Notes</h2> -<h3 id="keyboard-focus">Keyboard focus</h3> -<p>Keyboard focus will not be transferred to an application until the user clicks in the application or the application programmatically takes focus. An application should programmatically take focus when it is first loaded and when it receives a <code>show</code> message from Onshape. Shortcut keys will work immediately when the application is shown.</p> -<h3 id="future-work">Future work</h3> -<ul> -<li>New message types will be added as needed. If your application extension needs a message not listed in this document, please notify us, and we’ll work with you on it.</li> -<li>Mobile client support is unclear at this time.</li> -<li>Onshape is considering using promises to wrap <code>POST</code> messages, which would make the application extension&rsquo;s JavaScript simpler and enable chaining <code>POST</code>s with other operations. Promises would make some interactions with multiple responses difficult (e.g., when you open a dialog, like the Select Item dialog, and want to receive multiple <code>POST</code> messages back due to the user clicking on multiple items in the dialog).</li> -</ul>Docs: Structured Storagehttps://onshape-public.github.io/docs/app-dev/structuredstorage/Mon, 18 May 2020 20:40:16 -0400https://onshape-public.github.io/docs/app-dev/structuredstorage/ -<h2 id="sub-elements">Sub Elements</h2> -<p>Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements.</p> -<p>The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.</p> -<p>An application may need to perform multiple versionable actions in the course of performing a user-level action, and we want to allow the individual actions to be collected into a single action from the perspective of document history. We do this by providing support for creation of a private transaction and support for atomically committing the transaction to the document workspace as a single user-visible action.</p> -<p>Onshape does not assume any knowledge about the semantics of application deltas. All merging of deltas into a consolidated form is done by the application. Applications should typically send checkpoint state for a sub-element if many delta changes have been made since the last checkpoint.</p> -<p>Document content and changes are logically an array of bytes, but since they are transmitted through JSON, then are expected to be presented a Base-64 encoding of the array into string form.</p> -<p>We use some terminology in this document that is new.</p> -<ul> -<li> -<p><strong>changeId</strong> - an opaque identifier for the state of an application element. Each change to the application element results in a new changeId</p> -</li> -<li> -<p><strong>transaction</strong> - a private workspace within a document workspace for composing modifications to an application element. These changes are not visible to the user until committed.</p> -</li> -<li> -<p><strong>transaction commit</strong> - an operation that moves the changes performed within a transaction to the application element workspace as a single user-visible action.</p> -</li> -</ul> -<p><strong>Concurrent access by multiple users</strong></p> -<p>If the element is being concurrently accessed by multiple sessions, updates may encounter conflicts during update. If the application has a mechanism that ensures that all accesses to the element are mediated by a single process, as is done with our part studio and assemblies, this can be addressed directly by the application. However, if the application is not able to mediate access in this way, updates by one session may invalidate state held by another session. We address this by notifying updaters when an update cannot be directly applied because their state is out of date and allowing them to refresh their state before re-applying the change.</p> -<p>This policy of requiring the application have current state when posting updates could be overly conservative in some cases. Detecting conflict at the sub-element level might provide for better concurrent access performance, but there probably are cases where this fails, so it probably would need some level of application control.</p> -<h2 id="json-tree">JSON Tree</h2> -<p>In contrast with sub elements, JSON tree storage is a more managed data storage mechanism that Onshape itself can merge and diff. At the root of it, the data structure is a single JSON object per Application Element. The user submits incremental changes that are then applied by Onshape to the JSON tree. Onshape stores these &lsquo;diffs&rsquo; in a new microversion created as a result of the update request, or during a subsequent transaction commit request. When the user then performs a merge or restore operation, Onshape can sum and apply the requisite incremental changes. By storing diffs, Onshape provides to the user a storage mechanism that is more robust to race conditions, since multiple simultaneous edits can be optionally merged by Onshape. All of these qualities make JSON tree a preferred way to store application element data in an Onshape-native manner.</p> -<h3 id="json-tree-edit-semantics">JSON Tree Edit Semantics</h3> -<h5 id="btjedit-encoding">BTJEdit Encoding</h5> -<p>A JSON tree edit represents an incremental change to an application element&rsquo;s JSON tree. The edit is a <code>BTJEdit</code> class, which is encoded as one of the following:</p> -<ul> -<li>Deletion:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span> } -</span></span></code></pre></div><ul> -<li>Insertion:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span> : <span style="color:#a50">&#34;newValue&#34;</span> } -</span></span></code></pre></div><ul> -<li>Change:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span> : <span style="color:#a50">&#34;newValue&#34;</span> } -</span></span></code></pre></div><ul> -<li>Move:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditMove-3245&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;sourcePath&#34;</span> : <span style="color:#a50">&#34;path&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;destinationPath&#34;</span> : <span style="color:#a50">&#34;path&#34;</span> } -</span></span></code></pre></div><ul> -<li>List (where edit1, edit2, etc. are zero or more edits.):</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJEditList-2707&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;edits&#34;</span> : [ <span style="color:#a50">&#34;edit1&#34;</span>, <span style="color:#a50">&#34;edit2&#34;</span>, <span style="color:#a50">&#34;...&#34;</span>] } -</span></span></code></pre></div><p>Within the above encoding, <code>newValue</code> is a stand in for any valid JSON, and <code>path</code> is a stand in for an object representing a path to the node at which to perform the edit.</p> -<h5 id="btjpath-encoding">BTJPath Encoding</h5> -<p>The BTJPath object describes a path through the JSON tree to a particular node, and is encoded as follows:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span> : <span style="color:#a50">&#34;startNode&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span> : [ <span style="color:#a50">&#34;pathElement1&#34;</span>, <span style="color:#a50">&#34;pathElement2&#34;</span>, <span style="color:#a50">&#34;...&#34;</span>] } -</span></span></code></pre></div><p>where startNode is a string that is either empty to specify the root node or a nodeId of a node in the tree. The pathElement is one of:</p> -<ul> -<li>Key:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span> : <span style="color:#a50">&#34;string&#34;</span> } -</span></span></code></pre></div><ul> -<li>Index:</li> -</ul> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ <span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span> : <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span> : <span style="color:#a50">&#34;integer&#34;</span> } -</span></span></code></pre></div><p>In the insertion and move type edits the path elements can describe a path that doesn&rsquo;t currently exist. Onshape will generate the proper keys and values as needed to place the node value in the proper location.</p> -<h3 id="json-tree-examples">JSON Tree Examples</h3> -<p>Below are some examples that show the body required to perform the particular edit on a JSON tree.</p> -<h4 id="deletion-example">Deletion Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>and a delete edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}} -</span></span></code></pre></div><p>then the resulting JSON is the result of deleting the node specified by <code>path</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><h4 id="insert-example">Insert Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><p>and the insertion edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;insertedKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>then the resulting JSON is the result of inserting the node described by <code>value</code> at the node specified by <code>path</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;insertedKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><h4 id="change-example">Change Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><p>and the change edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><p>then the resulting JSON is the result of changing the node specified by <code>path</code> to the node described by <code>value</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><h4 id="move-example">Move Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;myOtherKey&#34;</span>: <span style="color:#a50">&#34;myOtherValue&#34;</span>} -</span></span></code></pre></div><p>and the move edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditMove-3245&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;sourcePath&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;destinationPath&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;keyCreatedFromMove&#34;</span>}]}} -</span></span></code></pre></div><p>then the resulting JSON is the result of moving the node from the specified <code>sourcePath</code> to the <code>destinationPath</code>:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;keyCreatedFromMove&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div><h4 id="list-example">List Example</h4> -<p>If the pre-existing JSON tree looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{} -</span></span></code></pre></div><p>and the list edit looks like:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditList-2707&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;edits&#34;</span>: [ -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditChange-2636&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditInsert-2523&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span>: <span style="color:#099">1</span>}]}, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;value&#34;</span>: <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJEditDelete-1992&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPath-3073&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;startNode&#34;</span>: <span style="color:#a50">&#34;&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;path&#34;</span>: [{<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathKey-3221&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;key&#34;</span>: <span style="color:#a50">&#34;myKey&#34;</span>}, -</span></span><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;btType&#34;</span>: <span style="color:#a50">&#34;BTJPathIndex-1871&#34;</span>, <span style="color:#1e90ff;font-weight:bold">&#34;index&#34;</span>: <span style="color:#099">2</span>}]}} -</span></span><span style="display:flex;"><span> ]} -</span></span></code></pre></div><p>then the resulting JSON is the result of applying all the given edits in order:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>]} -</span></span></code></pre></div><p>The intermediate steps were:</p> -<ol> -<li>Insertion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: <span style="color:#a50">&#34;myValue&#34;</span>} -</span></span></code></pre></div></li> -<li>Change: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]} -</span></span></code></pre></div></li> -<li>List insertion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>, <span style="color:#a50">&#34;secondValue&#34;</span>]} -</span></span></code></pre></div></li> -<li>List deletion: -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {<span style="color:#1e90ff;font-weight:bold">&#34;myKey&#34;</span>: [<span style="color:#a50">&#34;firstValue&#34;</span>, <span style="color:#a50">&#34;myBetterSecondValue&#34;</span>]} -</span></span></code></pre></div></li> -</ol> -<p>All the examples above were tested and validated using the Python client <a href="https://github.com/onshape-public/onshape-clients/blob/next/python/test/test_app_element_json_tree.py">here</a>.</p>Docs: Webhookshttps://onshape-public.github.io/docs/app-dev/webhook/Mon, 18 May 2020 20:44:05 -0400https://onshape-public.github.io/docs/app-dev/webhook/ -<p>This page describes the Webhook APIs Onshape provides for working with notifications.</p> -<p>Notifications are delivered to an application as an HTTP <code>POST</code> with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message.</p> -<p>Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.</p> -<p>An application may register for notifications to a URL that uses either HTTP or HTTPS. If HTTPS is specified by the URL template, the notification server must supply a certificate that is signed by a certificate authority (CA) recognized by Onshape. Self-signed certificates (as well as certificates signed by unrecognized CAs) will be rejected, causing notification delivery to fail.</p> -<blockquote> -<p>📘 <strong>Notes</strong></p> -<ul> -<li>This page provides sample code as curls. See the <a href="https://curl.se/docs/">curl documentation</a> for more information.</li> -<li>All Onshape API calls must be properly authenticated by replacing the <code>CREDENTIALS</code> variable in the curls below. See the <a href="https://onshape-public.github.io/docs/auth/apikeys">API Keys</a> page for instructions and the <a href="https://onshape-public.github.io/docs/api-intro/quickstart">Quick Start</a> for an example. All applications submitted to the Onshape App Store <em>must</em> authenticate with <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth2</a>.</li> -<li>This documentation refers to Onshape IDs in the following format: <code>{did}, {wid}, {eid}, {pid}, {otherId}</code>. These represent document, workspace, element, part, and other IDs (respectively) that are needed make the API calls. We sometimes abbreviate these variables as <code>DWVEM</code> Please see <a href="https://onshape-public.github.io/docs/api-intro/#onshape-api-request">API Guide: API Intro</a> for information on what these IDs mean and how to obtain them from your documents. Sometimes, this page will use a stand-in string to represent these IDs (<code>000000000000000000000000</code>). Never include the curly braces (<code>{}</code>) in your API calls.</li> -<li>For Enterprise accounts, replace <strong><font color="slate">cad</font></strong> in all Onshape URLs with your company domain. -https://<font color="slate"><strong>cad</strong></font>.onshape.com &gt; https://<font color="slate"><strong>companyName</strong></font>.onshape.com</li> -</ul> -</blockquote> -<h2 id="events">Events</h2> -<p>Each type of event that an application may receive notifications for has a unique identifier known as the event type. Event types are grouped into Event Groups. Each group shares specification requirements.</p> -<p>Event types are categorized into several different groups based on the dominant user resource of the event. The group that a given event is part of defines the required parameters needed in the registration process to identify the resource or group of resources to watch. For instance, if registering for an event in the <code>document</code> event group, the application must identify either a specific document&rsquo;s id or a specific company&rsquo;s id. If registered for a company, the event will be registered for all present and future documents owned by the company.</p> -<blockquote> -<p>📘 <strong>Note</strong></p> -<p>You can see the full list of available events in the Glassworks API Explorer. Expand the <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">createWebhook</a> endpoint, then click <strong>Callbacks</strong>.</p> -<img src="https://onshape-public.github.io/images/webhooks-callbacks.png" alt="callbacks in the Glassworks Webhook > createWebhook > Callback page" width=80%> -</blockquote> -<h3 id="application-group">Application Group</h3> -<p>Monitor changes to applications.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.user.lifecycle.updateappsettings</code> - Occurs when user application settings are modified</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li><code>clientId</code> - Must be specified in the registration body</li> -<li><code>event</code> - Must be set to <code>onshape.user.lifecycle.updateappsettings</code></li> -<li><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></li> -<li><code>url</code> - Must be provided to receive the webhook notifications</li> -</ul> -<pre tabindex="0"><code>{ -&#34;clientId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.user.lifecycle.updateappsettings&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="document-group">Document Group</h3> -<p>Monitor various aspects of document changes.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.model.lifecycle.changed</code> - Occurs when a change to a model is made</li> -<li><code>onshape.model.translation.complete</code> - Occurs when a translation request is complete</li> -<li><code>onshape.model.lifecycle.metadata</code> - Occurs when Part or element metadata is modified</li> -<li><code>onshape.model.lifecycle.createversion</code> - Occurs when a new version of a document is created</li> -<li><code>onshape.model.lifecycle.createworkspace</code> - Occurs when a new workspace is created</li> -<li><code>onshape.model.lifecycle.createelement</code> - Occurs when a new element is created</li> -<li><code>onshape.model.lifecycle.deleteelement</code> - Occurs when an element is deleted</li> -<li><code>onshape.document.lifecycle.statechange</code> - Occurs when a document changes state</li> -<li><code>onshape.model.lifecycle.changed.externalreferences</code> - Occurs when an external reference changes</li> -<li><code>onshape.document.lifecycle.created</code> - Occurs when a document is created</li> -<li><code>onshape.revision.created</code> - Occurs when a revision is created</li> -<li><code>onshape.comment.create</code> - Occurs when a comment is created in a document</li> -<li><code>onshape.comment.update</code> - Occurs when a comment is updated in a document</li> -<li><code>onshape.comment.delete</code> - Occurs when a comment is deleted in a document</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li> -<p><code>documentId</code> OR <code>companyId</code> must be specified in the registration body</p> -<ul> -<li>Only <code>documentId</code> is valid for the <code>onshape.document.lifecycle.statechange</code></li> -</ul> -</li> -<li> -<p><code>event</code> - Must be set to one of the supported event types listed above</p> -<ul> -<li>May be set to <code>false</code> if the application is always listening to webhook notifications and <code>companyId</code> is specified.</li> -<li>If <code>false</code>, unregister the webhook when it is no longer needed.</li> -</ul> -</li> -<li> -<p><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></p> -</li> -<li> -<p><code>url</code> - Must be provided to receive the webhook notifications</p> -</li> -</ul> -<pre tabindex="0"><code>{ -&#34;documentId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.user.lifecycle.updateappsettings&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="workflow-group">Workflow Group</h3> -<p>Monitor release management actions.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>onshape.workflow.transition</code> - Occurs when a revision or release package transitions through workflow states</li> -</ul> -<p><strong>Registration Requirements</strong></p> -<ul> -<li><code>companyId</code> - Must be specified in the registration body</li> -<li><code>event</code> - Must be set to <code>onshape.workflow.transition</code> -<ul> -<li>May be set to <code>false</code> if the application is always listening to webhook notifications.</li> -<li>If <code>false</code>, unregister the webhook when it is no longer needed.</li> -</ul> -</li> -<li><code>options.collapseEvents</code> - Must be set to <code>true</code> or <code>false</code></li> -<li><code>url</code> - Must be provided to receive the webhook notifications</li> -</ul> -<pre tabindex="0"><code>{ -&#34;companyId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.workflow.transition&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -} -</code></pre><h3 id="lifecycle-group">Lifecycle Group</h3> -<p>Monitor webhook changes. You do not need to register for these events; they are sent automatically when a webhook for another event type is registered, unregistered, or pinged.</p> -<p><strong>Supported Event Types</strong></p> -<ul> -<li><code>webhook.register</code> - Occurs in response to a notification registration API call</li> -<li><code>webhook.unregister</code> - Occurs in response to a notification deregistation API call</li> -<li><code>webhook.ping</code> - Occurs either: -<ul> -<li>In response to a request by an application to call the <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/pingWebhook">pingWebook</a> endpoint.</li> -<li>As a post-registration validation initiated by Onshape</li> -</ul> -</li> -</ul> -<h2 id="example-notifications">Example Notifications</h2> -<p><strong>webhook.register</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.register&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>webhook.ping</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.ping&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.model.lifecycle.changed</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.model.lifecycle.changed&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.document.lifecycle.statechange</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.document.lifecycle.statechange&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentState&#34;</span>: <span style="color:#a50">&#34;TRASH&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>Possible values of <code>documentState</code> are:</p> -<ul> -<li><code>ACTIVE</code> - Document is in a normal, usable state.</li> -<li><code>TRASH</code> - Document has been moved to the trash; user can move document back to <code>ACTIVE</code> state.</li> -<li><code>DELETED</code> - Document has been deleted; user cannot access document.</li> -</ul> -<p><strong>onshape.user.lifecycle.updateappsettings</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.user.lifecycle.updateappsettings&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;userId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;clientId&#34;</span>:<span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.model.translation.complete</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.model.translation.complete&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;userId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;translationId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p><strong>onshape.comment.create</strong></p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2024-05-05T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.comment.create&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;commentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><h2 id="endpoints">Endpoints</h2> -<p>Webhook notifications allow an application to register to receive notifications of certain events that occur within the Onshape environment. To receive a notification, an application must expose an endpoint that Onshape can call.</p> -<ul> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhooks">Webhook/getWebhooks</a> -<pre tabindex="0"><code> curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks?user={uid}&amp;offset=0&amp;limit=20&#39; \ --H &#39;aAccept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">Webhook/createWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;events&#34;: [ -&#34;eventType&#34; // See the [Events](#events) section above for valid event types. -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: true | false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -//Other parameters may be required. See the [Events](#events) section above. -}&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhook">Webhook/getWebhook</a> -<pre tabindex="0"><code>curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/webhookId&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/updateWebhook">Webhook/updateWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/webhookId&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;id&#34;: &#34;webhookId&#34;, -&#34;options&#34;: { -&#34;collapseEvents&#34;: true | false -} -}&#39; -</code></pre><ul> -<li>Note that the webhook <code>id</code> must be sent in both the URL and the request body.</li> -</ul> -</li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/unregisterWebhook">Webhook/unregisterWebhook</a> -<pre tabindex="0"><code> curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/{webhookId}?blockNotification=false&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -<li><a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/pingWebhook">Webhook/pingWebhook</a> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/{webhookId}/ping&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; -</code></pre></li> -</ul> -<h2 id="sample-workflows">Sample Workflows</h2> -<h3 id="create-a-webhook">Create a webhook</h3> -<p>An application registers for event notification by:</p> -<ol> -<li>Making a REST call to the Onshape web service</li> -<li>Providing a URL to notify</li> -<li>Providing the required parameters for the event types to be registered</li> -</ol> -<p>If the registration request is well-formed, the registration API call returns information about the registration, including a unique <code>id</code> string that identifies the webhook registration. This corresponds to the <code>webhookId</code> field in other endpoints. No de-duplication of notification registrations is performed by the API. Each registration call will yield a new <code>registrationId</code>, even if the parameters are identical to those passed in a prior call.</p> -<p>Shortly after an application calls the notification registration API, Onshape will make make an asynchronous trial notification call to the URL generated from the URL template with an event type of <code>webhook.register</code> to test if the application notification server is accessible. If the trial notification delivery fails to return an HTTP <code>200</code> status code, the notification registration is cancelled. The trial notification is usually delivered after the notification registration has been received by the application. However, variations in network delays may result in the trial notification occurring before the response is received and processed by the application, so the notification handler should be ready to process notifications before the registration call is made.</p> -<p>In this example, we use a webhook to send information from Onshape to another server. You need a URL for Onshape to send notifications to, and a way to view the messages sent with those notifications.</p> -<ol> -<li>Open an Onshape document, or create a new one.</li> -<li>In this example, we want to receive a notification from Onshape any time a new version is created in the specified document. For this, we’ll use <code>onshape.model.lifecycle.createversion</code> as our <code>event</code>.</li> -<li>The event type requires one parameter. We’ll use our <code>documentId</code> for this field (shown as <code>000000000000000000000000</code> in the example below).</li> -<li>All event types require specifying <code>true</code> or <code>false</code> for the <code>options.collapseEvents</code> field. In this case, set the field to <code>false</code>.</li> -<li>Next, we need the URL to send the notification to. You must provide your own URL to receive notifications here.</li> -<li>Confirm your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/createWebhook">createWebhook</a> call looks like this (substitute your own authorization credentials, document ID, and URL), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;documentId&#34;: &#34;000000000000000000000000&#34;, -&#34;events&#34;: [ -&#34;onshape.model.lifecycle.createversion&#34; -], -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -}, -&#34;url&#34;: &#34;https://sampleUrl.org&#34; -}&#39; -</code></pre><ol start="7"> -<li>In your application, confirm that you received the <code>webhook.register</code> event from Onshape.</li> -<li>In Onshape, create a new version in your document.</li> -<li>In your application, confirm that you received the <code>onshape.model.lifecycle.createversion</code> event from Onshape. Make note of the <code>id</code> in the response; use this as your <code>webhookId</code> in subsequent examples.</li> -</ol> -<h3 id="get-webhook-info">Get webhook info</h3> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/getWebhook">getWebhook</a> call. substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;GET&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ -</code></pre><ol start="3"> -<li>Confirm that the <code>event</code> in the response is <code>onshape.model.lifecycle.createversion</code>.</li> -</ol> -<h3 id="update-a-webhook">Update a webhook</h3> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>. Note that in the same response, the webhook <code>description</code> is <code>null</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/updateWebhook">updateWebhook</a> call. In this example, ww update the webhook&rsquo;s <code>description</code>. Substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below in both the URL and request body). Then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;POST&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS&#39; \ --H &#39;Content-Type: application/json;charset=UTF-8; qs=0.09&#39; \ --d &#39;{ -&#34;id&#34;: &#34;000000000000000000000000&#34;, -&#34;description&#34;: &#34;Send a notification each time a document version is created.&#34;, -&#34;options&#34;: { -&#34;collapseEvents&#34;: false -} -}&#39; -</code></pre><ol start="3"> -<li>Confirm in the response that the webhook <code>description</code> is set to <code>Send a notification each time a document version is created.</code></li> -</ol> -<h3 id="delete-a-webhook">Delete a webhook</h3> -<p>When an application no longer needs to be notified of changes specified by a particular notification registration, it should normally deregister the notification request. Deregistration is performed by making an HTTP that specifies the hook to deregister. Onshape will attempt to call the deregistered hook with an event type of <code>webhook.unregister</code> as validation that the deregistration is complete. If the application does not deregister the webhook, Onshape will continue delivering notifications until the the application either returns an error in response to a notification for the webhook or fails to respond at all for an extended period of time.</p> -<ol> -<li>Complete the <a href="#create-a-webhook">Create a webhook</a> steps above to obtain a <code>webhookId</code>.</li> -<li>Create your <a href="https://cad.onshape.com/glassworks/explorer/#/Webhook/deleteWebhook">deleteWebhook</a> call. substitute your own authorization credentials and <code>webhookId</code> (shown as <code>000000000000000000000000</code> in the example below), then make the call.</li> -</ol> -<pre tabindex="0"><code> curl -X &#39;DELETE&#39; \ -&#39;https://cad.onshape.com/api/v6/webhooks/000000000000000000000000&#39; \ --H &#39;Accept: application/json;charset=UTF-8; qs=0.09&#39; \ --H &#39;Authorization: Basic CREDENTIALS=&#39; \ -</code></pre><ol start="3"> -<li>In your application, confirm that you received the <code>webhook.unregister</code> event from Onshape.</li> -<li>In Onshape, create a new version in your document.</li> -<li>In your application, confirm that no new events have been received.</li> -</ol> -<h2 id="additional-resources">Additional Resources</h2> -<ul> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">Onshape Help: Webhooks</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/explorer">API Guide: API Explorer</a></li> -<li><a href="https://cad.onshape.com/help/Content/Plans/webhooks.htm">API Explorer: Webhooks</a></li> -<li><a href="https://github.com/onshape-public/onshape-clients/blob/master/python/test/test_webhooks.py#L126">Sample Code: Python Webhooks</a></li> -</ul>Docs: Launch Checklisthttps://onshape-public.github.io/docs/app-store/checklist/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/checklist/ -<p>This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion.</p> -<h3 id="1-understand-quality-expectations">1. Understand quality expectations</h3> -<p>These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the <a href="https://onshape-public.github.io/docs/app-store/quality">Quality Considerations</a> page, and reach out to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> with any questions.</p> -<h3 id="2-sign-in-to-your-developer-account">2. Sign in to your developer account</h3> -<p>Sign in to your developer account at <a href="https://dev-portal.onshape.com">dev-portal.onshape.com</a>, and ensure your developer account details are accurate. Contact our <a href="mailto:api-support@onshape.com">API Support team</a> if you need assistance.</p> -<h3 id="3-authenticate-your-app">3. Authenticate your app</h3> -<p>Please refer to the <a href="https://onshape-public.github.io/docs/auth/oauth">OAuth documentation</a> for information on authenticating your app with OAuth2.</p> -<h3 id="4-build-your-app">4. Build your app</h3> -<p>While building your app, use the resources in our Onshape Developer Documentation, including this API Guide and our API Explorer. We recommend familiarizing yourself with the following pages:</p> -<ul> -<li><a href="https://onshape-public.github.io/docs/api-intro/">Introduction to the Onshape REST API</a></li> -<li><a href="https://onshape-public.github.io/docs/api-intro/architecture">Onshape Architecture</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/">Onshape App Development</a></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/extensions">Extensions</a> <!-- Susan move the videos to their pages --></li> -<li><a href="https://onshape-public.github.io/docs/app-dev/clientmessaging">Client Messaging</a></li> -<li><a href="https://onshape-public.github.io/docs/app-store">Onshape App Store</a></li> -</ul> -<h3 id="5-prepare-your-store-entry">5. Prepare your store entry</h3> -<p>Prepare the descriptions, promotional graphics, screenshots, and videos you&rsquo;ll add to your store entry. Make sure you include a link to if required. Watch this video for more details.</p> -<p>See the video below for a walkthrough:</p> -<p><a href="https://onshape.wistia.com/medias/tuhuzfi7we"><img src="https://onshape-public.github.io/images/AppStoreEntryVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></p> -<h3 id="6-run-beta-tests">6. Run beta tests</h3> -<p>During the beta period, try to enlist at least 5 active testers to get feedback before making your app available to the general public.</p> -<ol> -<li>To find beta testers, contact our <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a>, and recruit via the <a href="https://forum.onshape.com/categories/developer-community">Onshape forum</a>.</li> -<li>To give beta users early visibility, first <a href="https://cad.onshape.com/help/Content/teams-enterprise.htm">create a team</a>, then ensure your app is shared with that team in the <a href="https://dev-portal.onshape.com">Developer Portal</a>. See the <a href="https://onshape.wistia.com/medias/5t1dwkspfo">Create a Team in Onshape video</a> for a walkthrough.</li> -</ol> -<h3 id="7-determine-your-apps-price">7. Determine your app&rsquo;s price</h3> -<p>Once you&rsquo;ve determined your monetization model, set up your price, billing, and other details. Billing should be tested, and to do so a staging environment is available. See the <a href="https://onshape-public.github.io/docs/api-adv/billing">Billing API</a> page for more details.</p> -<h3 id="8-sign-and-return-the-developer-agreement">8. Sign and return the developer agreement</h3> -<p>Email to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> to obtain yours.</p> -<h3 id="9-submit-your-app-for-final-testing">9. Submit your app for final testing</h3> -<p>Once you&rsquo;ve returned the developer agreement, you can submit your app to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> for final testing. <a href="https://onshape-public.github.io/docs/app-store/testingguidelines">This is a comprehensive functionality and design test.</a> During this testing period (expect up to a week, depending on complexity), changes to code are prohibited unless requested. At the conclusion of the test, you will receive one of the following notifications from our Developer Relations team:</p> -<ul> -<li>Approved for release</li> -<li>Approved for release with feedback</li> -<li>Changes required before another round of testing</li> -</ul> -<h3 id="10-integrate-your-support-systems">10. Integrate your support systems</h3> -<p>Whether you use Zendesk, Jira, or email support, we’ll help you determine and set up this integration. Contact the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> to explore these options. This is the channel we will use to test your app and provide feedback.</p> -<h3 id="11-connect-via-slack">11. Connect via Slack</h3> -<p>Connecting directly with our Support, Tech, and Sales teams has proven to be valuable to app developers. This dedicated channel is simple to implement if you already have a paid Slack account. If not (or if you want to use the free version of Slack), we can add members of your team as guests to our account. Please contact <a href="mailto:amagnin@ptc.com">Aaron Magnin</a> to establish this connection.</p> -<h3 id="12-final-check-and-publish">12. Final check and publish</h3> -<p>First, double-check you&rsquo;ve done everything on this list. Now you&rsquo;re ready to publish your app to the production channel! Send an email detailing <strong>when</strong> you’d like this to happen to the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a>.</p> -<h3 id="13-promote-your-app">13. Promote your app</h3> -<p>Start promoting your app with the <a href="https://www.ptc.com/en/brand-guide/logos/onshape">Onshape badge</a> and by presenting it to our internal teams in one of the following ways:</p> -<ul> -<li>To the Onshape Tech and Sales teams in a small meeting (~1 hour, Wednesdays at noon Eastern Time)</li> -<li>To the entire Onshape organization in a company-wide meeting (~5-10 minutes, Thursdays at 11am Eastern Time).</li> -</ul> -<h3 id="14-encourage-reviews-from-users">14. Encourage reviews from users</h3> -<p>The value of reviews is not to be underestimated. Reviews give users an opportunity to provide feedback, and can also signal to others that your app is worth investigating.</p> -<h3 id="15-maintain-your-app">15. Maintain your app</h3> -<p>Continually fix stability and performance issues. Improving the user experience will result in more engaged users, higher ratings, and in turn, more success.</p> -<blockquote> -<blockquote> -<p>Failure to respond to customer tickets in a reasonable time will lead to the removal of your app from the Onshape App Store.</p> -</blockquote> -</blockquote> -<h3 id="16-increase-engagement-and-retention">16. Increase engagement and retention</h3> -<p>Aim to increase user engagement, retain and grow your audience, and earn more revenue by:</p> -<ul> -<li>Encouraging repeat visits with a nurture stream and training materials</li> -<li>Integrating more features from user requests</li> -<li>Interacting with and understanding your audience via the <a href="https://forum.onshape.com/categories/developer-community">Onshape forum</a>, social media, etc.</li> -</ul> -<h3 id="17-address-app-security">17. Address app security</h3> -<p>At some point, a prospect or user will enquire about your app&rsquo;s security controls. To address this, we recommend that you understand SOC 2 Compliance requirements, and consider filling out the <a href="https://www.google.com/url?q=https://cloudsecurityalliance.org/artifacts/consensus-assessments-initiative-questionnaire-v3-1/&amp;sa=D&amp;source=editors&amp;ust=1686683388460627&amp;usg=AOvVaw2xq8zlODs3a7W2Y3jighnr">Consensus Assessment Initiative Questionnaire</a> (CAIQ). Onshape/PTC cannot and will not attest to your compliance. More on SOC Compliance can be found at the following links:</p> -<ul> -<li><a href="https://us.aicpa.org/interestareas/frc/assuranceadvisoryservices/aicpasoc2report">AICPA.org</a></li> -<li><a href="https://en.wikipedia.org/wiki/System_and_Organization_Controls">Wikipedia: System and Organization Controls</a></li> -</ul>Docs: Testing Guidelineshttps://onshape-public.github.io/docs/app-store/testingguidelines/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/testingguidelines/ -<p>The purpose of this document is to help you get your application and App Store entry ready for QA testing.</p> -<h2 id="application-release-workflow-arw">Application Release Workflow (ARW)</h2> -<p>Each application submitted to the Onshape App Store goes through a series of stage-gates:</p> -<ol> -<li>Starting state: <code>Ok to deploy to limited visibility on Production</code> (Beta testing)</li> -<li><code>Ok to make Public</code></li> -<li>Goal state: <code>Application is Public</code></li> -</ol> -<p>To advance to the next stage, your application must pass testing, and your App Store entry must pass review.</p> -<h2 id="kick-off-testing">Kick Off Testing</h2> -<p>While completing the <a href="https://onshape-public.github.io/docs/app-store/checklist">Launch Checklist</a>, you will need to use Jira to request testing and release for your application. You can initiate the following tasks from Jira:</p> -<ul> -<li><code>Request application testing</code>: This puts your application in the testing queue. We will note when testing has started (<code>in progress</code>) and when concluded, the ticket will be closed. The outcome will include notes and links to any issues generated (<code>tickets</code>). This phase may include as many iterations as needed to get your application ready.</li> -<li><code>Request public (general) authorization</code>: We will note when testing has started (<code>in progress</code>), and this request will trigger a review of your app store entry and any outstanding bugs. Note there is no implied testing of your application, simply a review of outstanding issues (<code>tickets</code>) and of the App Store entry. Success at this stage will advance the Application Release Workflow (ARW), and you can request public release.</li> -<li><code>Request public (general) release</code>: This request states that you have coordinated with the <a href="mailto:onshape-developer-relations@ptc.com">Developer Relations team</a> and the Onshape Marketing team<!--How do they get in touch with the Marketing team? Slack?-->, and agreement has been reached that the app is ready for launch. Congratulations!</li> -</ul> -<h2 id="testing-protocol">Testing Protocol</h2> -<p><em>Applications</em> are first tested against the checklist in <a href="#addendum-a">Addendum A</a>. <em>Production App Store</em> entries are then performed against the checklist in <a href="#addendum-b">Addendum B</a>.</p> -<p>Results will be viewable in your Onshape support system (i.e., Zendesk, Jira). The result of each test will be one of:</p> -<ul> -<li><code>Pass</code>: -<ul> -<li>No action needed.</li> -<li>No notification issued. <!-- How do they know it passed? Does it just show up in the app store? --></li> -</ul> -</li> -<li><code>Enhancement</code>: Suggestions we believe would make the application better. -<ul> -<li>Will NOT prevent the application from being turned on for public access.</li> -</ul> -</li> -<li><code>Bug (low priority)</code>: Slight deviations from the criteria that have low end user impact. -<ul> -<li>Will NOT prevent the application being turned on for public access.</li> -<li>No stipulated time-frame for resolution.</li> -</ul> -</li> -<li><code>Bug (medium priority)</code>: Material deviations from the criteria that are noticeable to the end-user. Represents a minor problem that requires a work-around. -<ul> -<li>Will NOT prevent the application from being turned on for public access.</li> -<li>Must be fixed within 30 days.</li> -</ul> -</li> -<li><code>Bug (high priority)</code>: Significant deviation from the criteria. -<ul> -<li>WILL prevent the application from being turned on for public access.</li> -</ul> -</li> -<li><code>Bug (MUST FIX)</code>: Significant deviation from protocol or security violation. -<ul> -<li>WILL prevent the application from being turned on for public access.</li> -<li>If the application is already public, it may be temporarily suspended from the App Store.</li> -</ul> -</li> -</ul> -<h2 id="testing-notes">Testing Notes</h2> -<ul> -<li>Testing may be requested at any time.</li> -<li>Testing is done on a first-come basis.</li> -<li>When testing is complete (pass or fail), you go to the back of the queue.</li> -</ul> -<h2 id="addendum-a">Addendum A</h2> -<p><font size="5">Application Test Criteria</font></p> -<ul> -<li>The application must use the Onshape OAUTH mechanism</li> -<li>The OAUTH must be against the correct stack</li> -<li>To be promoted to the Production stack, and hosted service must be on a monitored production server with worldwide 24/7 availability.</li> -<li>The application should not generate any avoidable console (browser) errors</li> -<li>The application should should provide one or more of the following options. The user should not have to leave the registration workflow to complete a pre-requisite. -<ul> -<li>Sign in using the Onshape ID (account created silently on first use)</li> -<li>Sign in with partner product account credentials</li> -<li>Create a new partner account</li> -</ul> -</li> -<li>The application must be capable of managing/displaying documents in excess of 20. The application must display reasonable performance when reading documents, workspaces, elements, and parts. At scale, an account may have thousands of documents, many with multiple workspaces and each with multiple elements. Suggested strategies include: -<ul> -<li>Using a <code>Next</code> button to load the next 20 documents</li> -<li>Using infinite scroll (loading the next 20 if the scrollbar reaches the bottom of the dialog)</li> -<li>Displaying the most recently-opened documents first</li> -<li>Displaying a counter of documents/workspaces/elements read</li> -<li>Using progressive loading</li> -</ul> -</li> -<li>The application should correctly list valid documents when <code>per document app access</code> is turned on.</li> -<li>The application should correctly handle selection of versions.</li> -<li>The application should correctly handle selection of workspaces (branches).</li> -<li>The application should correctly handle/display elements that are: -<ul> -<li>Part Studios that contain nothing</li> -<li>Assemblies that contain nothing</li> -<li>Part Studios that contain only surfaces</li> -<li>Part Studios that contain only wire data (e.g., helices)</li> -</ul> -</li> -<li>The application should appropriately handle revocation of a grant.</li> -</ul> -<h2 id="addendum-b">Addendum B</h2> -<p><font size="5">App Store Testing Criteria</font></p> -<ul> -<li>The application should have a descriptive name</li> -<li>The application summary should be accurate</li> -<li>The redirect URLS should be valid</li> -<li>The iframe URL should be valid</li> -<li>The <code>Grant</code> (permissions) request should be no more than is needed</li> -<li>The <code>Application Type</code> should be correctly set</li> -<li>Team visibility should be set (optional)</li> -<li>The category should be appropriate</li> -<li>The application description should be accurate</li> -<li>The Sign-In URL should be valid</li> -<li>The pricing summary should be accurate -<ul> -<li>i.e., trials should not be listed as <code>Free</code>; <code>Free for xx days and then $xx/month</code> is more accurate.</li> -</ul> -</li> -<li>All pay plans should have accurate descriptions.</li> -<li>The support URL should point to a resource for help (the resource should NOT be an FAQ page, unless that page also contains one of the other options): -<ul> -<li>Support ticketing system (e.g., Zendesk, Jira, etc.)</li> -<li>Web page with a telephone number</li> -<li>Web page with an email address</li> -<li>Forum</li> -</ul> -</li> -<li>The EULA link should point to an English Language EULA.</li> -</ul>Docs: Quality Considerationshttps://onshape-public.github.io/docs/app-store/quality/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/quality/ -<h2 id="core-app-quality">Core App Quality</h2> -<p>Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention.</p> -<p>This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria.</p> -<p>Before publishing your apps, test them against these criteria to ensure that they function well. Your testing should go well beyond what&rsquo;s described here; the purpose of this page is to specify the essential quality characteristics all apps should display, so that you can cover them in your test plans.</p> -<h2 id="functionality">Functionality</h2> -<p>These criteria ensure that your app provides the expected functional behavior, with the appropriate level of permissions.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Permissions</td> -<td>The app requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.</td> -</tr> -</tbody> -</table> -<h2 id="compatibility-performance-and-stability">Compatibility, Performance, and Stability</h2> -<p>These criteria ensure that apps provide the compatibility, performance, stability, and responsiveness expected by users.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Stability</td> -<td>The app does not crash, force close, freeze, or otherwise function abnormally.</td> -</tr> -<tr> -<td>Performance</td> -<td>The app loads quickly or provides onscreen feedback to the user (e.g., a progress indicator or similar cue) if the app takes longer than two (2) seconds to load.</td> -</tr> -<tr> -<td>Visual quality</td> -<td>The app displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</td> -</tr> -</tbody> -</table> -<h2 id="security">Security</h2> -<p>These criteria ensure that apps handle user data and personal information safely.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Data</td> -<td>All private data is stored in the app&rsquo;s internal storage. </br> All data from external storage is verified before being accessed. </br> No personal or sensitive user data is logged to the system or app-specific log.</td> -</tr> -<tr> -<td>Networking</td> -<td>All network traffic is sent over SSL.</td> -</tr> -</tbody> -</table> -<h2 id="onshape-app-store">Onshape App Store</h2> -<p>These criteria ensure that your apps are ready to publish on Onshape App Store.</p> -<table> -<thead> -<tr> -<th>Area</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>App Details page</td> -<td>The app’s feature graphic follows guidelines such as: </br>- The app listing includes a high-quality feature graphic.</br>- The feature graphic does not resemble an advertisement.</br>- The app’s screenshots or videos do not represent the content and experience of your app in a misleading way.</td> -</tr> -<tr> -<td>User support</td> -<td>User-reported bugs are addressed if they are reproducible.</td> -</tr> -</tbody> -</table> -<h2 id="test-procedures">Test procedures</h2> -<p>These test procedures help you discover various types of quality issues in your app. You can combine the tests or integrate groups of tests together in your own test plans. See the sections above for references that associate criteria with these test procedures.</p> -<table> -<thead> -<tr> -<th>Type</th> -<th>Description</th> -</tr> -</thead> -<tbody> -<tr> -<td>Core suite</td> -<td>Navigate to all parts of the app: all screens, dialogs, settings, and all user flows.</td> -</tr> -<tr> -<td>Security</td> -<td>- Review all data stored in external storage. </br>- Review how data loaded from external storage is handled and processed.</td> -</tr> -</tbody> -</table>Docs: Sync Data and Metadatahttps://onshape-public.github.io/docs/tutorials/sync/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/sync/ -<p>The first business case is probably the most common, “How do I sync data -that I create in Onshape with my ERP or PLM system?”. There could be -many reasons why you would want to sync data between two different -systems. Primarily Onshape is a system that creates new data. This data -is created by designers as they perform their daily tasks. While the -designer works primarily in Onshape, the actual data that they create -does not exist in a vacuum, it is used by other departments, other -processes within the organization. These departments and processes -probably do not have access to Onshape or the required knowledge of how -to use Onshape. In addition, quite often, the data generated by Onshape -will be augmented with additional data as the product lifecycle process -progresses.</p> -<p>Therefore, Onshape could be considered the genesis of the data that will -be used to develop a product, yet it is not the only data that will be -required.</p> -<h2 id="overview">Overview</h2> -<p>In this business case we examine how a designer could work in Onshape -and how the data generated by Onshape can be used to make decisions in -other systems. Based upon the decisions made, data is pushed back to -Onshape as values calculated in another system. Let’s look at the -process in much more detail.</p> -<h3 id="step-1-define-properties-in-onshape">Step 1: Define Properties in Onshape</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage31.png" -style="width:5.41667in;height:1.84722in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>In the first step, the designer starts a new part in Onshape – -remember that in Onshape a Part can be created along with other -parts in a Part Studio, so we can assume that there could be -multiple parts created in the single document. Obviously, we want -the designer to have the freedom to use all Onshape functionality -without constraints placed by the demands of the integration.</p> -</li> -<li> -<p>At some point in the design process, the designer will be required -to enter property values for the part – these could include values -such as the Part Name, the description, material and so on.</p> -</li> -<li> -<p>The designer clicks the “Save” or “Apply” button for the properties -and closes the properties window.</p> -</li> -<li> -<p>A web hook that listens to any changes in the properties has been -defined. As the user saves the properties, the web hook is -triggered, and it will send a notification through the defined web -hook to the third-party system.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note: There are Part -properties, workspace properties and document properties – all these -properties live at different levels of the document. While the trigger -could pick up changes to any to these properties, we are currently -focused on just Part properties – the event will be triggered on any -saving of properties, however our third-party code can ignore anything -that’s not a Part (or an Assembly). In this next step we assume that a -new object is being created in the third-party application.</p> -<h3 id="step-2-create-corresponding-object">Step 2: Create Corresponding Object</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage32.png" -style="width:5.16667in;height:2.13889in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>Once the designer made changes to the properties in Onshape and -saved those changes, a message is sent to our third-party -application. This message is in JSON format and contains minimal -information such as the Workspace ID, the Document ID, the Element -ID, the Part ID (if it’s a Part) and information regarding the event -that was triggered. The third-party application receives this -information to an endpoint that was defined during the setup of the -web hook.</p> -</li> -<li> -<p>The code in our application can now use the ID’s sent over to check -if an object with corresponding IDs exists in our system. Here we -are assuming that no such object exists. This does mean that we must -store Onshape IDs into our objects in the third-party system.</p> -</li> -<li> -<p>We then create a new object and populate the ID information and save -it to the database. Note that at this point in time, we only have -minimal information that provides no more than the identity of the -Onshape Part.</p> -</li> -<li> -<p>Next, in order to get the complete metadata, we must make a REST API -call to Onshape in order to get the metadata for the part. Since we -were provided the ID information in the web hook, we have enough -information to go back to Onshape and request the metadata for a -specific, document, element, workspace and part.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that you can either -store the Onshape IDs in separate fields in your database or as one long -unique string which can be used to easily identify the part in your -application.</p> -<h3 id="step-3-get-onshape-metadata">Step 3: Get Onshape Metadata</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage33.png" -style="width:5.75in;height:2.04167in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>The response from the call to the Onshape API is sent back as JSON. -The data will contain a lot of different objects that represent the -property values, their types, the IDs, name of the property, value -of the property, etc.</p> -</li> -<li> -<p>Once received this data must be parsed by your third-party -application code and the corresponding object updated as required. -For bi-directional update, it is important to store the Onshape -property IDs of any data that will need to be synced back to Onshape -from the third-party application.</p> -</li> -<li> -<p>This is an optional stage. Once you have all the metadata values -imported, you could now calculate any values that are based off the -metadata. The most common use case scenario is the generation of -intelligent part numbers. Based off configuration, part type, etc., -you could generate a part number that has specific meaning within -the context of the company.</p> -</li> -<li> -<p>If you calculated specific values, you can now store them in your -database.</p> -</li> -</ol> -<h3 id="step-4-modify-properties-in-onshape">Step 4: Modify Properties in Onshape</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage34.png" -style="width:5.04167in;height:3.97222in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>As in Step 1 the designer updates the properties in Onshape – this -is obviously something that can happen multiple times</p> -</li> -<li> -<p>The web hook is triggered when the designer saves the property -changes</p> -</li> -<li> -<p>Our third-party application is listening for property changes</p> -</li> -<li> -<p>The third-party application’s code will check if the corresponding -object exists based off the IDs sent from Onshape.</p> -</li> -<li> -<p>In this scenario the corresponding object has already been saved in -our system</p> -</li> -<li> -<p>We make a REST API call to Onshape to get the metadata based off the -IDs sent from Onshape.</p> -</li> -<li> -<p>Onshape returns the JSON that represents the updated properties</p> -</li> -<li> -<p>We ingest the updated metadata and update our existing object in the -third-party system.</p> -</li> -</ol> -<h3 id="step-5-request-part-number">Step 5: Request Part Number</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage35.png" -style="width:5.76389in;height:2.13889in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>As we will see later, Onshape has the built in capability to pull -custom part numbers from a third-party system. From either the -properties window or the release candidate window, click the button -to request a part number</p> -</li> -<li> -<p>Onshape sends basic ID information to a predefined endpoint in our -third-party app.</p> -</li> -<li> -<p>The ID information sent by Onshape is enough data to find the -corresponding object in our database. We then extract from that -object the pre-calculated intelligent part number – or we can -calculate it at this point.</p> -</li> -<li> -<p>The part number is returned to Onshape and populated in the Part -Number field</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that in order to pull a -part number from a third-party application we will need to implement -OAuth2 in our application and grant Onshape access to the resources of -our application. Onshape has a very good mechanism for achieving this -and we will be explaining this in detail in this section.</p> -<p>Note that by default Onshape uses its own internal Part number -generator, in order to use a custom third-party generator, we will need -to define an app extension and then define in the Enterprise release -settings to use our custom part number generator.</p> -<h3 id="step-6-push-updates-from-third-party-application">Step 6: Push Updates from Third-Party Application</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage36.png" -style="width:5.75in;height:2.45833in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>In this scenario we are updating an Object in our third-party -application and expecting that some of the property values will be -updated in Onshape. We can either send over all the properties -populated for this object, or a subset of properties and values</p> -</li> -<li> -<p>The REST API to update properties in Onshape requires that we -reference the IDs of the properties that we are updating. For this -reason we have stored the Onshape property IDs with our metadata -object in our database.</p> -</li> -<li> -<p>We construct the correct JSON that contains all the properties to -update and the new values. We can then call the Onshape REST API to -update the properties in Onshape with the new data.</p> -</li> -<li> -<p>Once successfully completed, the Onshape REST API call will return -HTTP 200 and we can notify the user if needed.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that updates to Onshape -will happen behind the scenes in real-time, therefore someone working on -the document in Onshape will be able to see the updates as soon as they -have been made. There is no notification in Onshape that notifies the -user that properties have been updated, however you can open the -properties window and view the updated data.</p> -<h2 id="implementation">Implementation</h2> -<p>We’ll start by defining an <a href="https://onshape-public.github.io/docs/app-dev/extensions">App Extension</a> in Onshape so that we can -receive custom part numbers.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" /></p> -<h3 id="debug">Debug</h3> -<p>All Browsers now have developer tools exposed in their interface. These -tools provide us ways to debug client code, view console messages and -most importantly for our use case, view Network requests and their -response.</p> -<p>In this example I am using Chrome’s developer tools. Most other Browsers -have more or less copied Chrome’s layout for the developer tools so it -should be easy to find the network section.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage39.png" -style="width:5.36972in;height:4.16096in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977895" class="anchor"></span>Figure 24 Accessing -Chrome&rsquo;s Developer Tools</p> -<p>Let’s take the simple use case of trying to understand which endpoint -Onshape uses for saving Metadata.</p> -<p>Open a document in Onshape and define some properties – don’t save yet.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage40.png" -style="width:3.42406in;height:2.25966in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p>Prior to saving open the developer tools and click on the “Network” tab.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage41.png" style="width:6.5in;height:2.37014in" -alt="Table Description automatically generated" /></p> -<p><span id="_Toc102977896" class="anchor"></span>Figure 25 Developer Tools -Network Tab</p> -<p>Next save the updated properties by clicking either the Apply Button or -the Save Button</p> -<p>In the Network tab you will see a new web request – select it:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage42.png" -style="width:5.40656in;height:2.82458in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977897" class="anchor"></span>Figure 26 Network Request -Sample</p> -<p>What we are seeing here is the response from the call to Save the -properties. We can expand this response to view the complete JSON.</p> -<p>By clicking on the Headers we can view the actual request:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage43.png" -style="width:5.125in;height:2.47222in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977898" class="anchor"></span>Figure 27 HTTP POST -Request for Saving Properties</p> -<p>Here we can see that this will correspond to the APIs listed in the API Explorer.</p> -<p>Most importantly the “Payload” tab is our definition of the body of the -request. This is provided in JSON format and can be expanded. As shown -here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage44.png" -style="width:4.90769in;height:2.94205in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977899" class="anchor"></span>Figure 28 HTTP POST Body</p> -<p>We now have the correct API call and the format of the body to -successfully make the API call. We can also see from the body that if we -wish to update properties in Onshape from our third-party application, -we need to store the propertyID value.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />It is important to mention – -ALWAYS use cad.onshape.com to make API calls (no matter what you see in -the Headers tab or is shown in the Payload tab.</p> -<h3 id="define-an-application-extension">Define an Application Extension</h3> -<p>An application extension is how Onshape embeds third-party application -features in its UI. There are two types of extension:</p> -<ol> -<li> -<p>An extension that embeds its UI from the application into the -Onshape UI in an iFrame. Such a application my call Onshape REST -APIs or just expose an application interface inside Onshape.</p> -</li> -<li> -<p>An extension that embeds and that calls a REST API exposed by the -application from the Onshape UI. For instance, embedding application -functionality in the context menus or toolbars. This type of -application extension relies on external OAuth information in order -to authenticate the call. In this case Onshape acts as the client -and the application as the server.</p> -</li> -</ol> -<p>Each extension will exist at a specific location in the Onshape UI and -will work within the context of that location or a specific selection, -passing the relative information to the application.</p> -<p>In order to define the Application Extension we return to the -development portal at <a href="https://dev-portal.onshape.com/oauthApps">https://dev-portal.onshape.com/oauthApps</a> where -we initially defined our OAuth Application.</p> -<p>Select the OAuth Application that you previously defined and click on -the Extensions tab.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage91.png" style="width:6.5in;height:3.37917in" -alt="Graphical user interface, text, application, Teams Description automatically generated" /></p> -<p><span id="_Toc102977900" class="anchor"></span>Figure 29 - Oauth -Applications - Extensions</p> -<p>Start by clicking the Add Extension button.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that you can create as -many extensions as you need for your application within the Onshape UI.</p> -<p>This is the interface where you define where in the Onshape UI the -command will appear, and what endpoint in your application the command -will reference. Changing the Location dropdown will provide additional -fields that can be defined to specify context and other relevant fields.</p> -<p>For our use case, Define a name, i.e. “Custom Part Number Generator”, -define a description of the extension and select “Part Number Generator” -from the Location dropdown. The only other field that you need to define -is the Action URL. This is the endpoint in your application where you -will fetch the part number from.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage46.png" style="width:4.125in;height:4.125in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977901" class="anchor"></span>Figure 30 - Define -Application Extension</p> -<p>Once you save the definition you will see it in the list of extensions. -You can always come back and edit the definition of the extension.</p> -<h3 id="grant-onshape-access-to-3suprdsup-party-data">Grant Onshape Access to 3<sup>rd</sup> Party Data</h3> -<p>If you require Onshape to access the resources of your application, then -you will need to define the external OAuth parameters. In our use case -we will need Onshape to access data in our application in order to pull -the part numbers into Onshape.</p> -<p>Click on the External OAuth tab, the final tab on the OAuth Applications -page.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage47.png" style="width:6.5in;height:3.27361in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977902" class="anchor"></span>Figure 31 - Define -External OAuth</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />In this guide we’re not -detailing the implementation of OAuth2 inside your application, this is -explained very well in many on-line guides. My favorite of these can be -found at: -<a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2">https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2</a></p> -<p>Onshape provides the fields that are required for it to make a secure -request to your application, receive an access Token and refresh it when -required. In this case Onshape acts as the client and your application -as the server – this is the inverse to what we defined when we enabled -the third-party application to access Onshape.</p> -<p>Once you have defined the fields, Save/Update the definitions. We have -now completed defining the application extension and enabling Onshape to -access your applications resources.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note if you haven’t defined -all the endpoints at this time, you can come back later and update the -information once you have it defined in your application.</p> -<p>The last thing we need to do is for the user to grant access for Onshape -to access your applications resources. We can do this through the same -interface that we used to grant access to Onshape.</p> -<p>From inside Onshape go to your account settings, from the top right -dropdown menu. Click on the applications page.</p> -<p>For applications that have an application extension and External OAuth -defined we have the “Grant” button available in the “external Access” -column as shown here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage48.png" style="width:6.5in;height:2.87083in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977903" class="anchor"></span>Figure 32 - Grant -External Access</p> -<p>Click the “Grant” Button in the External Access column.</p> -<p>Your third-party application will present the user with option to -authorize access to the application – similar to this simple interface:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage49.png" -style="width:4.25285in;height:1.71051in" -alt="Graphical user interface, text Description automatically generated" /></p> -<p><span id="_Toc102977904" class="anchor"></span>Figure 33 - Enabling -Onshape to access a 3rd parties data</p> -<p>If you click “Allow”, you will be returned to Onshapes Applications page -and external access will be granted.</p> -<h3 id="defining-webhooks">Defining Webhooks</h3> -<p>Now that we’ve defined our application extension and OAuth access to our -application, we can start on receiving notifications in our application -when events happen in Onshape.</p> -<p>Onshape supports webhook notification for many different types of -events. We will register an endpoint in our application that will -receive a notification whenever something occurs in Onshape. In our -specific scenario this will be when the user updates the Onshape -properties – as we defined in <strong>Step 1 Define Properties in Onshape</strong>:</p> -<p>For our purposes we will be registering to receive web hook -notifications for the onshape.model.lifecycle.metadata event. When -registering for an event in Onshape there are only two pieces of -information required:</p> -<ol> -<li> -<p>The event (onshape.model.lifecycle.metadata)</p> -</li> -<li> -<p>The Enterprise ID</p> -</li> -</ol> -<p>To easily find your enterprise ID, in Onshape select the Enterprise -Settings option from the top right dropdown menu and then click on the -“Details” menu option on the left-hand menu bar.</p> -<p>You will see your Enterprise ID and a “Copy to Clipboard” button next to -it. This will enable you to directly copy this unique ID into your code.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage50.png" -style="width:3.0006in;height:2.70759in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977905" class="anchor"></span>Figure 34 - Finding Your -Enterprise ID</p> -<p>The following code shows how we can register a webhook in Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage51.emf" alt="">In this example I’ve hard-coded a few of -the values for clarity, however this method could be re-written to be a -generic model for registering various webhooks. Some good examples of -registering for webhooks exist at <a href="https://github.com/onshape-public">https://github.com/onshape-public</a>.</p> -<p>As with other calls to Onshape that we’ve seen, we are passing the -accessToken in the header in order to establish a secure call to -Onshape’s resources.</p> -<p>The information coming back from the registration call will be similar -to the following:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2014-12-16T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.register&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;544e91f7fb88ed44f5de1508&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;34795d2e5f5f44eeb61fb7b1&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>In our example we are saving the event -(onshape.model.lifecycle.metadata) and the returned webhookId to a -database in order that we can later ping it to make sure that it is -live.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Following the registration of -the webhook, Onshape will attempt to make a call to the Notify URL -defined in the body of the registration request. This is the endpoint of -your application that should be called when the event is fired in -Onshape. The most common reason for registration failures is that the -endpoint you defined, does not return an HTTP 200 status code. -Therefore, even if you registered for an event and received a -registration notification and a webhookId back from Onshape, your web -hook is not in fact registered until Onshape validates the notify URL -and receives the HTTP 200 notification back from it. Unfortunately there -is no way to easily know if your web hook has been successfully -registered until you either ping it, request to list it, or try to -activate the event through Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Also it is important to know -that even when your webhook is registered successfully, if you change -your code later on and Onshape fails to receive an HTTP 200 status code -back from the notify URL, the web hook will be removed.</p> -<p>One of the ways we can validate that a webhook is “live” is by pinging -it using the Onshape REST API. The following code shows the -implementation of a ping to the webhook. If an HTTP status code of 200 -is returned, we know that the webhook is enabled, if not then we can -re-register the webhook as needed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" /><img src="https://onshape-public.github.io/images/integrationguideimage52.emf" alt="">Once -we store the webhook ID in the database we can ping the webhook whenever -the application is loaded and validate that it’s still registered. If we -need to re-register the webhook (usually only occurs when changes are -made to the code in the notify URL), we can create a new webhook -registration and update the database record.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that you can create many -duplicate webhook registrations for the same event with the exact same -notify URL. Onshape doesn’t limit how many registrations are created for -a single webhook. In the event that this happens, the notify URL will be -called as many times as there are webhooks registered for that event. -You can validate the registered webhooks by calling the -<a href="https://cad.onshape.com/glassworks/explorer/#/Webhook">Webhook API</a>.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Use -<a href="https://cad.onshape.com/glassworks">https://cad.onshape.com/glassworks</a> to call APIs and validate the -requirements for each REST API call. This interface lists all the -available Onshape REST APIs and provides examples of the values returned -from each call.</p> -<h3 id="receiving-webhook-notifications">Receiving Webhook Notifications</h3> -<p>Once your webhook is registered and confirmed to be working you should -be getting a notification from the webhook to your notify URL. The -notification should be similar to the following:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2014-12-16T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.document.lifecycle.metadata&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;544e91f7fb88ed44f5de1508&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;60f54ac1cbc04179a6642d9a&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;0f9c4392e5934f30b48ab645&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentState&#34;</span>: <span style="color:#a50">&#34;IN PROGRESS&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>In your case the workspaceId, elementID, documentID, and PartId should -be populated with the values from the Onshape document that was open -when the properties were updated.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />It is important to note that -there is currently no OAuth validation on the webhook response, -therefore the endpoint in your application will not receive any access -token data for directly calling Onshape APIs. Therefore, if you need to -make a call to the Onshape REST APIs inside the notify URL endpoint make -a call to an endpoint in your application and include your application -OAuth credentials in the body of the request. In this way, you can make -a call to your application and load the passport and the Onshape -credentials.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Onshape takes security very -seriously and for this reason, unauthenticated calls only provide -minimal details such aa, in this case, id’s.</p> -<h3 id="getting-onshape-properties">Getting Onshape Properties</h3> -<p>In our specific use case, when we received the webhook notification, we -want to use the ID data provided to find the corresponding object in our -database (or create a new one) as shown in Step 2 Create Corresponding -Object: Then we make a call to the Onshape REST API: -/metadata/d/{did}/{wvm}/{wvmid}/e/{eid}/{iden}/{pid}</p> -<p>All the relevant data is provided in the response from the webhook so we -can pass this to the method which will call this API as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage53.emf" alt="">From this call I am returning the -“properties” part of the JSON – this contains all the metadata -definitions that I wish to store in my database and associate with the -corresponding object. The following is an example of one of the property -objects:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage54.emf" alt=""></p> -<p>In fact there is probably only three key pairs that we’re interested in -here:</p> -<ol> -<li> -<p>Name – name of the property. In this case “Name”</p> -</li> -<li> -<p>Value – the value of the property. In this case “Top Plate”</p> -</li> -<li> -<p>propertyId – the ID of this property. We might need this if we want -to enable a bi-directional sync between both applications.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that for valueType -CATEGORY the actual name, value and id will be embedded deeper in the -object inside an array. I suggest copying and pasting the output from -the API call into a JSON viewer such as <a href="http://jsonviewer.stack.hu/">http://jsonviewer.stack.hu/</a> so -that it will be easier to find where the correct values are.</p> -<p>We can now update our corresponding object with the Onshape metadata -values as described in Step 3 Get Onshape Metadata:</p> -<h3 id="updating-onshape">Updating Onshape</h3> -<p>So far we have pulled data from Onshape and populated it into our -third-party application, however what if we make updates in our -application that we want to propagate back to Onshape? This is certainly -possible through Onshape’s REST API. Usually this would be implemented -in your application on the click of a button – such as “Save”, if you -have multiple properties to update, or when a property is updated if you -want to trigger the sync for the update of a specific field.</p> -<p>Either way it is fairly straight forward to send the REST API call to -Onshape to update properties. The following snippet of code shows how -the call can be made:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage55.emf" alt="">As we can see here, we provide the body in -the form of JSON that includes an array of items (in this case one item) -and a nested array of properties (two property objects are listed here). -Each property has a value and an ID of the property in Onshape to -update.</p> -<p>The response from this API call should be an HTTP 200 status. If this is -the case, we can update the user that the sync was successful.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />If you know that you want to -update Onshape with property values from your application, it will be -important to build a data model that can store the properties with the -unique ID provided by Onshape.</p> -<h3 id="implementing-custom-part-numbers">Implementing Custom Part Numbers</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage56.png" -style="width:2.95556in;height:2.94924in" /></p> -<p>The final step in this -business case is to pull the part numbers form our third-party -application. The part numbers can be calculated based on metadata values -that were previously synced from Onshape or they might be numbers being -pulled from yet another system – such as an ERP or even a Google -Spreadsheet. The important thing is that when the user clicks a button -in Onshape, the correct Part Numbers get populated.</p> -<p>To first understand how the setup for pulling part numbers from a -third-party application we need to go back to the definition of our -Application Extension in the Onshape developer’s portal.</p> -<p>Here we can see that we gave the application extension a name, defined -the location as “Part Number Generator” and defined the “Action URL” – -this is the endpoint in our application where we will fetch the part -number from.</p> -<p>Once we have the application extension defined as Location = Part Number -Generator, you will be able to use this option inside Onshape Release -Management settings.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that in order to use the -Part Number Generator option you will have to define the External OAuth -option and grant Onshape access to the resources of your application. -This is because Onshape will need to access the defined endpoint in -order to pull the part number from the application</p> -<p>From within Onshape Select the “Enterprise Settings” from the top right -dropdown menu. Navigate to the “Release Management” settings and scroll -down to the “Revisions and part numbers” section of the page.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage57.png" -style="width:4.05994in;height:3.27831in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977907" class="anchor"></span>Figure 36 - Revisions and -Part Number Settings</p> -<p>In the Part Number Generation dropdown select the “Custom Part Number -Generator”. Note that this is the name that you defined in your -Application Extension so it might differ from what’s shown here.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage58.png" -style="width:2.73732in;height:2.03131in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977908" class="anchor"></span>Figure 37 - Selecting -Custom Part Number Generator</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Finally scroll to the bottom -of the page and save the settings.</p> -<p>Note that you will need the Admin role in order to access the enterprise -settings.</p> -<h3 id="implementing-part-number-code">Implementing Part Number Code</h3> -<p>Onshape will send a message to the endpoint defined in your application -extension settings. The content of this message will be an array of the -following data.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage59.emf" alt="">There might be one or more object depending -upon where the user initiated the call for part numbers from. For -instance, if the call was initiated from the Part properties window, -there will only be one object, however if initiated from the release -candidate window, multiple parts/assemblies and drawings might be -requested in the single call. Therefore, your code should be able to -handle these two situations.</p> -<p>Onshape will expect a response back from your endpoint and it should be -formatted in the following manner:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage60.emf" alt="">Note that in fact only the id and -partNumber fields are actually required – the other fields are optional.</p> -<p>The following is an implementation of the getNextPartNumber endpoint -that was defined in the application extension “Action URL” field:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage61.emf" alt="">This in turn calls a function that pulls -the next part number from the corresponding object in the database (this -was defined in, Step 5: Request Part Number). In this function I’m -defining the object that will be sent to Onshape with the part number. -This will be called multiple times depending how many objects were sent -from Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage62.emf" alt="">In this case I’m sending back all the data -required by Onshape, however it would be enough to just populate the id -and the partNumber.</p> -<p>Once you load the Part Properties window or the Release candidate -window, you can now request the Next Part number. The part number will -be pulled from the third-party application and populated in the relevant -fields as shown below.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage63.png" -style="width:4.59649in;height:3.80143in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977909" class="anchor"></span>Figure 38 - Release -Candidate Part Number generation</p>Docs: Sync Releases and Revisionshttps://onshape-public.github.io/docs/tutorials/releases/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/releases/ -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/sync">Sync Data and Metadata</a> tutorial. Please complete that one before starting on this one.</p> -<p>In this case, we’ll be looking at the ability for Onshape to sync its -release data with an external system and for that system to send -information back to Onshape with regards to released data.</p> -<p>This specific business case will look at what happens when you wish for -a PLM system to control the release of data instead of Onshape having -that control – this is in fact a common use case.</p> -<h2 id="overview">Overview</h2> -<p><img src="https://onshape-public.github.io/images/integrationguideimage64.png" -style="width:3.21077in;height:2.56522in" /></p> -<p>We have mentioned before that -Onshape has the ability to release data – it is totally integrated to -Onshape since there is no division between CAD capabilities and PDM -capabilities in Onshape – they are all part of the same solution. See -Versions and Releases for more information on how Onshape manages -releases. There is importance in releasing data through Onshape. Onshape -uses visual cues to show which parts are released in an assembly for -instance and which parts might have a newer revision. Onshape can also -add/remove watermarks to drawings and update the title block depending -on release states. Also, the BOM table can pull a parts release data and -display it. All this is dependent upon a release process being completed -in Onshape.</p> -<p>Many organizations have implemented Product Lifecycle management systems -(PLM). One of the key benefits of a PLM system is that it manages more -than just engineering data originating from the engineering department, -it deals with all the data related to the product – from concept through -retirement. Therefore, it is a system that is used by many groups and -departments throughout the organization.</p> -<p>Often, in release processes or Engineering Change processes, additional -input and approvals are required from various departments downstream -from engineering. PLM systems are very good at routing the data for -approval to users from multiple departments and groups throughout the -organization. Onshape, on the other hand, is very focused on the -engineering department and the data generated there. While it certainly -has the capabilities to bring other groups into approval processes, it -is not considered a process centric enterprise-wide system with the -capabilities of a PLM system.</p> -<p>Many companies will have well established processes that have been -modeled in their PLM system, it is much easier for us to integrate into -those processes than reinvent the wheel in Onshape.</p> -<p>This section looks at how we might have the best of both worlds, -initiate release processes in Onshape and update our Onshape visual cues -as well as have the PLM system manage the actual approvals and release.</p> -<p>This section uses concepts such as OAuth and web hooks that we have -introduced in detail in previous sections, therefore feel free to -reference those sections for more information on these topics.</p> -<h3 id="step-1-initiate-release">Step 1: Initiate Release</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage65.png" -style="width:4.88889in;height:2.02778in" -alt="Application Description automatically generated" /></p> -<p>In this first step we are using Onshape’s out-of-the-box capabilities to -initiate a release candidate – just as we would if we were releasing -natively in Onshape.</p> -<ol> -<li> -<p>We start by initiating the release on all the data that is required. -In this step you should use a custom workflow that simply has one -approval node.</p> -</li> -<li> -<p>Define the mandatory and any other release properties in the release -candidate window. <img src="https://onshape-public.github.io/images/integrationguideimage66.png" -style="width:4.70609in;height:3.12281in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -</li> -</ol> -<p><span id="_Toc102977911" class="anchor"></span>Figure 40 - Initiating a -release candidate</p> -<ol start="3"> -<li> -<p>Since an approver is required, we must provide a fictious -user/approver that has been defined in the system – this could be -named “Release Approver” for instance. The process will be sent to -this approver even though they are not a real person and will not be -able to approve the release. Instead, our release process will be -approved by an external source.</p> -</li> -<li> -<p>Finally, when everything is defined, submit the release. The window -will close. Since the release is pending approval, the parts -involved in the release will enter the state of “Pending” as shown -here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage67.png" -style="width:4.40131in;height:2.9375in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -</li> -</ol> -<p><span id="_Toc102977912" class="anchor"></span>Figure 41 - Pending -Release</p> -<p>They will remain in this state until the release has been completed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage68.png" -style="width:2.71208in;height:1.52174in" /></p> -<p>It is important to note that -unlike traditional PDM systems where the files are locked for change -until the release is completed or rejected, Onshape does not lock the -files. As mentioned previously, Onshape views the releases as a point in -time. As far as Onshape is concerned, time moves forward, parts can -change and at a specific point in time, the parts are in a state of -pending. It is important to mention that this does in fact prevent -another release from being initiated on the parts until the previous -release has been completed.</p> -<h3 id="step-2-initiate-release-process-in-3suprdsup-party-app">Step 2: Initiate Release Process in 3<sup>rd</sup> Party App</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage69.png" -style="width:5.34722in;height:3.34722in" -alt="Diagram Description automatically generated" /></p> -<p>Once the user initiates the release candidate and the parts transition -to the “pending” state we can register for a webhook that will notify -our third-party application that the parts have changed state.</p> -<ol> -<li> -<p>Once the parts enter the workflow, the onshape.workflow.transition -webhook will be triggered.</p> -</li> -<li> -<p>Our third-party application should be listening for this event along -with other data, we are provided with the objectId of the release -package – this is all the data associated with the parts that are to -be released. The response also contains the objectType and the -transitionName; for our use case we will only concern ourselves with -requests that have an objectType of “Release” and a transitionName -of “Submit”.</p> -</li> -<li> -<p>Using the ObjectId we make an API call to onshape; -/api/releasepackages/&lt;releasePackageId&gt;?detailed=true</p> -</li> -<li> -<p>This API call will return to us a JSON response containing all -assemblies and parts in the release package. The following -information should be extracted from the release package:</p> -<ol> -<li> -<p>For each line item (assembly or part) extract the documentId, -the elementId, elementType, versionId and PartId</p> -</li> -<li> -<p>Iterate through the top level properties and record the -propertyId for property with the name “comment” – this will be -used to update the release comments later on.</p> -</li> -</ol> -</li> -<li> -<p>Now that we have the relevant IDs we can update the state of our -corresponding objects in the third party system and record any -additional data such as the release comment field.</p> -</li> -<li> -<p>Finally, we can kick off our official release process in the -third-party application. This could be an automated process or a -manual one.</p> -</li> -</ol> -<h3 id="step-3-complete-release-process">Step 3: Complete Release Process</h3> -<p>The release process continues in the third-party application until -approvals have been received by all required actors. Meanwhile in -Onshape the parts are in the pending state. In this step we close the -loop once the release process is completed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage70.png" -style="width:5.375in;height:3.34722in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<ol> -<li> -<p>The release process managed by the third-party application is -completed and the data in that system is released.</p> -</li> -<li> -<p>Once this happens, we make a call to the Onshape API; -/api/releasepackages/&lt;releasePackageId&gt; the releasePackageId is -the ID we were provided with at the start of this process – While -there are different ways of implementing this, I tend to store the -ID and any other data related to the release in a custom “release -Object” in my database so I can retrieve and update the release as -required. In addition to the passing the release package ID, in the -body of the request we should pass the id of the release comment and -a value for the comment. This will update the release in Onshape -with any relevant data.</p> -</li> -<li> -<p>Onshape releases the data that was included in the release candidate -and that completes the workflow process.</p> -</li> -<li> -<p>Onshape will return a status code that indicates success or failure</p> -</li> -<li> -<p>Finally we can optionally update the corresponding object to -indicate that it is in sync with the Onshape data.</p> -</li> -</ol> -<p>In the event that the release process is rejected at anytime, we can -send the releasePackages API request to Onshape with a REJECT workflow -Action argument. This will cause Onshape to reject the workflow and the -state of the parts at the specific release point in time, will be set to -“Rejected”.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage71.png" -style="width:4.69737in;height:3.12807in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977914" class="anchor"></span>Figure 43 - release -candidate rejected</p> -<p>Since our timeline is moving forward this has no actual effect on the -parts other than to cancel the pending release and enable them to be -released at another future point in time.</p> -<h2 id="implementation">Implementation</h2> -<p>In this section we will take a closer look at how to implement the -release scenario in our code. The first thing we need to do is define -the correct web hook to listen for the initiation of the release – this -means that once the user clicks the submit button on the release -candidate dialog, this web hook will be triggered.</p> -<h3 id="set-up-webhook">Set Up Webhook</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage72.emf" alt=""></p> -<p>This code is very similar to what we defined previously for the metadata -update, instead here we are defining a hook for the -onshape.workflow.transition hook. As with other code examples that -require authentication, we have included error handling in order to -refresh that access token in the event that it has expired.</p> -<p>The onshape.workflow.transition will in fact fire whenever a revision or -release package transitions through different workflow states. In his -specific case we are only interested in catching the event when the -workflow is initially submitted. This can be filtered by the information -sent to the return URL, in this case -<a href="https://myserver.com/api/getReleaseData">https://myserver.com/api/getReleaseData</a></p> -<p>In this implementation we are storing he webhook ID in the database so -that we can ping it when the application is loaded to make sure that it -is still active. Other implementations delete the webhook after it is -used and then recreate it as required. There is no specific preference -for which methodology is better – that depend s upon the requirements of -your integration.</p> -<h3 id="receive-web-hook-notifications">Receive Web Hook Notifications</h3> -<p>Once the user who is initiating the release clicks the Submit button on -the Release Candidate dialog, the webhook will be triggered and a -message will be sent to the third-party application listening for that -webhook.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage66.png" -style="width:4.70609in;height:3.12281in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p>In our example the URL that the webhook data from Onshape gets sent to -is:</p> -<p><a href="https://myserver.com/api/getReleaseData">https://myserver.com/api/getReleaseData</a></p> -<p>In our application we can define a router for that end point as follows:</p> -<p>router.route(&rsquo;/getReleaseData&rsquo;).post(mymodule.getReleaseData);</p> -<p>In this case “mymodule” is where I’ve defined all the functionality for -managing data coming from Onshape. Since the webhook data contains no -authentication information (just minimal data is sent from the webhoom -for security reasons), we can’t directly authenticate our application -against Onshape, therefore we need to pass the data received from the -webhook through a method that will then add the authentication data to -our request object. The getReleaseData method simply passes the webhook -information received by the application to another authenticated -endpoint as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage73.emf" alt=""></p> -<p>Here is the endpoint defined for processReleasePackage:</p> -<p>router.route(&rsquo;/processReleasePackage&rsquo;).post(authController.isAuthenticated, -releaseController.processReleasePackage);</p> -<p>As we can see here, we have now added in the authentication middleware - -authController.isAuthenticated - and can make secure calls to Onsahpe’s -API.</p> -<h3 id="get-release-package-data">Get Release Package Data</h3> -<p>The parameter that the web hook sent over to our application that we -need to make use of is the ID of the release package. We can now make a -call to Onshape to retrieve the complete release package with the ID.</p> -<p>We get the release package ID from the request object and make the REST -API call to get the package as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage74.emf" alt=""></p> -<p>The complete release package should be returned in “response”. We can -now parse that data to retrieve the properties we need. The most -important properties will the IDs of the parts that we are going to -release – these should already be synced with our system – if not, we -can create them from the data in the release package.</p> -<h3 id="save-release-package-data">Save Release Package Data</h3> -<p>The next step is to save the properties of the release package to a -corresponding object in our database. We need at least the ID of the -release package so we can later release it automatically from the -third-party application. In this case I’m storing other properties that -came from the release candidate such as release name and description.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage75.emf" alt=""></p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage76.png" -style="width:3.01875in;height:4.38889in" /></p> -<p>Most of this code deals with -retrieving values from the release package and storing them as a new -release object in the database. Additional values are associated with -the part in the PLM system. In a typical production scenario this code -would interface with the PLMs workflow capabilities and possibly kick -off a release or change process in that system. For our basic example we -are storing values from Onshape with our items and setting a state on -the part so that users can see that the part is pending release and take -actions required.</p> -<p>At this point in time, Onshape does not care that the part is pending a -release. The part in Onshape will remain in a pending state until it is -released by the PLM system. As noted previously, we used a user setup in -the system to specifically initiate the release, therefore no other -users will receive notifications from Onshape with regards to release -actions on this part.</p> -<h3 id="complete-the-release">Complete the Release</h3> -<p>Once the release or change workflow has completed in the PLM system and -all approvals have been received, the Part/Item will be in a released -state in the PLM system. However, we must now update Onshape with the -correct release status of the parts. It is important that Onshape data -is in sync with the corresponding data in the PLM system for reasons of -data integrity and the visual cues used within Onshape to identify a -part as released.</p> -<p>In a typical scenario Onshape will be automatically updated once the -workflow completes in the PLM system. In our use case we are simplifying -the process by clicking a button to release the item. This will update -the state of the part in our system and send a REST API call to Onshape -to release the data in the release package (be it one part, an assembly -with multiple parts, or drawings).</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage77.emf" alt=""></p> -<p>This code snippet updates the database with the released status of a -part. Since we stored data from the release package in our database we -now retrieve the “Comment” property so that we can send an updated value -to Onshape with the release.</p> -<p>let attrid = rp.props.find(ob =&gt; ob.name == &ldquo;Comment&rdquo;);</p> -<p>The important line of code here is the REST API call to Onshape:</p> -<p><strong>axios.post(&lsquo;<a href="https://cad.onshape.com/api/releasepackages/'">https://cad.onshape.com/api/releasepackages/'</a> + id + -&lsquo;?wfaction=RELEASE&rsquo;</strong></p> -<p>The id provided here is the ID of the release package that we stored -when the web hook was called at the beginning of the process. The -“wfaction” argument indicates that the workflow action in Onshape should -be to release the data associated with this release package.</p> -<p>In this example we are also updating the release comments in Onshape, -for this reason we required the property ID of the Comment field – which -we also previously stored in our release object in the database.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage78.png" style="width:6.5in;height:4.25903in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977916" class="anchor"></span>Figure 45 - Release -completed automatically in Onshape</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage79.png" style="width:6.5in;height:4.25625in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977917" class="anchor"></span>Figure 46 - Release -comments Updated from third-party system</p>Docs: Generate Derivative Fileshttps://onshape-public.github.io/docs/tutorials/derivative/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/derivative/ -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/releases">Sync Releases and Revisions</a> tutorial. Please complete that one before starting on this one.</p> -<p>It’s clear by now that Onshape doesn’t use files to store its data, -instead it is a data driven solution that is always up to date. Files -are a snapshot in time that provide a view of the design at a specific -point in time - such as at a release or version. A new file is required -for each “snapshot” and managing these files can get quite cumbersome. -However, there are situations that require that files be generated from -the Onshape data.</p> -<p>In general, we want files to be generated at defined points of time and -within the context of a business process – such as a release process. -The derived file could be a format such as a PDF of the drawing that is -generated following the successful release of the data. Also, a common -requirement is to generate STEP files or JT files that can be used in 3D -Printing or viewers embedded in PLM solutions. Regardless of the use -case Onshape has very good export capabilities for many different file -formats.</p> -<p>This business case examines how to automatically generate files derived -from the Onshape data. The process described here can be plugged into -many different use cases. In this specific example we are plugging the -translation use case into the Release Business case just after the -release is completed in the third-party application and Onshape is -updated. Since we already have all the relevant ID information for the -parts to translate from the release package data, we can directly call -the translation APIs after receiving notification that the release was -successfully executed in Onshape.</p> -<h2 id="overview">Overview</h2> -<p><img src="https://onshape-public.github.io/images/integrationguideimage80.png" -style="width:5.5in;height:4.79167in" /></p> -<ol> -<li> -<p>Once we have received an HTTP 200 status from the call to Onshape to -release the release Package, we can proceed with the translation. -The reason why we may want to wait till the release has successfully -completed could be for several reasons:</p> -<ol> -<li> -<p>We are generating a PDF of the drawing and want the “In -Progress” watermark removed, and the title block updated with -release information</p> -</li> -<li> -<p>We are generating files for 3D printing or for sending to a -vendor to manufacture and we only want to send released data</p> -</li> -</ol> -</li> -<li> -<p>We can now make an API call to Onshape. In both the following cases -we must pass the document Id, the version Id and element Id – all -values that were available in the release package. Other values are -dependent upon your specific use case and can be referenced in -<a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation</a></p> -<ol> -<li> -<p>For Assembly translation we can POST to :/api -/assemblies/d/{did}/{wv}/{wvid}/e/{eid}/translations.</p> -</li> -<li> -<p>For Parts we can POST to: -/api/partstudios/d/{did}/{wv}/{wvid}/e/{eid}/translations</p> -</li> -</ol> -</li> -<li> -<p>Three variables of importance are returned from the API call to -translate: requestState, id (of the translation) and -resultExternalDataIds. We should store or keep this data in memory -until the translation is completed. Depending upon the requestState -there might be additional data available in the response.</p> -</li> -<li> -<p>We can now periodically ping the translation web service with the id -retrieved in the last step. Using the GET call to -/api/translation/{id} we will receive one of three responses in the -requestState:</p> -<ol> -<li> -<p>DONE</p> -</li> -<li> -<p>ACTIVE</p> -</li> -<li> -<p>FAILED</p> -</li> -</ol> -</li> -<li> -<p>Depending on the response we can either continue to periodically -ping the translation service if we received ACTIVE</p> -</li> -<li> -<p>Notify the user of a failed translation attempt if we received a -FAILED response</p> -</li> -<li> -<p>Make a call to Onshape to GET the translated file if we received a -DONE response. To retrieve the translated file make a GET request to -/api/documents/d/{documentId}/externaldata/{externalDataId}</p> -</li> -<li> -<p>The file can now be stored in your third-party system or stored to -an external drive depending upon your specific use case.</p> -</li> -</ol> -<h2 id="implementation">Implementation</h2> -<p>As use cases go, this is a very straightforward process. The only -complexity here is deciding how to receive the notification from Onshape -that the translation has completed. There are several ways of -implementing this including using a webhook to notify us when the -translation completes. In the examples here I will show both the webhook -methodology as well as pinging Onshape with a status request every -couple of seconds. The status request can be initiated from the client -through an AJAX call or, as in the example I use here, from the server.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage81.png" -style="width:3.3395in;height:3.66667in" /> In our example I have added a -button to the interface of my third-party system that enables me to -request a translated file. In this use case I have hard coded that the -resulting file should be a STEP file – in a production ready -implementation, we would expect that one or more formats are available -and possibly selected by the user. In addition, a production ready -implementation might have automated the translation for whenever a part -is released. Other considerations for automation might include -identifying what is being released. I.e. if it’s a part then translate -to STEP, if it’s a Drawing then translate to PDF, etc. These are all -very common use cases.</p> -<h3 id="initiate-the-translation">Initiate the Translation</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage82.emf" alt="">The code snippet shown here is fairly -straightforward. First it gets the ID of the part that was sent from the -client, it then uses that ID to retrieve the part from the database. The -part stored in our database already has all the required values to -successfully communicate with Onshape, such as the document ID, the -workspace ID and the element ID – all these values are used in the -translation request.</p> -<p>In the body of the request we can see some of the required values that -define how the part is to be translated to STEP. In this case I have -only included the minimum required key pairs for this translation.</p> -<p>The REST API call to translate an Onshape element returns an object that -includes the translationId – this is the value that will be used to ping -Onshape and request the status of the translation.</p> -<h3 id="ping-onshape-for-translation">Ping Onshape for Translation</h3> -<p>In this code snippet I have simplified things by including a function -that waits for a second and then pings Onshape again, It will continue -pinging Onshape until it receives back a status that is not “ACTIVE”. -Once the status returned is anything except “ACTIVE” it returns the -resulting object back to the client.</p> -<p>The id used here is the translationId retrieved from the result object -when the translation was initiated.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage83.emf" alt=""></p> -<p>Once the requestState is changed, this will indicate that the -translation has completed either with a FAIL or a DONE status. Depending -on the result we can define our logic on the client appropriately.</p> -<p>The following shows the object returned to the client from the -translation REST API. Note that the requestState is now set to “DONE”,, -meaning that the translation has completed -successfully.<img src="https://onshape-public.github.io/images/integrationguideimage84.png" style="width:6.5in;height:3.17986in" -alt="A picture containing timeline Description automatically generated" /></p> -<p>With this data we can now request the file directly from Onshape. The ID -that we need to use to retrieve the file is the “resultExternalDataIds”. -Note that this is an array of values – since it makes sense that we -might be translating more than one part.</p> -<h3 id="retrieve-translated-file">Retrieve Translated File</h3> -<p>With the resultExternalDataIds we can now retrieve the translated file -from Onshape. The following code snippet does exactly this.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage85.emf" alt=""></p> -<p>The Onshape REST API</p> -<p><a href="https://cad.onshape.com/api/d/'">https://cad.onshape.com/api/d/'</a> + did + &lsquo;/externaldata/&rsquo; + id</p> -<p>retrieves the translated file – in this case the ID is -resultExternalDataIds[0] value.</p> -<p>Once this is completed, we use the response to save the file directly to -our server where the application is hosted. Finally, I’m sending a JSON -object to the client that provides a direct link to the file that is now -hosted on our server.</p> -<p>The client can then request the translated file from our server, even -though this is a function of the server and not related to Onshape, I -have included a code snippet here that will send the file to the client.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage86.emf" alt=""></p> -<p>In our sample implementation Once the translation has completed -successfully I display a link to the translated file that calls the -“getfile” endpoint shown above.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage87.png" style="width:6.5in;height:2.32917in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<p>Clicking the link will cause the file to be downloaded as shown here.</p> -<h3 id="define-translation-webhooks">Define Translation Webhooks</h3> -<p>As we mentioned at the beginning of this section there is more than one -way to receive notification back from Onshape that the translation has -completed. We can also define a webhook that will notify us once the -translation completes. The drawback with this methodology is that the -webhook must be created for each translation and then deleted.</p> -<p>A complete example of this can be found at: -<a href="https://github.com/onshape-public/app-gltf-viewer/blob/main/services/webhook-service.js">https://github.com/onshape-public/app-gltf-viewer/blob/main/services/webhook-service.js</a></p> -<p>The following function is used in this application to define the -webhook:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage88.emf" alt=""></p> -<p>The following line would call this function once the user requests to -initiate a translation.</p> -<p>WebhookService.registerWebhook(req.user.accessToken, -req.session.passport.user.id, did)</p> -<p>Finally the endpoint registered with the webhook could be defined as -follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage89.emf" alt=""></p> -<p>In this case once the translation is completed, this endpoint receives a -notification. If the event is equal to</p> -<p>onshape.model.translation.complete</p> -<p>We can assume that the translation has completed and we can unregister -the webhook and retrieve the translated file.</p> -<p>The complete sample including it setup and deployment can be found at: -<a href="https://github.com/onshape-public/app-gltf-viewer">https://github.com/onshape-public/app-gltf-viewer</a></p>Docs: Create an Extensionhttps://onshape-public.github.io/docs/tutorials/createextension/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/createextension/ -<p>In this example, you will create a custom web page (as shown in the image below) that is displayed in the -right-hand fly-out panel. This interface displays metadata pulled from -a third-party system when a part in Onshape is selected. This interface can also update metadata in Onshape through the <code>Update</code> functionality.</p> -<p>You can follow along with the steps below with this video: -<a href="https://onshape.wistia.com/medias/0ivxxngkjz?embedType=async&seo=false&videoFoam=true&videoWidth=640&wvideo=0ivxxngkjz)"><img src="https://onshape-public.github.io/images/ExtensionsVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></p> -<h3 id="define-the-extension">Define the extension</h3> -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/derivative">Generate Derivative Files</a> tutorial. Please complete that one before starting on this one.</p> -<ol> -<li> -<p>Navigate to the Developer portal from <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</p> -</li> -<li> -<p>Click <strong>OAuth applications</strong> in the left menu.</p> -</li> -<li> -<p>Select your application, and the click the <strong>Extensions</strong> tab. -<img src="https://onshape-public.github.io/images/integrationguideimage91.png" style="width:6.5in;height:3.48958in" alt="Graphical user interface, application, Teams Description automatically generated" /></p> -</li> -<li> -<p>Click the <strong>Add Extension</strong> button on the top right.</p> -</li> -<li> -<p>Select <code>Element Right Panel</code>. -<img src="https://onshape-public.github.io/images/integrationguideimage92.png" style="width:5.05785in;height:5.66469in" alt="Graphical user interface, application Description automatically generated" /></p> -</li> -<li> -<p>Next, define the context. The context defines what parameters -can be sent from Onshape to the application. Some basic -parameters are automatically sent with any context, additional information can be passed to our -application, depending on the context selected. Click the <code>Selected part</code> option. This sends the <code>partId</code> and <code>partNumber</code> to the application, along with the <code>documentId</code>, <code>elementId</code>, and the <code>workspaceOrVersionId</code>.</p> -</li> -<li> -<p>In the <code>Action URL</code> field, fill in the URL of the page to load in the right element panel. The parameters can be added as arguments (variable that get replaced with real values when the page is loaded from Onshape).</p> -<pre tabindex="0"><code>https://ourserver.com/bom?documentId=${documentid}&amp;elementId=${elementid}&amp;partId={$partId}&amp;partNumber={$partNumber} -</code></pre></li> -<li> -<p>Finally, select an icon for the extension. This will appear on the tab that opens the right element panel.</p> -</li> -</ol> -<p>You have now defined the extension, and it will appear in the Onshape -interface.</p> -<h3 id="call-a-page-in-the-extension">Call a page in the extension</h3> -<p>The following code snippet shows how to use your previous definition to -pull data from the third-party application and send it to the web page:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//https://myserver.com/bom?documentId=${documentId}&amp;elementId=${elementId}&amp; -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//partId=${partId}&amp;partNumber=${partNumber} -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/bom&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (req.query.partNumber !== <span style="color:#a50">&#39;${partNumber&#39;</span>}) { -</span></span><span style="display:flex;"><span> partController.getPartsList(req.query.partNumber).then((parts) =&gt; { -</span></span><span style="display:flex;"><span> catController.getCatById(parts.Category).then((cat) =&gt; { -</span></span><span style="display:flex;"><span> res.render(<span style="color:#a50">&#39;bomview&#39;</span>, { -</span></span><span style="display:flex;"><span> parts: parts, -</span></span><span style="display:flex;"><span> cat: cat -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> res.render(<span style="color:#a50">&#39;bomview&#39;</span>, { -</span></span><span style="display:flex;"><span> parts: { <span style="color:#a50">&#34;_id&#34;</span>: <span style="color:#099">0</span> }, -</span></span><span style="display:flex;"><span> cat: { <span style="color:#a50">&#34;_id&#34;</span>: <span style="color:#099">0</span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}) -</span></span></code></pre></div><p>This code checks to see if the <code>partNumber</code> parameter was actually populated (i.e., that a part number was defined for the selected part). If defined, you can use the part number to -retrieve information about the selected part from our third-party application.</p> -<p>If the part number isn’t defined, you can send an alert to the web page to notify the user that a part number must be defined to use this web page.</p> -<p>You can also use the document ID, the element ID, and the Part ID to retrieve the correct part as long as they are stored with the part in your application.</p> -<h3 id="use-the-extension">Use the extension</h3> -<ol> -<li> -<p>In Onshape, load a document. You will see your icon embedded in -the location you chose for you extension.</p> -</li> -<li> -<p>Select a part in a Part Studio, and click the icon to open the extension application: -<img src="https://onshape-public.github.io/images/integrationguideimage94.png" style="width:6.5in;height:3.94236in" alt="Graphical user interface Description automatically generated" /></p> -<p>If the part you selected has not yet been synced with your third-party application, no part number has been generated, and the system can’t find a corresponding object in our database.</p> -<p>When you select a part that has been synced, and a part number has been generated, you will see the expected result:</p> -<img src="https://onshape-public.github.io/images/integrationguideimage95.png" style="width:5.49548in;height:3.32019in" alt="Graphical user interface Description automatically generated" /> -<p>Since the context you selected for this application extension was <code>Selected Part</code>, a part must be selected to load anything in the extension. If no part is selected, you will see a notification similar to the following:</p> -<img src="https://onshape-public.github.io/images/integrationguideimage96.png" style="width:5.10442in;height:1.41408in" alt="Graphical user interface, text, application Description automatically generated" /></li> -</ol>Docs: glTF Viewerhttps://onshape-public.github.io/docs/tutorials/gltf/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/gltf/ -<p>The GLTF Viewer is a sample application that demonstrates:</p> -<ul> -<li>How to fetch a glTF representation of an Onshape model</li> -<li>How to create an app that runs as a tab inside an Onshape document</li> -<li>OAuth2 authentication</li> -<li>Use of REST APIs</li> -<li>Use of document context</li> -</ul> -<p>The application is built using Express and is deployed on Heroku.</p> -<p>Refer to the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app README</a> for instructions on running this sample app.</p>Docs: Changeloghttps://onshape-public.github.io/docs/changelog/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/changelog/ -<h4 id="rel-1185---released-2024-08-12"><code>rel-1.185</code> - released 2024-08-12</h4> -<ul> -<li>Updated all endpoints that return a user summary (createdBy, modifiedBy) have a new boolean property <code>isOnshapeSupport</code> for use to separate Onshape support employee activities.</li> -<li>Updated all <code>bodyDetails</code>, <code>tessellatededged</code>, and <code>tessellatedfaces</code> endpionts (parts and Part Studios) to include <code>errorEnum</code> vales for detecting new mate position, curve pattern and Simulation material checks.</li> -</ul> -<h4 id="rel-1184---released-2024-07-19"><code>rel-1.184</code> - released 2024-07-19</h4> -<ul> -<li>Updated API version to <code>V8</code>, (<a href="https://cad.onshape.com/api/versions)">https://cad.onshape.com/api/versions)</a>, A new microversion will not be created when a document restore operation results in a no-op.</li> -<li>Remove inconsistencies in assembly definition endpoint (<code>/assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]</code>) related to configuration parameters</li> -<li>Update all translation endpoints (<code>POST</code> : <code>../translations</code>) to include new request property <code>useFileNameToSetSinglePartName</code></li> -<li>Update all revision endpoints (<code>GET</code> : <code>/revisions/..</code>) to include response property <code>canChangeType</code> (supporting new admin option to change type part, assembly, file, etc)</li> -<li>Update <code>GET</code> : <code>/users/[:uid]/settings</code> endpoint to include responses for <code>highlightLaminarEdges</code> and <code>perspectiveModeOn</code> for <code>default</code> status</li> -</ul> -<h4 id="rel-1183---released-2024-06-28"><code>rel-1.183</code> - released 2024-06-28</h4> -<ul> -<li>Added new <code>V7</code> version to the api (<a href="https://cad.onshape.com/api/versions">https://cad.onshape.com/api/versions</a>)</li> -<li>Updated <code>GET</code> : <code>V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches</code> to return fully defined status (UNDERDEFINED, WELL_DEFINED, OVERDEFINED, UNKNOWN)</li> -<li>Updated <code>GET</code> : <code>V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches</code> vectors are now maps instead of arrays, and may be <code>BTVector2d</code> or <code>BTVector3d</code> depending on the <code>output3D</code> parameter</li> -<li>Updated <code>GET</code> : <code>V7/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/sketches</code> to use more consistent naming:</li> -</ul> -<table> -<thead> -<tr> -<th>Fields</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>sketch</code> -&gt; <code>name</code></td> -</tr> -<tr> -<td><code>sketchId</code> -&gt; <code>featureId</code></td> -</tr> -<tr> -<td><code>transformMatrix</code> -&gt; <code>sketchMatrix</code></td> -</tr> -<tr> -<td><code>featuresUsed</code> -&gt; <code>featuresUsingSketch</code></td> -</tr> -<tr> -<td><code>geomEntities</code> -&gt; <code>entities</code></td> -</tr> -</tbody> -</table> -<ul> -<li>Updated <code>GET</code> : <code>/variables</code> endpoint to return variable description when variable is set through custom feature</li> -<li>Updated <code>POST</code> : <code>/webhooks</code> endpoint to default to <code>isTransient = true</code> if not specified (auto cleanup)</li> -<li>Updated descriptions for Assembly, Documents, Metadata, Parts, Part Studios, Revisions, Variables and Versions enddpoints</li> -</ul> -<h4 id="rel-1182---released-2024-06-07"><code>rel-1.182</code> - released 2024-06-07</h4> -<ul> -<li>Updated descriptions for <code>webhooks</code> endpoints</li> -</ul> -<h4 id="rel-1181---released-2024-05-17"><code>rel-1.181</code> - released 2024-05-17</h4> -<ul> -<li>Update Document, Assembly, Blob, Drawing and Part Studio translation <code>POST</code> endpoints to have a new request body property <code>occurancesToExport</code></li> -<li>Update to <code>/elements</code> endpoint summary and descriptions in Glassworks</li> -<li>Updated documentation for webhooks (<a href="https://onshape-public.github.io/docs/app-dev/webhook/">https://onshape-public.github.io/docs/app-dev/webhook/</a>)</li> -</ul> -<h4 id="rel-1180---released-2024-04-26"><code>rel-1.180</code> - released 2024-04-26</h4> -<ul> -<li>New Drawings sample application (public repo: <a href="https://github.com/onshape-public/onshapedrawingjson">https://github.com/onshape-public/onshapedrawingjson</a>)</li> -<li>New API Guide section for response codes (<a href="https://onshape-public.github.io/docs/api-adv/errors/">https://onshape-public.github.io/docs/api-adv/errors/</a>)</li> -<li>Support export of tables in JSON of Drawings <code>GET</code> : <code>/appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views/[:viewid]/jsongeometry</code></li> -<li>Update Assembly, Blob, Drawing and Part Studio translation <code>POST</code> endpoints to have a new request body property <code>resolution</code></li> -</ul> -<h4 id="rel-1179---released-2024-04-05"><code>rel-1.179</code> - released 2024-04-05</h4> -<ul> -<li>New drawing views list endpoint <code>GET</code> : <code>/appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views</code></li> -<li>New drawing view endpoint <code>GET</code> : <code>/appelements/[:did]/[:wvm]/[:wvmid]/e/[:eid]/views/[:viewid]/jsongeometry</code></li> -<li>New updated features endpoint documentation</li> -<li>Updated glassworks for all metadata endpoints to reference developer documentation</li> -<li>Added description of output to schema for Metadata APIs</li> -<li>Updated translation endpoints with new request property <code>specifyMaterialData</code></li> -</ul> -<h4 id="rel-1178---released-2024-03-15"><code>rel-1.178</code> - released 2024-03-15</h4> -<ul> -<li>Update Part Studio translation <code>POST</code> endpoint to have a new request body property <code>importMaterialDensity</code></li> -<li>Update active workflow endpost <code>GET</code>: <code>/workflow/active</code> to have a new response property <code>hasInactiveCustomWorkflows</code></li> -<li>Updated authorization (OAuth2 and BasicAuth) for publication endpoints</li> -<li>Various updates to descriptions of data types and query parameters</li> -<li>Fixed delete publication endpoint (<code>HTTP::200</code> now removes publication)</li> -</ul> -<h4 id="rel-1177---released-2024-02-23"><code>rel-1.177</code> - released 2024-02-23</h4> -<ul> -<li>Updated translation endpoints with new request property <code>useIGESImportPostProcessing</code></li> -<li>Updated translation endpoints with modified request property <code>stepParasolidPreprocessingOption</code></li> -<li>Updated descriptions for <code>metadata</code> | <code>releasepackages</code> for property <code>propertyOverrideStatus</code></li> -</ul> -<h4 id="rel-1176---released-2024-02-02"><code>rel-1.176</code> - released 2024-02-02</h4> -<ul> -<li>New create publication endpoint <code>POST</code> : <code>/publications</code></li> -<li>New update publication endpoint <code>POST</code>: <code>/publications/[:pid]</code></li> -<li>New delete publication endpoint <code>DELETE</code>: <code>/publications/[:pid]</code></li> -<li>New create publication item endpoint <code>POST</code> : <code>/publications/item</code></li> -<li>New update publication item endpoint <code>POST</code>: <code>/publications/item/[:iid]</code></li> -<li>New delete publication item endpoint <code>DELETE</code>: <code>/publications/item/[:iid]</code></li> -</ul> -<h4 id="rel-1175---released-2024-01-12"><code>rel-1.175</code> - released 2024-01-12</h4> -<ul> -<li>Exclude suppressed sub assemblies from rootAssembly occurrences for <code>GET</code>: <code>/assemblies/d/[did]/[wvm]/[wvmid]/e/[eid]</code></li> -</ul> -<h4 id="rel-1174---released-2023-12-15"><code>rel-1.174</code> - released 2023-12-15</h4> -<ul> -<li>Add microversion id the extension url <code>[$microversionId]</code></li> -<li>Updated translation endpoints with new request property <code>pdfVersion</code></li> -<li>Fixed issue with bodydetails endpoints always returning <code>isInner</code> and <code>isOuter</code> the same</li> -<li>Update all endpoints for <code>bodydetails</code> | <code>tessellatededges</code> | <code>tessellatedfaces</code> | <code>featurescript</code> to include new response body <code>errorEnum</code>:</li> -</ul> -<table> -<thead> -<tr> -<th>errorEnum</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>BODY_DRAFT_STRAY_NONMITER_EDGES</code></td> -</tr> -<tr> -<td><code>MASS_PROPERTY_FACES_NOT_COPLANAR</code></td> -</tr> -<tr> -<td><code>PARAMETER_VALUE_INVALID</code></td> -</tr> -<tr> -<td><code>SHEET_METAL_CHAMFER_NO_TANGENT_BASED</code></td> -</tr> -<tr> -<td><code>CHAMFER_DIRECTION_OVERRIDE_NO_EFFECT</code></td> -</tr> -<tr> -<td><code>FILLET_CHAMFER_UNSUPPORTED</code></td> -</tr> -<tr> -<td><code>CHAMFER_HELD_BACK</code></td> -</tr> -<tr> -<td><code>SWEEP_BAD_LOCK_DIRECTION</code></td> -</tr> -<tr> -<td><code>SHEET_METAL_COUNTER_HOLE_UNSUPPORTED</code></td> -</tr> -<tr> -<td><code>SWEEP_SELECT_DIRECTION</code></td> -</tr> -</tbody> -</table> -<ul> -<li>Update all endpoints for <code>bodydetails</code> | <code>tessellatededges</code> | <code>tessellatedfaces</code> | <code>featurescript</code> to include new property <code>imageForeignId</code></li> -<li>Support sending a list of emails to <code>POST</code> : <code>/classrooms/[cid]/members</code></li> -</ul> -<h4 id="rel-1173---released-2023-11-28"><code>rel-1.173</code> - released 2023-11-28</h4> -<ul> -<li>Update all classroom endpoints (<code>/classrooms/</code>) to support OAuth</li> -<li>Add description of output to schema for getAssemblyShadedViews API</li> -</ul> -<h4 id="rel-1172---released-2023-11-06"><code>rel-1.172</code> - released 2023-11-06</h4> -<ul> -<li>Update all endpoints for <code>bodydetails</code> | <code>tessellatededges</code> | <code>tessellatedfaces</code> | <code>featurescript</code> to include new response body <code>errorEnum</code>:</li> -</ul> -<table> -<thead> -<tr> -<th>errorEnum</th> -</tr> -</thead> -<tbody> -<tr> -<td><code>FIT_TOLERANCE_LIMITS_NOT_FOUND</code></td> -</tr> -<tr> -<td><code>FIT_TOLERANCE_SIZE_TOO_LARGE_ISO</code></td> -</tr> -<tr> -<td><code>FIT_TOLERANCE_SIZE_TOO_LARGE_ANSI</code></td> -</tr> -<tr> -<td><code>OFFSET_WIRE_SHEET_CREATION_FAILED</code></td> -</tr> -<tr> -<td><code>REPLACE_FACE_SHEET_SMALL</code></td> -</tr> -<tr> -<td><code>REPLACE_FACES_NOT_ADJACENT</code></td> -</tr> -<tr> -<td><code>SHEET_METAL_HOLE_REBUILD_FAILED</code></td> -</tr> -<tr> -<td><code>CPLANE_TANGENT_INPUT</code></td> -</tr> -<tr> -<td><code>CPLANE_TANGENT_SELECT_REFERENCE</code></td> -</tr> -<tr> -<td><code>CNE_TANGENT_PLANE_INVALID</code></td> -</tr> -<tr> -<td><code>CPLANE_TANGENT_POINT_INVALID</code></td> -</tr> -<tr> -<td><code>REPLACE_FACES_NOT_SAME_BODY</code></td> -</tr> -<tr> -<td><code>MUST_USE_DEFAULT_RADIUS_WITH_FACE_BEND</code></td> -</tr> -<tr> -<td><code>CANNOT_RIP_A_FACE_BEND</code></td> -</tr> -<tr> -<td><code>CANNOT_MAKE_A_FACE_BEND_TANGENT</code></td> -</tr> -</tbody> -</table> -<ul> -<li>References to <code>API Guide</code> for endpoint descriptions in Glassworks</li> -</ul> -<h4 id="rel-1171---released-2023-10-13"><code>rel-1.171</code> - released 2023-10-13</h4> -<ul> -<li>Update all translation <code>POST</code> endpoints to have a new request body properties <code>hideInspectionItems</code> and <code>textOption</code></li> -<li>Replaced <code>GET</code> : <code> /releasepackages/companyreleaseworkflow</code> | <code>/workflow/active</code> property <code>canCurrentUserSyncVersionsToArena</code> with <code>canCurrentUserSyncStandardContentToArena</code></li> -<li>Updated <code>GET</code> and <code>POST</code> : <code>/tabletemplates</code> endpoint with new response property <code>valueType</code></li> -<li>Comprehensive update to remaining endpoint summary and descriptions in Glassworks</li> -</ul> -<h4 id="rel-1170---released-2023-09-22"><code>rel-1.170</code> - released 2023-09-22</h4> -<ul> -<li>New appelements delete subelement endpoint <code>DELETE</code> : <code>/appelements/d/[did]/[wvm]/[wvmid]/e/[eid]/content/subelements</code></li> -<li>New company add new user endoint <code>POST</code> : <code>/companies/[cid]/users</code></li> -<li>New company update user endoint <code>POST</code> : <code>/companies/[cid]/users/[uid]</code></li> -<li>New company delete user endoint <code>DELETE</code> : <code>/companies/[cid]/users/[uid]</code></li> -<li>Comprehensive update to remaining endpoint summary and descriptions in Glassworks</li> -</ul> -<h4 id="rel-1169---released-2023-09-01"><code>rel-1.169</code> - released 2023-09-01</h4> -<ul> -<li>Comprehensive update to most endpoint summary and descriptions in Glassworks</li> -<li>Update all translation endpoints to include new property <code>importAppearances</code></li> -<li>Update <code>POST</code> : <code>/partstudios/d/[did]/[wvm]/[wvmid]/e/[eid]/featurescript</code> has a new property <code>expressionErrorInfo</code></li> -<li>Update <code>GET</code> and <code>POST</code> : <code>/releasepackages/[rpid]</code> property <code>workflow/actions</code> has a new enum value <code>REASSIGN_TASK</code></li> -</ul> -<h4 id="rel-1168---released-2023-08-11"><code>rel-1.168</code> - released 2023-08-11</h4> -<ul> -<li>Deprecated <code>POST</code> : <code>/api/drawings/create</code> -&gt; Replaced with <code>POST</code> : <code>/api/drawings/d/[did]/w/w/[wid]/create</code></li> -<li>Update <code>GET</code> : <code>/api/documents</code> endpoint has a new property <code>publishedVersion</code></li> -<li>Update <code>GET</code> and <code>POST</code> : <code>/api/releasepackages/[rpid]</code> has a new property <code>syncedWithPLM</code></li> -</ul> -<h4 id="rel-1167---released-2023-07-21"><code>rel-1.167</code> - released 2023-07-21</h4> -<ul> -<li>Update glTF translation endpoints to use new field <code>useGltfCompression</code> (bool)</li> -<li>Update STEP translation endpoints to use new field <code>stepParasolidPreprocessingOption</code> (0-None, 1-Advanced, 2-Automatic, 3-Basic)</li> -<li>Update <code>GET</code> : <code>/api/documents</code> | <code>/api/documents/[did]</code> | <code>/api/companies/[cid]/documentsbyname</code> to include new field <code>forceExportRules</code></li> -</ul> -<h4 id="rel-1165---released-2023-06-12"><code>rel-1.165</code> - released 2023-06-12</h4> -<ul> -<li>Support <code>partId</code> array string for <code>GET</code> : <code>/api/partstudios/bodydetails</code> endpoint for the option of getting a subset of parts from a partstudio (empty = all parts)</li> -</ul> -<h4 id="rel-1163---released-2023-04-28"><code>rel-1.163</code> - released 2023-04-28</h4> -<ul> -<li>Update documentation for the Documents endpoint (<code>/api/documents</code>)</li> -<li>Update Releasepackage endpoint <code>GET</code> : <code>/api/releasepackage</code> to include <code>type</code> to understand action (ie. Approve vs Reject)</li> -<li>Update API to V6 - Fix a bug in how updating the JSON tree of an app element in a transaction returns the diff</li> -</ul> -<h4 id="rel-1162---released-2023-04-12"><code>rel-1.162</code> - released 2023-04-12</h4> -<ul> -<li>New Assembly modify endpoint <code>POST</code> : <code>/api/assemblies/d/{did}/w/{wid}/e/{eid}/modify</code> for bulk deletion and suppression of instances and features</li> -</ul> -<h4 id="rel-1161---released-2023-03-20"><code>rel-1.161</code> - released 2023-03-20</h4> -<ul> -<li>New BOM templates endpoint (<code>/api/tabletemplates</code>)</li> -<li>Support POST <code>/api/webhooks</code> parameter <code>isTransient = true</code> to specify auto cleanup after a set number of days</li> -</ul> -<h4 id="rel-1160---released-2023-02-24"><code>rel-1.160</code> - released 2023-02-24</h4> -<ul> -<li>Support configuratons for <code>GET</code> : <code>/api/partstudios/d/{did}/{wvm}/{wvmid}/e/{eid}/features</code></li> -<li>Remove deprecated <code>GET</code> : <code>/api/elements/:emid</code></li> -<li>Remove deprecated <code>GET</code> and <code>POST</code> : <code>/api/elements/d/:did/[wvm]/:wvmid/e/:eid/metadata</code></li> -<li>Deprecated <code>GET</code> and <code>POST</code> : <code>/api/parts/standardcontent/d/:did/v/:vid/e/:eid/[cu]/:cuid/partid/:pid/metadata</code></li> -<li>Deprecated <code>GET</code> and <code>POST</code> : <code>/api/parts/d/:did/[wvm]/:wmvid/e/:eid/partid/:pid/metadata</code></li> -</ul> -<h4 id="rel-1158---released-2023-01-11"><code>rel-1.158</code> - released 2023-01-11</h4> -<ul> -<li>New example values in Glassworks API documentation</li> -</ul> -<h4 id="rel-1155---released-2022-11-01"><code>rel-1.155</code> - released 2022-11-01</h4> -<ul> -<li>Support Parasolid binary (x_b) exports</li> -</ul> -<h4 id="rel-1154---released-2022-10-10"><code>rel-1.154</code> - released 2022-10-10</h4> -<ul> -<li>Add face color, hidden state and type of composite to body details endpoint</li> -</ul> -<h4 id="rel-1152---released-2022-08-30"><code>rel-1.152</code> - released 2022-08-30</h4> -<ul> -<li>Support more parameters to filter the partstudio endpoint</li> -</ul> -<h4 id="rel-1147---released-2022-05-16"><code>rel-1.147</code> - released 2022-05-16</h4> -<ul> -<li>Support global tree node endpoint for impacting recently opened filter</li> -</ul> -<h4 id="rel-1146---released-2022-04-25"><code>rel-1.146</code> - released 2022-04-25</h4> -<ul> -<li>Support API versioning</li> -<li>Return ‘nodeId’ when adding or updating an AppElement</li> -</ul> -<h4 id="rel-1145---released-2022-04-05"><code>rel-1.145</code> - released 2022-04-05</h4> -<ul> -<li>Fixed issue where assembly feature errors were missing</li> -</ul> -<h4 id="rel-1140---released-2021-12-15"><code>rel-1.140</code> - released 2021-12-15</h4> -<ul> -<li>Add mass properties for assemblies</li> -</ul> -<h4 id="rel-1139---released-2021-11-15"><code>rel-1.139</code> - released 2021-11-15</h4> -<ul> -<li>Relax casing search in Glassworks (Swagger client)</li> -<li>BOM and Metadata API endpoint responses now matched</li> -</ul> -<h4 id="rel-1138---released-2021-10-25"><code>rel-1.138</code> - released 2021-10-25</h4> -<ul> -<li>Updated webhook documentation</li> -</ul> -<h4 id="rel-1135---released-2021-8-20"><code>rel-1.135</code> - released 2021-8-20</h4> -<ul> -<li>Webhook events for Enterprise SSO configuration changes</li> -</ul> -<h4 id="rel-1134---released-2021-07-30"><code>rel-1.134</code> - released 2021-07-30</h4> -<ul> -<li>Support comment events (add, update, delete) for the web-hook endpoint</li> -</ul> -<h4 id="rel-1131---released-2021-06-01"><code>rel-1.131</code> - released 2021-06-01</h4> -<ul> -<li>Add synchronous glTF/gLB endpoint for assemblies</li> -</ul> -<h4 id="rel-1128---released-2021-03-29"><code>rel-1.128</code> - released 2021-03-29</h4> -<ul> -<li>Support face color for export of glTF/gLB</li> -<li>Add document API endpoint for comments</li> -</ul> -<h4 id="rel-1127---released-2021-03-08"><code>rel-1.127</code> - released 2021-03-08</h4> -<ul> -<li>Add translation option dtkPeriodicFacesPolicy=3 for CATIA parts</li> -</ul> -<h4 id="rel-1126---released-2021-02-12"><code>rel-1.126</code> - released 2021-02-12</h4> -<ul> -<li>Add GLTF and GLB accepts option to the tessellation APIs</li> -</ul> -<h4 id="rel-1125---released-2021-01-25"><code>rel-1.125</code> - released 2021-01-25</h4> -<ul> -<li>Add ‘good/better/best’ quality query parameters to tessellation endpoint</li> -</ul> -<h4 id="rel-1122---released-2020-11-18"><code>rel-1.122</code> - released 2020-11-18</h4> -<ul> -<li>Enforce OAuth endpoint rate limiting</li> -<li>Add release package action/transition based webhooks</li> -</ul> -<h4 id="rel-1119---released-2020-09-15"><code>rel-1.119</code> - released 2020-09-15</h4> -<ul> -<li>Add rollback bar to EvalFeatureScript endpoint</li> -</ul> -<h4 id="rel-1118---released-2020-08-25"><code>rel-1.118</code> - released 2020-08-25</h4> -<ul> -<li>PartStudio GET support for sketch constraints in features endpoint</li> -</ul> -<h4 id="rel-1116---released-2020-07-15"><code>rel-1.116</code> - released 2020-07-15</h4> -<ul> -<li>Specify starting elements to create document endpoint</li> -</ul> -<h4 id="rel-1114---released-2020-06-03"><code>rel-1.114</code> - released 2020-06-03</h4> -<ul> -<li>Project endpoints</li> -</ul> -<h4 id="rel-1113---released-2020-05-11"><code>rel-1.113</code> - released 2020-05-11</h4> -<ul> -<li>Output GLTF files for an element (tab)</li> -</ul> -<h4 id="rel-1111---released-2020-03-31"><code>rel-1.111</code> - released 2020-03-31</h4> -<ul> -<li>Support ownership transfer for teams</li> -</ul> -<h4 id="rel-1110---released-2020-03-09"><code>rel-1.110</code> - released 2020-03-09</h4> -<ul> -<li>Add support for exploded views</li> -</ul> -<h4 id="rel-1108---released-2020-01-29"><code>rel-1.108</code> - released 2020-01-29</h4> -<ul> -<li>Drawings endpoints for create 4 view, get view geometry and view definition</li> -</ul> -<h4 id="rel-1102---released-2019-09-11"><code>rel-1.102</code> - released 2019-09-11</h4> -<ul> -<li>Added webhook events for release management</li> -<li>Added webhook event for document version creation</li> -</ul> -<h4 id="rel-199---released-2019-07-08"><code>rel-1.99</code> - released 2019-07-08</h4> -<ul> -<li>Assembly BOM API support for items</li> -</ul> -<h4 id="rel-196---released-2019-05-03"><code>rel-1.96</code> - released 2019-05-03</h4> -<ul> -<li>Part Studio compare endpoint</li> -</ul> -<h4 id="rel-193---released-2019-03-01"><code>rel-1.93</code> - released 2019-03-01</h4> -<ul> -<li>Webhook subscriptions for a company</li> -</ul> -<h4 id="rel-186---released-2018-09-28"><code>rel-1.86</code> - released 2018-09-28</h4> -<ul> -<li>Export Drawings to DXF, DWG and PDF</li> -</ul> \ No newline at end of file +Welcome to the Onshape Developer Documentation onhttps://onshape-public.github.io/docs/Recent content in Welcome to the Onshape Developer Documentation onHugoen-usMon, 01 Jan 0001 00:00:00 +0000Changeloghttps://onshape-public.github.io/docs/changelog/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/changelog/rel-1.185 - released 2024-08-12 Updated all endpoints that return a user summary (createdBy, modifiedBy) have a new boolean property isOnshapeSupport for use to separate Onshape support employee activities. Updated all bodyDetails, tessellatededged, and tessellatedfaces endpionts (parts and Part Studios) to include errorEnum vales for detecting new mate position, curve pattern and Simulation material checks. rel-1.184 - released 2024-07-19 Updated API version to V8, (https://cad.onshape.com/api/versions), A new microversion will not be created when a document restore operation results in a no-op. \ No newline at end of file diff --git a/docs/tutorials/createextension/index.html b/docs/tutorials/createextension/index.html index f347dba..1d53dfb 100644 --- a/docs/tutorials/createextension/index.html +++ b/docs/tutorials/createextension/index.html @@ -1,9 +1,8 @@ -Create an Extension |

    Create an Extension

    In this example, you will create a custom web page (as shown in the image below) that is displayed in the +Create an Extension |

    Create an Extension

    In this example, you will create a custom web page (as shown in the image below) that is displayed in the right-hand fly-out panel. This interface displays metadata pulled from a third-party system when a part in Onshape is selected. This interface can also update metadata in Onshape through the Update functionality.

    You can follow along with the steps below with this video: OAuth app creation video

    Define the extension

    This tutorials builds off the Generate Derivative Files tutorial. Please complete that one before starting on this one.

    1. Navigate to the Developer portal from https://dev-portal.onshape.com.

    2. Click OAuth applications in the left menu.

    3. Select your application, and the click the Extensions tab. @@ -36,4 +35,4 @@

    This code checks to see if the partNumber parameter was actually populated (i.e., that a part number was defined for the selected part). If defined, you can use the part number to retrieve information about the selected part from our third-party application.

    If the part number isn’t defined, you can send an alert to the web page to notify the user that a part number must be defined to use this web page.

    You can also use the document ID, the element ID, and the Part ID to retrieve the correct part as long as they are stored with the part in your application.

    Use the extension

    1. In Onshape, load a document. You will see your icon embedded in the location you chose for you extension.

    2. Select a part in a Part Studio, and click the icon to open the extension application: -Graphical user interface Description automatically generated

      If the part you selected has not yet been synced with your third-party application, no part number has been generated, and the system can’t find a corresponding object in our database.

      When you select a part that has been synced, and a part number has been generated, you will see the expected result:

      Graphical user interface Description automatically generated

      Since the context you selected for this application extension was Selected Part, a part must be selected to load anything in the extension. If no part is selected, you will see a notification similar to the following:

      Graphical user interface, text, application Description automatically generated
    \ No newline at end of file +Graphical user interface Description automatically generated

    If the part you selected has not yet been synced with your third-party application, no part number has been generated, and the system can’t find a corresponding object in our database.

    When you select a part that has been synced, and a part number has been generated, you will see the expected result:

    Graphical user interface Description automatically generated

    Since the context you selected for this application extension was Selected Part, a part must be selected to load anything in the extension. If no part is selected, you will see a notification similar to the following:

    Graphical user interface, text, application Description automatically generated
    \ No newline at end of file diff --git a/docs/tutorials/derivative/index.html b/docs/tutorials/derivative/index.html index 09538a9..ac178eb 100644 --- a/docs/tutorials/derivative/index.html +++ b/docs/tutorials/derivative/index.html @@ -1,9 +1,8 @@ -Generate Derivative Files |

    Generate Derivative Files

    This tutorials builds off the Sync Releases and Revisions tutorial. Please complete that one before starting on this one.

    It’s clear by now that Onshape doesn’t use files to store its data, +Generate Derivative Files |

    Generate Derivative Files

    This tutorials builds off the Sync Releases and Revisions tutorial. Please complete that one before starting on this one.

    It’s clear by now that Onshape doesn’t use files to store its data, instead it is a data driven solution that is always up to date. Files are a snapshot in time that provide a view of the design at a specific point in time - such as at a release or version. A new file is required @@ -109,4 +108,4 @@ follows:

    In this case once the translation is completed, this endpoint receives a notification. If the event is equal to

    onshape.model.translation.complete

    We can assume that the translation has completed and we can unregister the webhook and retrieve the translated file.

    The complete sample including it setup and deployment can be found at: -https://github.com/onshape-public/app-gltf-viewer

    \ No newline at end of file +https://github.com/onshape-public/app-gltf-viewer

    \ No newline at end of file diff --git a/docs/tutorials/gltf/index.html b/docs/tutorials/gltf/index.html index 1ddb344..2e04d7b 100644 --- a/docs/tutorials/gltf/index.html +++ b/docs/tutorials/gltf/index.html @@ -1,11 +1,9 @@ -glTF Viewer | glTF Viewer |

    glTF Viewer

    The GLTF Viewer is a sample application that demonstrates:

    • How to fetch a glTF representation of an Onshape model
    • How to create an app that runs as a tab inside an Onshape document
    • OAuth2 authentication
    • Use of REST APIs
    • Use of document context

    The application is built using Express and is deployed on Heroku.

    Refer to the gltf-viewer-app README for instructions on running this sample app.

    \ No newline at end of file +Refer to the gltf-viewer-app README for instructions on running this sample app.">

    glTF Viewer

    The GLTF Viewer is a sample application that demonstrates:

    • How to fetch a glTF representation of an Onshape model
    • How to create an app that runs as a tab inside an Onshape document
    • OAuth2 authentication
    • Use of REST APIs
    • Use of document context

    The application is built using Express and is deployed on Heroku.

    Refer to the gltf-viewer-app README for instructions on running this sample app.

    \ No newline at end of file diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html index b6c7aa2..eb02f7d 100644 --- a/docs/tutorials/index.html +++ b/docs/tutorials/index.html @@ -1,3 +1,5 @@ -Sample Apps |

    Sample Apps

    The easiest way to get started with the Onshape API is to look at our sample applications. Each sample application is provided as a Github repository. For access, go to https://github.com/onshape-public.

    Sample Apps and Tutorials

    1. In Sync Data and Metadata, we set up a third-party OAuth application and pull part numbers into it from Onshape.
    2. Whether data is released initially in Onshape or in the third-party application, those releases must be kept in sync. In Sync Releases and Revisions, we use part number data (pushed to the third-party application in the previous tutorial) to release data and push notifications back to Onshape.
    3. Generate Derivative Files deals with the creation of derivative -files (such as PDF, STEP, etc.) once the release has been successfully completed.
    4. In the Extensions tutorial, we add our app to an extension in the right-hand fly-out panel in Onshape.
    5. In the glTF Viewer app, we authenticate with OAuth2 and fetch a glTF representation of an Onshape model.
    \ No newline at end of file +Sample Apps |

    Sample Apps

    The easiest way to get started with the Onshape API is to look at our sample applications. Each sample application is provided as a Github repository. For access, go to https://github.com/onshape-public.

    Sample Apps and Tutorials

    1. In Sync Data and Metadata, we set up a third-party OAuth application and pull part numbers into it from Onshape.
    2. Whether data is released initially in Onshape or in the third-party application, those releases must be kept in sync. In Sync Releases and Revisions, we use part number data (pushed to the third-party application in the previous tutorial) to release data and push notifications back to Onshape.
    3. Generate Derivative Files deals with the creation of derivative +files (such as PDF, STEP, etc.) once the release has been successfully completed.
    4. In the Extensions tutorial, we add our app to an extension in the right-hand fly-out panel in Onshape.
    5. In the glTF Viewer app, we authenticate with OAuth2 and fetch a glTF representation of an Onshape model.
    \ No newline at end of file diff --git a/docs/tutorials/index.xml b/docs/tutorials/index.xml index 9b43fe4..93e5ab4 100644 --- a/docs/tutorials/index.xml +++ b/docs/tutorials/index.xml @@ -1,1325 +1,7 @@ -– Sample Appshttps://onshape-public.github.io/docs/tutorials/Recent content in Sample Apps onHugo -- gohugo.ioen-usWed, 07 Jun 2023 00:00:00 +0000Docs: Sync Data and Metadatahttps://onshape-public.github.io/docs/tutorials/sync/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/sync/ -<p>The first business case is probably the most common, “How do I sync data -that I create in Onshape with my ERP or PLM system?”. There could be -many reasons why you would want to sync data between two different -systems. Primarily Onshape is a system that creates new data. This data -is created by designers as they perform their daily tasks. While the -designer works primarily in Onshape, the actual data that they create -does not exist in a vacuum, it is used by other departments, other -processes within the organization. These departments and processes -probably do not have access to Onshape or the required knowledge of how -to use Onshape. In addition, quite often, the data generated by Onshape -will be augmented with additional data as the product lifecycle process -progresses.</p> -<p>Therefore, Onshape could be considered the genesis of the data that will -be used to develop a product, yet it is not the only data that will be -required.</p> -<h2 id="overview">Overview</h2> -<p>In this business case we examine how a designer could work in Onshape -and how the data generated by Onshape can be used to make decisions in -other systems. Based upon the decisions made, data is pushed back to -Onshape as values calculated in another system. Let’s look at the -process in much more detail.</p> -<h3 id="step-1-define-properties-in-onshape">Step 1: Define Properties in Onshape</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage31.png" -style="width:5.41667in;height:1.84722in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>In the first step, the designer starts a new part in Onshape – -remember that in Onshape a Part can be created along with other -parts in a Part Studio, so we can assume that there could be -multiple parts created in the single document. Obviously, we want -the designer to have the freedom to use all Onshape functionality -without constraints placed by the demands of the integration.</p> -</li> -<li> -<p>At some point in the design process, the designer will be required -to enter property values for the part – these could include values -such as the Part Name, the description, material and so on.</p> -</li> -<li> -<p>The designer clicks the “Save” or “Apply” button for the properties -and closes the properties window.</p> -</li> -<li> -<p>A web hook that listens to any changes in the properties has been -defined. As the user saves the properties, the web hook is -triggered, and it will send a notification through the defined web -hook to the third-party system.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note: There are Part -properties, workspace properties and document properties – all these -properties live at different levels of the document. While the trigger -could pick up changes to any to these properties, we are currently -focused on just Part properties – the event will be triggered on any -saving of properties, however our third-party code can ignore anything -that’s not a Part (or an Assembly). In this next step we assume that a -new object is being created in the third-party application.</p> -<h3 id="step-2-create-corresponding-object">Step 2: Create Corresponding Object</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage32.png" -style="width:5.16667in;height:2.13889in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>Once the designer made changes to the properties in Onshape and -saved those changes, a message is sent to our third-party -application. This message is in JSON format and contains minimal -information such as the Workspace ID, the Document ID, the Element -ID, the Part ID (if it’s a Part) and information regarding the event -that was triggered. The third-party application receives this -information to an endpoint that was defined during the setup of the -web hook.</p> -</li> -<li> -<p>The code in our application can now use the ID’s sent over to check -if an object with corresponding IDs exists in our system. Here we -are assuming that no such object exists. This does mean that we must -store Onshape IDs into our objects in the third-party system.</p> -</li> -<li> -<p>We then create a new object and populate the ID information and save -it to the database. Note that at this point in time, we only have -minimal information that provides no more than the identity of the -Onshape Part.</p> -</li> -<li> -<p>Next, in order to get the complete metadata, we must make a REST API -call to Onshape in order to get the metadata for the part. Since we -were provided the ID information in the web hook, we have enough -information to go back to Onshape and request the metadata for a -specific, document, element, workspace and part.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that you can either -store the Onshape IDs in separate fields in your database or as one long -unique string which can be used to easily identify the part in your -application.</p> -<h3 id="step-3-get-onshape-metadata">Step 3: Get Onshape Metadata</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage33.png" -style="width:5.75in;height:2.04167in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>The response from the call to the Onshape API is sent back as JSON. -The data will contain a lot of different objects that represent the -property values, their types, the IDs, name of the property, value -of the property, etc.</p> -</li> -<li> -<p>Once received this data must be parsed by your third-party -application code and the corresponding object updated as required. -For bi-directional update, it is important to store the Onshape -property IDs of any data that will need to be synced back to Onshape -from the third-party application.</p> -</li> -<li> -<p>This is an optional stage. Once you have all the metadata values -imported, you could now calculate any values that are based off the -metadata. The most common use case scenario is the generation of -intelligent part numbers. Based off configuration, part type, etc., -you could generate a part number that has specific meaning within -the context of the company.</p> -</li> -<li> -<p>If you calculated specific values, you can now store them in your -database.</p> -</li> -</ol> -<h3 id="step-4-modify-properties-in-onshape">Step 4: Modify Properties in Onshape</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage34.png" -style="width:5.04167in;height:3.97222in" -alt="Diagram Description automatically generated" /></p> -<ol> -<li> -<p>As in Step 1 the designer updates the properties in Onshape – this -is obviously something that can happen multiple times</p> -</li> -<li> -<p>The web hook is triggered when the designer saves the property -changes</p> -</li> -<li> -<p>Our third-party application is listening for property changes</p> -</li> -<li> -<p>The third-party application’s code will check if the corresponding -object exists based off the IDs sent from Onshape.</p> -</li> -<li> -<p>In this scenario the corresponding object has already been saved in -our system</p> -</li> -<li> -<p>We make a REST API call to Onshape to get the metadata based off the -IDs sent from Onshape.</p> -</li> -<li> -<p>Onshape returns the JSON that represents the updated properties</p> -</li> -<li> -<p>We ingest the updated metadata and update our existing object in the -third-party system.</p> -</li> -</ol> -<h3 id="step-5-request-part-number">Step 5: Request Part Number</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage35.png" -style="width:5.76389in;height:2.13889in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>As we will see later, Onshape has the built in capability to pull -custom part numbers from a third-party system. From either the -properties window or the release candidate window, click the button -to request a part number</p> -</li> -<li> -<p>Onshape sends basic ID information to a predefined endpoint in our -third-party app.</p> -</li> -<li> -<p>The ID information sent by Onshape is enough data to find the -corresponding object in our database. We then extract from that -object the pre-calculated intelligent part number – or we can -calculate it at this point.</p> -</li> -<li> -<p>The part number is returned to Onshape and populated in the Part -Number field</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that in order to pull a -part number from a third-party application we will need to implement -OAuth2 in our application and grant Onshape access to the resources of -our application. Onshape has a very good mechanism for achieving this -and we will be explaining this in detail in this section.</p> -<p>Note that by default Onshape uses its own internal Part number -generator, in order to use a custom third-party generator, we will need -to define an app extension and then define in the Enterprise release -settings to use our custom part number generator.</p> -<h3 id="step-6-push-updates-from-third-party-application">Step 6: Push Updates from Third-Party Application</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage36.png" -style="width:5.75in;height:2.45833in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<ol> -<li> -<p>In this scenario we are updating an Object in our third-party -application and expecting that some of the property values will be -updated in Onshape. We can either send over all the properties -populated for this object, or a subset of properties and values</p> -</li> -<li> -<p>The REST API to update properties in Onshape requires that we -reference the IDs of the properties that we are updating. For this -reason we have stored the Onshape property IDs with our metadata -object in our database.</p> -</li> -<li> -<p>We construct the correct JSON that contains all the properties to -update and the new values. We can then call the Onshape REST API to -update the properties in Onshape with the new data.</p> -</li> -<li> -<p>Once successfully completed, the Onshape REST API call will return -HTTP 200 and we can notify the user if needed.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that updates to Onshape -will happen behind the scenes in real-time, therefore someone working on -the document in Onshape will be able to see the updates as soon as they -have been made. There is no notification in Onshape that notifies the -user that properties have been updated, however you can open the -properties window and view the updated data.</p> -<h2 id="implementation">Implementation</h2> -<p>We’ll start by defining an <a href="https://onshape-public.github.io/docs/app-dev/extensions">App Extension</a> in Onshape so that we can -receive custom part numbers.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" /></p> -<h3 id="debug">Debug</h3> -<p>All Browsers now have developer tools exposed in their interface. These -tools provide us ways to debug client code, view console messages and -most importantly for our use case, view Network requests and their -response.</p> -<p>In this example I am using Chrome’s developer tools. Most other Browsers -have more or less copied Chrome’s layout for the developer tools so it -should be easy to find the network section.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage39.png" -style="width:5.36972in;height:4.16096in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977895" class="anchor"></span>Figure 24 Accessing -Chrome&rsquo;s Developer Tools</p> -<p>Let’s take the simple use case of trying to understand which endpoint -Onshape uses for saving Metadata.</p> -<p>Open a document in Onshape and define some properties – don’t save yet.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage40.png" -style="width:3.42406in;height:2.25966in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p>Prior to saving open the developer tools and click on the “Network” tab.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage41.png" style="width:6.5in;height:2.37014in" -alt="Table Description automatically generated" /></p> -<p><span id="_Toc102977896" class="anchor"></span>Figure 25 Developer Tools -Network Tab</p> -<p>Next save the updated properties by clicking either the Apply Button or -the Save Button</p> -<p>In the Network tab you will see a new web request – select it:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage42.png" -style="width:5.40656in;height:2.82458in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977897" class="anchor"></span>Figure 26 Network Request -Sample</p> -<p>What we are seeing here is the response from the call to Save the -properties. We can expand this response to view the complete JSON.</p> -<p>By clicking on the Headers we can view the actual request:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage43.png" -style="width:5.125in;height:2.47222in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977898" class="anchor"></span>Figure 27 HTTP POST -Request for Saving Properties</p> -<p>Here we can see that this will correspond to the APIs listed in the API Explorer.</p> -<p>Most importantly the “Payload” tab is our definition of the body of the -request. This is provided in JSON format and can be expanded. As shown -here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage44.png" -style="width:4.90769in;height:2.94205in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977899" class="anchor"></span>Figure 28 HTTP POST Body</p> -<p>We now have the correct API call and the format of the body to -successfully make the API call. We can also see from the body that if we -wish to update properties in Onshape from our third-party application, -we need to store the propertyID value.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />It is important to mention – -ALWAYS use cad.onshape.com to make API calls (no matter what you see in -the Headers tab or is shown in the Payload tab.</p> -<h3 id="define-an-application-extension">Define an Application Extension</h3> -<p>An application extension is how Onshape embeds third-party application -features in its UI. There are two types of extension:</p> -<ol> -<li> -<p>An extension that embeds its UI from the application into the -Onshape UI in an iFrame. Such a application my call Onshape REST -APIs or just expose an application interface inside Onshape.</p> -</li> -<li> -<p>An extension that embeds and that calls a REST API exposed by the -application from the Onshape UI. For instance, embedding application -functionality in the context menus or toolbars. This type of -application extension relies on external OAuth information in order -to authenticate the call. In this case Onshape acts as the client -and the application as the server.</p> -</li> -</ol> -<p>Each extension will exist at a specific location in the Onshape UI and -will work within the context of that location or a specific selection, -passing the relative information to the application.</p> -<p>In order to define the Application Extension we return to the -development portal at <a href="https://dev-portal.onshape.com/oauthApps">https://dev-portal.onshape.com/oauthApps</a> where -we initially defined our OAuth Application.</p> -<p>Select the OAuth Application that you previously defined and click on -the Extensions tab.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage91.png" style="width:6.5in;height:3.37917in" -alt="Graphical user interface, text, application, Teams Description automatically generated" /></p> -<p><span id="_Toc102977900" class="anchor"></span>Figure 29 - Oauth -Applications - Extensions</p> -<p>Start by clicking the Add Extension button.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note that you can create as -many extensions as you need for your application within the Onshape UI.</p> -<p>This is the interface where you define where in the Onshape UI the -command will appear, and what endpoint in your application the command -will reference. Changing the Location dropdown will provide additional -fields that can be defined to specify context and other relevant fields.</p> -<p>For our use case, Define a name, i.e. “Custom Part Number Generator”, -define a description of the extension and select “Part Number Generator” -from the Location dropdown. The only other field that you need to define -is the Action URL. This is the endpoint in your application where you -will fetch the part number from.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage46.png" style="width:4.125in;height:4.125in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977901" class="anchor"></span>Figure 30 - Define -Application Extension</p> -<p>Once you save the definition you will see it in the list of extensions. -You can always come back and edit the definition of the extension.</p> -<h3 id="grant-onshape-access-to-3suprdsup-party-data">Grant Onshape Access to 3<sup>rd</sup> Party Data</h3> -<p>If you require Onshape to access the resources of your application, then -you will need to define the external OAuth parameters. In our use case -we will need Onshape to access data in our application in order to pull -the part numbers into Onshape.</p> -<p>Click on the External OAuth tab, the final tab on the OAuth Applications -page.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage47.png" style="width:6.5in;height:3.27361in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977902" class="anchor"></span>Figure 31 - Define -External OAuth</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />In this guide we’re not -detailing the implementation of OAuth2 inside your application, this is -explained very well in many on-line guides. My favorite of these can be -found at: -<a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2">https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2</a></p> -<p>Onshape provides the fields that are required for it to make a secure -request to your application, receive an access Token and refresh it when -required. In this case Onshape acts as the client and your application -as the server – this is the inverse to what we defined when we enabled -the third-party application to access Onshape.</p> -<p>Once you have defined the fields, Save/Update the definitions. We have -now completed defining the application extension and enabling Onshape to -access your applications resources.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Note if you haven’t defined -all the endpoints at this time, you can come back later and update the -information once you have it defined in your application.</p> -<p>The last thing we need to do is for the user to grant access for Onshape -to access your applications resources. We can do this through the same -interface that we used to grant access to Onshape.</p> -<p>From inside Onshape go to your account settings, from the top right -dropdown menu. Click on the applications page.</p> -<p>For applications that have an application extension and External OAuth -defined we have the “Grant” button available in the “external Access” -column as shown here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage48.png" style="width:6.5in;height:2.87083in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977903" class="anchor"></span>Figure 32 - Grant -External Access</p> -<p>Click the “Grant” Button in the External Access column.</p> -<p>Your third-party application will present the user with option to -authorize access to the application – similar to this simple interface:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage49.png" -style="width:4.25285in;height:1.71051in" -alt="Graphical user interface, text Description automatically generated" /></p> -<p><span id="_Toc102977904" class="anchor"></span>Figure 33 - Enabling -Onshape to access a 3rd parties data</p> -<p>If you click “Allow”, you will be returned to Onshapes Applications page -and external access will be granted.</p> -<h3 id="defining-webhooks">Defining Webhooks</h3> -<p>Now that we’ve defined our application extension and OAuth access to our -application, we can start on receiving notifications in our application -when events happen in Onshape.</p> -<p>Onshape supports webhook notification for many different types of -events. We will register an endpoint in our application that will -receive a notification whenever something occurs in Onshape. In our -specific scenario this will be when the user updates the Onshape -properties – as we defined in <strong>Step 1 Define Properties in Onshape</strong>:</p> -<p>For our purposes we will be registering to receive web hook -notifications for the onshape.model.lifecycle.metadata event. When -registering for an event in Onshape there are only two pieces of -information required:</p> -<ol> -<li> -<p>The event (onshape.model.lifecycle.metadata)</p> -</li> -<li> -<p>The Enterprise ID</p> -</li> -</ol> -<p>To easily find your enterprise ID, in Onshape select the Enterprise -Settings option from the top right dropdown menu and then click on the -“Details” menu option on the left-hand menu bar.</p> -<p>You will see your Enterprise ID and a “Copy to Clipboard” button next to -it. This will enable you to directly copy this unique ID into your code.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage50.png" -style="width:3.0006in;height:2.70759in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977905" class="anchor"></span>Figure 34 - Finding Your -Enterprise ID</p> -<p>The following code shows how we can register a webhook in Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage51.emf" alt="">In this example I’ve hard-coded a few of -the values for clarity, however this method could be re-written to be a -generic model for registering various webhooks. Some good examples of -registering for webhooks exist at <a href="https://github.com/onshape-public">https://github.com/onshape-public</a>.</p> -<p>As with other calls to Onshape that we’ve seen, we are passing the -accessToken in the header in order to establish a secure call to -Onshape’s resources.</p> -<p>The information coming back from the registration call will be similar -to the following:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2014-12-16T23:45:10.611-0500&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;webhook.register&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;544e91f7fb88ed44f5de1508&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;34795d2e5f5f44eeb61fb7b1&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span><span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>In our example we are saving the event -(onshape.model.lifecycle.metadata) and the returned webhookId to a -database in order that we can later ping it to make sure that it is -live.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Following the registration of -the webhook, Onshape will attempt to make a call to the Notify URL -defined in the body of the registration request. This is the endpoint of -your application that should be called when the event is fired in -Onshape. The most common reason for registration failures is that the -endpoint you defined, does not return an HTTP 200 status code. -Therefore, even if you registered for an event and received a -registration notification and a webhookId back from Onshape, your web -hook is not in fact registered until Onshape validates the notify URL -and receives the HTTP 200 notification back from it. Unfortunately there -is no way to easily know if your web hook has been successfully -registered until you either ping it, request to list it, or try to -activate the event through Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Also it is important to know -that even when your webhook is registered successfully, if you change -your code later on and Onshape fails to receive an HTTP 200 status code -back from the notify URL, the web hook will be removed.</p> -<p>One of the ways we can validate that a webhook is “live” is by pinging -it using the Onshape REST API. The following code shows the -implementation of a ping to the webhook. If an HTTP status code of 200 -is returned, we know that the webhook is enabled, if not then we can -re-register the webhook as needed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" /><img src="https://onshape-public.github.io/images/integrationguideimage52.emf" alt="">Once -we store the webhook ID in the database we can ping the webhook whenever -the application is loaded and validate that it’s still registered. If we -need to re-register the webhook (usually only occurs when changes are -made to the code in the notify URL), we can create a new webhook -registration and update the database record.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that you can create many -duplicate webhook registrations for the same event with the exact same -notify URL. Onshape doesn’t limit how many registrations are created for -a single webhook. In the event that this happens, the notify URL will be -called as many times as there are webhooks registered for that event. -You can validate the registered webhooks by calling the -<a href="https://cad.onshape.com/glassworks/explorer/#/Webhook">Webhook API</a>.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Use -<a href="https://cad.onshape.com/glassworks">https://cad.onshape.com/glassworks</a> to call APIs and validate the -requirements for each REST API call. This interface lists all the -available Onshape REST APIs and provides examples of the values returned -from each call.</p> -<h3 id="receiving-webhook-notifications">Receiving Webhook Notifications</h3> -<p>Once your webhook is registered and confirmed to be working you should -be getting a notification from the webhook to your notify URL. The -notification should be similar to the following:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{ -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;timestamp&#34;</span>: <span style="color:#a50">&#34;2014-12-16T23:46:29.284-0500&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;event&#34;</span>: <span style="color:#a50">&#34;onshape.document.lifecycle.metadata&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;workspaceId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;elementId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;webhookId&#34;</span>: <span style="color:#a50">&#34;544e91f7fb88ed44f5de1508&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;messageId&#34;</span>: <span style="color:#a50">&#34;60f54ac1cbc04179a6642d9a&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;data&#34;</span>: <span style="color:#a50">&#34;Some data&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentId&#34;</span>: <span style="color:#a50">&#34;0f9c4392e5934f30b48ab645&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;versionId&#34;</span>: <span style="color:#a50">&#34;000000000000000000000000&#34;</span>, -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span> <span style="color:#1e90ff;font-weight:bold">&#34;documentState&#34;</span>: <span style="color:#a50">&#34;IN PROGRESS&#34;</span> -</span></span><span style="display:flex;"><span> -</span></span><span style="display:flex;"><span>} -</span></span></code></pre></div><p>In your case the workspaceId, elementID, documentID, and PartId should -be populated with the values from the Onshape document that was open -when the properties were updated.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />It is important to note that -there is currently no OAuth validation on the webhook response, -therefore the endpoint in your application will not receive any access -token data for directly calling Onshape APIs. Therefore, if you need to -make a call to the Onshape REST APIs inside the notify URL endpoint make -a call to an endpoint in your application and include your application -OAuth credentials in the body of the request. In this way, you can make -a call to your application and load the passport and the Onshape -credentials.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Onshape takes security very -seriously and for this reason, unauthenticated calls only provide -minimal details such aa, in this case, id’s.</p> -<h3 id="getting-onshape-properties">Getting Onshape Properties</h3> -<p>In our specific use case, when we received the webhook notification, we -want to use the ID data provided to find the corresponding object in our -database (or create a new one) as shown in Step 2 Create Corresponding -Object: Then we make a call to the Onshape REST API: -/metadata/d/{did}/{wvm}/{wvmid}/e/{eid}/{iden}/{pid}</p> -<p>All the relevant data is provided in the response from the webhook so we -can pass this to the method which will call this API as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage53.emf" alt="">From this call I am returning the -“properties” part of the JSON – this contains all the metadata -definitions that I wish to store in my database and associate with the -corresponding object. The following is an example of one of the property -objects:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage54.emf" alt=""></p> -<p>In fact there is probably only three key pairs that we’re interested in -here:</p> -<ol> -<li> -<p>Name – name of the property. In this case “Name”</p> -</li> -<li> -<p>Value – the value of the property. In this case “Top Plate”</p> -</li> -<li> -<p>propertyId – the ID of this property. We might need this if we want -to enable a bi-directional sync between both applications.</p> -</li> -</ol> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that for valueType -CATEGORY the actual name, value and id will be embedded deeper in the -object inside an array. I suggest copying and pasting the output from -the API call into a JSON viewer such as <a href="http://jsonviewer.stack.hu/">http://jsonviewer.stack.hu/</a> so -that it will be easier to find where the correct values are.</p> -<p>We can now update our corresponding object with the Onshape metadata -values as described in Step 3 Get Onshape Metadata:</p> -<h3 id="updating-onshape">Updating Onshape</h3> -<p>So far we have pulled data from Onshape and populated it into our -third-party application, however what if we make updates in our -application that we want to propagate back to Onshape? This is certainly -possible through Onshape’s REST API. Usually this would be implemented -in your application on the click of a button – such as “Save”, if you -have multiple properties to update, or when a property is updated if you -want to trigger the sync for the update of a specific field.</p> -<p>Either way it is fairly straight forward to send the REST API call to -Onshape to update properties. The following snippet of code shows how -the call can be made:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage55.emf" alt="">As we can see here, we provide the body in -the form of JSON that includes an array of items (in this case one item) -and a nested array of properties (two property objects are listed here). -Each property has a value and an ID of the property in Onshape to -update.</p> -<p>The response from this API call should be an HTTP 200 status. If this is -the case, we can update the user that the sync was successful.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />If you know that you want to -update Onshape with property values from your application, it will be -important to build a data model that can store the properties with the -unique ID provided by Onshape.</p> -<h3 id="implementing-custom-part-numbers">Implementing Custom Part Numbers</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage56.png" -style="width:2.95556in;height:2.94924in" /></p> -<p>The final step in this -business case is to pull the part numbers form our third-party -application. The part numbers can be calculated based on metadata values -that were previously synced from Onshape or they might be numbers being -pulled from yet another system – such as an ERP or even a Google -Spreadsheet. The important thing is that when the user clicks a button -in Onshape, the correct Part Numbers get populated.</p> -<p>To first understand how the setup for pulling part numbers from a -third-party application we need to go back to the definition of our -Application Extension in the Onshape developer’s portal.</p> -<p>Here we can see that we gave the application extension a name, defined -the location as “Part Number Generator” and defined the “Action URL” – -this is the endpoint in our application where we will fetch the part -number from.</p> -<p>Once we have the application extension defined as Location = Part Number -Generator, you will be able to use this option inside Onshape Release -Management settings.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage4.png" -style="width:0.43056in;height:0.43056in" />Note that in order to use the -Part Number Generator option you will have to define the External OAuth -option and grant Onshape access to the resources of your application. -This is because Onshape will need to access the defined endpoint in -order to pull the part number from the application</p> -<p>From within Onshape Select the “Enterprise Settings” from the top right -dropdown menu. Navigate to the “Release Management” settings and scroll -down to the “Revisions and part numbers” section of the page.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage57.png" -style="width:4.05994in;height:3.27831in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977907" class="anchor"></span>Figure 36 - Revisions and -Part Number Settings</p> -<p>In the Part Number Generation dropdown select the “Custom Part Number -Generator”. Note that this is the name that you defined in your -Application Extension so it might differ from what’s shown here.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage58.png" -style="width:2.73732in;height:2.03131in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977908" class="anchor"></span>Figure 37 - Selecting -Custom Part Number Generator</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage6.png" -style="width:0.47222in;height:0.47222in" />Finally scroll to the bottom -of the page and save the settings.</p> -<p>Note that you will need the Admin role in order to access the enterprise -settings.</p> -<h3 id="implementing-part-number-code">Implementing Part Number Code</h3> -<p>Onshape will send a message to the endpoint defined in your application -extension settings. The content of this message will be an array of the -following data.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage59.emf" alt="">There might be one or more object depending -upon where the user initiated the call for part numbers from. For -instance, if the call was initiated from the Part properties window, -there will only be one object, however if initiated from the release -candidate window, multiple parts/assemblies and drawings might be -requested in the single call. Therefore, your code should be able to -handle these two situations.</p> -<p>Onshape will expect a response back from your endpoint and it should be -formatted in the following manner:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage60.emf" alt="">Note that in fact only the id and -partNumber fields are actually required – the other fields are optional.</p> -<p>The following is an implementation of the getNextPartNumber endpoint -that was defined in the application extension “Action URL” field:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage61.emf" alt="">This in turn calls a function that pulls -the next part number from the corresponding object in the database (this -was defined in, Step 5: Request Part Number). In this function I’m -defining the object that will be sent to Onshape with the part number. -This will be called multiple times depending how many objects were sent -from Onshape.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage62.emf" alt="">In this case I’m sending back all the data -required by Onshape, however it would be enough to just populate the id -and the partNumber.</p> -<p>Once you load the Part Properties window or the Release candidate -window, you can now request the Next Part number. The part number will -be pulled from the third-party application and populated in the relevant -fields as shown below.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage63.png" -style="width:4.59649in;height:3.80143in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977909" class="anchor"></span>Figure 38 - Release -Candidate Part Number generation</p>Docs: Sync Releases and Revisionshttps://onshape-public.github.io/docs/tutorials/releases/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/releases/ -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/sync">Sync Data and Metadata</a> tutorial. Please complete that one before starting on this one.</p> -<p>In this case, we’ll be looking at the ability for Onshape to sync its -release data with an external system and for that system to send -information back to Onshape with regards to released data.</p> -<p>This specific business case will look at what happens when you wish for -a PLM system to control the release of data instead of Onshape having -that control – this is in fact a common use case.</p> -<h2 id="overview">Overview</h2> -<p><img src="https://onshape-public.github.io/images/integrationguideimage64.png" -style="width:3.21077in;height:2.56522in" /></p> -<p>We have mentioned before that -Onshape has the ability to release data – it is totally integrated to -Onshape since there is no division between CAD capabilities and PDM -capabilities in Onshape – they are all part of the same solution. See -Versions and Releases for more information on how Onshape manages -releases. There is importance in releasing data through Onshape. Onshape -uses visual cues to show which parts are released in an assembly for -instance and which parts might have a newer revision. Onshape can also -add/remove watermarks to drawings and update the title block depending -on release states. Also, the BOM table can pull a parts release data and -display it. All this is dependent upon a release process being completed -in Onshape.</p> -<p>Many organizations have implemented Product Lifecycle management systems -(PLM). One of the key benefits of a PLM system is that it manages more -than just engineering data originating from the engineering department, -it deals with all the data related to the product – from concept through -retirement. Therefore, it is a system that is used by many groups and -departments throughout the organization.</p> -<p>Often, in release processes or Engineering Change processes, additional -input and approvals are required from various departments downstream -from engineering. PLM systems are very good at routing the data for -approval to users from multiple departments and groups throughout the -organization. Onshape, on the other hand, is very focused on the -engineering department and the data generated there. While it certainly -has the capabilities to bring other groups into approval processes, it -is not considered a process centric enterprise-wide system with the -capabilities of a PLM system.</p> -<p>Many companies will have well established processes that have been -modeled in their PLM system, it is much easier for us to integrate into -those processes than reinvent the wheel in Onshape.</p> -<p>This section looks at how we might have the best of both worlds, -initiate release processes in Onshape and update our Onshape visual cues -as well as have the PLM system manage the actual approvals and release.</p> -<p>This section uses concepts such as OAuth and web hooks that we have -introduced in detail in previous sections, therefore feel free to -reference those sections for more information on these topics.</p> -<h3 id="step-1-initiate-release">Step 1: Initiate Release</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage65.png" -style="width:4.88889in;height:2.02778in" -alt="Application Description automatically generated" /></p> -<p>In this first step we are using Onshape’s out-of-the-box capabilities to -initiate a release candidate – just as we would if we were releasing -natively in Onshape.</p> -<ol> -<li> -<p>We start by initiating the release on all the data that is required. -In this step you should use a custom workflow that simply has one -approval node.</p> -</li> -<li> -<p>Define the mandatory and any other release properties in the release -candidate window. <img src="https://onshape-public.github.io/images/integrationguideimage66.png" -style="width:4.70609in;height:3.12281in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -</li> -</ol> -<p><span id="_Toc102977911" class="anchor"></span>Figure 40 - Initiating a -release candidate</p> -<ol start="3"> -<li> -<p>Since an approver is required, we must provide a fictious -user/approver that has been defined in the system – this could be -named “Release Approver” for instance. The process will be sent to -this approver even though they are not a real person and will not be -able to approve the release. Instead, our release process will be -approved by an external source.</p> -</li> -<li> -<p>Finally, when everything is defined, submit the release. The window -will close. Since the release is pending approval, the parts -involved in the release will enter the state of “Pending” as shown -here:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage67.png" -style="width:4.40131in;height:2.9375in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -</li> -</ol> -<p><span id="_Toc102977912" class="anchor"></span>Figure 41 - Pending -Release</p> -<p>They will remain in this state until the release has been completed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage68.png" -style="width:2.71208in;height:1.52174in" /></p> -<p>It is important to note that -unlike traditional PDM systems where the files are locked for change -until the release is completed or rejected, Onshape does not lock the -files. As mentioned previously, Onshape views the releases as a point in -time. As far as Onshape is concerned, time moves forward, parts can -change and at a specific point in time, the parts are in a state of -pending. It is important to mention that this does in fact prevent -another release from being initiated on the parts until the previous -release has been completed.</p> -<h3 id="step-2-initiate-release-process-in-3suprdsup-party-app">Step 2: Initiate Release Process in 3<sup>rd</sup> Party App</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage69.png" -style="width:5.34722in;height:3.34722in" -alt="Diagram Description automatically generated" /></p> -<p>Once the user initiates the release candidate and the parts transition -to the “pending” state we can register for a webhook that will notify -our third-party application that the parts have changed state.</p> -<ol> -<li> -<p>Once the parts enter the workflow, the onshape.workflow.transition -webhook will be triggered.</p> -</li> -<li> -<p>Our third-party application should be listening for this event along -with other data, we are provided with the objectId of the release -package – this is all the data associated with the parts that are to -be released. The response also contains the objectType and the -transitionName; for our use case we will only concern ourselves with -requests that have an objectType of “Release” and a transitionName -of “Submit”.</p> -</li> -<li> -<p>Using the ObjectId we make an API call to onshape; -/api/releasepackages/&lt;releasePackageId&gt;?detailed=true</p> -</li> -<li> -<p>This API call will return to us a JSON response containing all -assemblies and parts in the release package. The following -information should be extracted from the release package:</p> -<ol> -<li> -<p>For each line item (assembly or part) extract the documentId, -the elementId, elementType, versionId and PartId</p> -</li> -<li> -<p>Iterate through the top level properties and record the -propertyId for property with the name “comment” – this will be -used to update the release comments later on.</p> -</li> -</ol> -</li> -<li> -<p>Now that we have the relevant IDs we can update the state of our -corresponding objects in the third party system and record any -additional data such as the release comment field.</p> -</li> -<li> -<p>Finally, we can kick off our official release process in the -third-party application. This could be an automated process or a -manual one.</p> -</li> -</ol> -<h3 id="step-3-complete-release-process">Step 3: Complete Release Process</h3> -<p>The release process continues in the third-party application until -approvals have been received by all required actors. Meanwhile in -Onshape the parts are in the pending state. In this step we close the -loop once the release process is completed.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage70.png" -style="width:5.375in;height:3.34722in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<ol> -<li> -<p>The release process managed by the third-party application is -completed and the data in that system is released.</p> -</li> -<li> -<p>Once this happens, we make a call to the Onshape API; -/api/releasepackages/&lt;releasePackageId&gt; the releasePackageId is -the ID we were provided with at the start of this process – While -there are different ways of implementing this, I tend to store the -ID and any other data related to the release in a custom “release -Object” in my database so I can retrieve and update the release as -required. In addition to the passing the release package ID, in the -body of the request we should pass the id of the release comment and -a value for the comment. This will update the release in Onshape -with any relevant data.</p> -</li> -<li> -<p>Onshape releases the data that was included in the release candidate -and that completes the workflow process.</p> -</li> -<li> -<p>Onshape will return a status code that indicates success or failure</p> -</li> -<li> -<p>Finally we can optionally update the corresponding object to -indicate that it is in sync with the Onshape data.</p> -</li> -</ol> -<p>In the event that the release process is rejected at anytime, we can -send the releasePackages API request to Onshape with a REJECT workflow -Action argument. This will cause Onshape to reject the workflow and the -state of the parts at the specific release point in time, will be set to -“Rejected”.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage71.png" -style="width:4.69737in;height:3.12807in" -alt="Graphical user interface, application Description automatically generated" /></p> -<p><span id="_Toc102977914" class="anchor"></span>Figure 43 - release -candidate rejected</p> -<p>Since our timeline is moving forward this has no actual effect on the -parts other than to cancel the pending release and enable them to be -released at another future point in time.</p> -<h2 id="implementation">Implementation</h2> -<p>In this section we will take a closer look at how to implement the -release scenario in our code. The first thing we need to do is define -the correct web hook to listen for the initiation of the release – this -means that once the user clicks the submit button on the release -candidate dialog, this web hook will be triggered.</p> -<h3 id="set-up-webhook">Set Up Webhook</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage72.emf" alt=""></p> -<p>This code is very similar to what we defined previously for the metadata -update, instead here we are defining a hook for the -onshape.workflow.transition hook. As with other code examples that -require authentication, we have included error handling in order to -refresh that access token in the event that it has expired.</p> -<p>The onshape.workflow.transition will in fact fire whenever a revision or -release package transitions through different workflow states. In his -specific case we are only interested in catching the event when the -workflow is initially submitted. This can be filtered by the information -sent to the return URL, in this case -<a href="https://myserver.com/api/getReleaseData">https://myserver.com/api/getReleaseData</a></p> -<p>In this implementation we are storing he webhook ID in the database so -that we can ping it when the application is loaded to make sure that it -is still active. Other implementations delete the webhook after it is -used and then recreate it as required. There is no specific preference -for which methodology is better – that depend s upon the requirements of -your integration.</p> -<h3 id="receive-web-hook-notifications">Receive Web Hook Notifications</h3> -<p>Once the user who is initiating the release clicks the Submit button on -the Release Candidate dialog, the webhook will be triggered and a -message will be sent to the third-party application listening for that -webhook.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage66.png" -style="width:4.70609in;height:3.12281in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p>In our example the URL that the webhook data from Onshape gets sent to -is:</p> -<p><a href="https://myserver.com/api/getReleaseData">https://myserver.com/api/getReleaseData</a></p> -<p>In our application we can define a router for that end point as follows:</p> -<p>router.route(&rsquo;/getReleaseData&rsquo;).post(mymodule.getReleaseData);</p> -<p>In this case “mymodule” is where I’ve defined all the functionality for -managing data coming from Onshape. Since the webhook data contains no -authentication information (just minimal data is sent from the webhoom -for security reasons), we can’t directly authenticate our application -against Onshape, therefore we need to pass the data received from the -webhook through a method that will then add the authentication data to -our request object. The getReleaseData method simply passes the webhook -information received by the application to another authenticated -endpoint as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage73.emf" alt=""></p> -<p>Here is the endpoint defined for processReleasePackage:</p> -<p>router.route(&rsquo;/processReleasePackage&rsquo;).post(authController.isAuthenticated, -releaseController.processReleasePackage);</p> -<p>As we can see here, we have now added in the authentication middleware - -authController.isAuthenticated - and can make secure calls to Onsahpe’s -API.</p> -<h3 id="get-release-package-data">Get Release Package Data</h3> -<p>The parameter that the web hook sent over to our application that we -need to make use of is the ID of the release package. We can now make a -call to Onshape to retrieve the complete release package with the ID.</p> -<p>We get the release package ID from the request object and make the REST -API call to get the package as follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage74.emf" alt=""></p> -<p>The complete release package should be returned in “response”. We can -now parse that data to retrieve the properties we need. The most -important properties will the IDs of the parts that we are going to -release – these should already be synced with our system – if not, we -can create them from the data in the release package.</p> -<h3 id="save-release-package-data">Save Release Package Data</h3> -<p>The next step is to save the properties of the release package to a -corresponding object in our database. We need at least the ID of the -release package so we can later release it automatically from the -third-party application. In this case I’m storing other properties that -came from the release candidate such as release name and description.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage75.emf" alt=""></p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage76.png" -style="width:3.01875in;height:4.38889in" /></p> -<p>Most of this code deals with -retrieving values from the release package and storing them as a new -release object in the database. Additional values are associated with -the part in the PLM system. In a typical production scenario this code -would interface with the PLMs workflow capabilities and possibly kick -off a release or change process in that system. For our basic example we -are storing values from Onshape with our items and setting a state on -the part so that users can see that the part is pending release and take -actions required.</p> -<p>At this point in time, Onshape does not care that the part is pending a -release. The part in Onshape will remain in a pending state until it is -released by the PLM system. As noted previously, we used a user setup in -the system to specifically initiate the release, therefore no other -users will receive notifications from Onshape with regards to release -actions on this part.</p> -<h3 id="complete-the-release">Complete the Release</h3> -<p>Once the release or change workflow has completed in the PLM system and -all approvals have been received, the Part/Item will be in a released -state in the PLM system. However, we must now update Onshape with the -correct release status of the parts. It is important that Onshape data -is in sync with the corresponding data in the PLM system for reasons of -data integrity and the visual cues used within Onshape to identify a -part as released.</p> -<p>In a typical scenario Onshape will be automatically updated once the -workflow completes in the PLM system. In our use case we are simplifying -the process by clicking a button to release the item. This will update -the state of the part in our system and send a REST API call to Onshape -to release the data in the release package (be it one part, an assembly -with multiple parts, or drawings).</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage77.emf" alt=""></p> -<p>This code snippet updates the database with the released status of a -part. Since we stored data from the release package in our database we -now retrieve the “Comment” property so that we can send an updated value -to Onshape with the release.</p> -<p>let attrid = rp.props.find(ob =&gt; ob.name == &ldquo;Comment&rdquo;);</p> -<p>The important line of code here is the REST API call to Onshape:</p> -<p><strong>axios.post(&lsquo;<a href="https://cad.onshape.com/api/releasepackages/'">https://cad.onshape.com/api/releasepackages/'</a> + id + -&lsquo;?wfaction=RELEASE&rsquo;</strong></p> -<p>The id provided here is the ID of the release package that we stored -when the web hook was called at the beginning of the process. The -“wfaction” argument indicates that the workflow action in Onshape should -be to release the data associated with this release package.</p> -<p>In this example we are also updating the release comments in Onshape, -for this reason we required the property ID of the Comment field – which -we also previously stored in our release object in the database.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage78.png" style="width:6.5in;height:4.25903in" -alt="Graphical user interface, text, application Description automatically generated" /></p> -<p><span id="_Toc102977916" class="anchor"></span>Figure 45 - Release -completed automatically in Onshape</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage79.png" style="width:6.5in;height:4.25625in" -alt="Graphical user interface, text, application, email Description automatically generated" /></p> -<p><span id="_Toc102977917" class="anchor"></span>Figure 46 - Release -comments Updated from third-party system</p>Docs: Generate Derivative Fileshttps://onshape-public.github.io/docs/tutorials/derivative/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/derivative/ -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/releases">Sync Releases and Revisions</a> tutorial. Please complete that one before starting on this one.</p> -<p>It’s clear by now that Onshape doesn’t use files to store its data, -instead it is a data driven solution that is always up to date. Files -are a snapshot in time that provide a view of the design at a specific -point in time - such as at a release or version. A new file is required -for each “snapshot” and managing these files can get quite cumbersome. -However, there are situations that require that files be generated from -the Onshape data.</p> -<p>In general, we want files to be generated at defined points of time and -within the context of a business process – such as a release process. -The derived file could be a format such as a PDF of the drawing that is -generated following the successful release of the data. Also, a common -requirement is to generate STEP files or JT files that can be used in 3D -Printing or viewers embedded in PLM solutions. Regardless of the use -case Onshape has very good export capabilities for many different file -formats.</p> -<p>This business case examines how to automatically generate files derived -from the Onshape data. The process described here can be plugged into -many different use cases. In this specific example we are plugging the -translation use case into the Release Business case just after the -release is completed in the third-party application and Onshape is -updated. Since we already have all the relevant ID information for the -parts to translate from the release package data, we can directly call -the translation APIs after receiving notification that the release was -successfully executed in Onshape.</p> -<h2 id="overview">Overview</h2> -<p><img src="https://onshape-public.github.io/images/integrationguideimage80.png" -style="width:5.5in;height:4.79167in" /></p> -<ol> -<li> -<p>Once we have received an HTTP 200 status from the call to Onshape to -release the release Package, we can proceed with the translation. -The reason why we may want to wait till the release has successfully -completed could be for several reasons:</p> -<ol> -<li> -<p>We are generating a PDF of the drawing and want the “In -Progress” watermark removed, and the title block updated with -release information</p> -</li> -<li> -<p>We are generating files for 3D printing or for sending to a -vendor to manufacture and we only want to send released data</p> -</li> -</ol> -</li> -<li> -<p>We can now make an API call to Onshape. In both the following cases -we must pass the document Id, the version Id and element Id – all -values that were available in the release package. Other values are -dependent upon your specific use case and can be referenced in -<a href="https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation">https://cad.onshape.com/glassworks/explorer/#/PartStudio/createPartStudioTranslation</a></p> -<ol> -<li> -<p>For Assembly translation we can POST to :/api -/assemblies/d/{did}/{wv}/{wvid}/e/{eid}/translations.</p> -</li> -<li> -<p>For Parts we can POST to: -/api/partstudios/d/{did}/{wv}/{wvid}/e/{eid}/translations</p> -</li> -</ol> -</li> -<li> -<p>Three variables of importance are returned from the API call to -translate: requestState, id (of the translation) and -resultExternalDataIds. We should store or keep this data in memory -until the translation is completed. Depending upon the requestState -there might be additional data available in the response.</p> -</li> -<li> -<p>We can now periodically ping the translation web service with the id -retrieved in the last step. Using the GET call to -/api/translation/{id} we will receive one of three responses in the -requestState:</p> -<ol> -<li> -<p>DONE</p> -</li> -<li> -<p>ACTIVE</p> -</li> -<li> -<p>FAILED</p> -</li> -</ol> -</li> -<li> -<p>Depending on the response we can either continue to periodically -ping the translation service if we received ACTIVE</p> -</li> -<li> -<p>Notify the user of a failed translation attempt if we received a -FAILED response</p> -</li> -<li> -<p>Make a call to Onshape to GET the translated file if we received a -DONE response. To retrieve the translated file make a GET request to -/api/documents/d/{documentId}/externaldata/{externalDataId}</p> -</li> -<li> -<p>The file can now be stored in your third-party system or stored to -an external drive depending upon your specific use case.</p> -</li> -</ol> -<h2 id="implementation">Implementation</h2> -<p>As use cases go, this is a very straightforward process. The only -complexity here is deciding how to receive the notification from Onshape -that the translation has completed. There are several ways of -implementing this including using a webhook to notify us when the -translation completes. In the examples here I will show both the webhook -methodology as well as pinging Onshape with a status request every -couple of seconds. The status request can be initiated from the client -through an AJAX call or, as in the example I use here, from the server.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage81.png" -style="width:3.3395in;height:3.66667in" /> In our example I have added a -button to the interface of my third-party system that enables me to -request a translated file. In this use case I have hard coded that the -resulting file should be a STEP file – in a production ready -implementation, we would expect that one or more formats are available -and possibly selected by the user. In addition, a production ready -implementation might have automated the translation for whenever a part -is released. Other considerations for automation might include -identifying what is being released. I.e. if it’s a part then translate -to STEP, if it’s a Drawing then translate to PDF, etc. These are all -very common use cases.</p> -<h3 id="initiate-the-translation">Initiate the Translation</h3> -<p><img src="https://onshape-public.github.io/images/integrationguideimage82.emf" alt="">The code snippet shown here is fairly -straightforward. First it gets the ID of the part that was sent from the -client, it then uses that ID to retrieve the part from the database. The -part stored in our database already has all the required values to -successfully communicate with Onshape, such as the document ID, the -workspace ID and the element ID – all these values are used in the -translation request.</p> -<p>In the body of the request we can see some of the required values that -define how the part is to be translated to STEP. In this case I have -only included the minimum required key pairs for this translation.</p> -<p>The REST API call to translate an Onshape element returns an object that -includes the translationId – this is the value that will be used to ping -Onshape and request the status of the translation.</p> -<h3 id="ping-onshape-for-translation">Ping Onshape for Translation</h3> -<p>In this code snippet I have simplified things by including a function -that waits for a second and then pings Onshape again, It will continue -pinging Onshape until it receives back a status that is not “ACTIVE”. -Once the status returned is anything except “ACTIVE” it returns the -resulting object back to the client.</p> -<p>The id used here is the translationId retrieved from the result object -when the translation was initiated.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage83.emf" alt=""></p> -<p>Once the requestState is changed, this will indicate that the -translation has completed either with a FAIL or a DONE status. Depending -on the result we can define our logic on the client appropriately.</p> -<p>The following shows the object returned to the client from the -translation REST API. Note that the requestState is now set to “DONE”,, -meaning that the translation has completed -successfully.<img src="https://onshape-public.github.io/images/integrationguideimage84.png" style="width:6.5in;height:3.17986in" -alt="A picture containing timeline Description automatically generated" /></p> -<p>With this data we can now request the file directly from Onshape. The ID -that we need to use to retrieve the file is the “resultExternalDataIds”. -Note that this is an array of values – since it makes sense that we -might be translating more than one part.</p> -<h3 id="retrieve-translated-file">Retrieve Translated File</h3> -<p>With the resultExternalDataIds we can now retrieve the translated file -from Onshape. The following code snippet does exactly this.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage85.emf" alt=""></p> -<p>The Onshape REST API</p> -<p><a href="https://cad.onshape.com/api/d/'">https://cad.onshape.com/api/d/'</a> + did + &lsquo;/externaldata/&rsquo; + id</p> -<p>retrieves the translated file – in this case the ID is -resultExternalDataIds[0] value.</p> -<p>Once this is completed, we use the response to save the file directly to -our server where the application is hosted. Finally, I’m sending a JSON -object to the client that provides a direct link to the file that is now -hosted on our server.</p> -<p>The client can then request the translated file from our server, even -though this is a function of the server and not related to Onshape, I -have included a code snippet here that will send the file to the client.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage86.emf" alt=""></p> -<p>In our sample implementation Once the translation has completed -successfully I display a link to the translated file that calls the -“getfile” endpoint shown above.</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage87.png" style="width:6.5in;height:2.32917in" -alt="Graphical user interface, text, application, chat or text message Description automatically generated" /></p> -<p>Clicking the link will cause the file to be downloaded as shown here.</p> -<h3 id="define-translation-webhooks">Define Translation Webhooks</h3> -<p>As we mentioned at the beginning of this section there is more than one -way to receive notification back from Onshape that the translation has -completed. We can also define a webhook that will notify us once the -translation completes. The drawback with this methodology is that the -webhook must be created for each translation and then deleted.</p> -<p>A complete example of this can be found at: -<a href="https://github.com/onshape-public/app-gltf-viewer/blob/main/services/webhook-service.js">https://github.com/onshape-public/app-gltf-viewer/blob/main/services/webhook-service.js</a></p> -<p>The following function is used in this application to define the -webhook:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage88.emf" alt=""></p> -<p>The following line would call this function once the user requests to -initiate a translation.</p> -<p>WebhookService.registerWebhook(req.user.accessToken, -req.session.passport.user.id, did)</p> -<p>Finally the endpoint registered with the webhook could be defined as -follows:</p> -<p><img src="https://onshape-public.github.io/images/integrationguideimage89.emf" alt=""></p> -<p>In this case once the translation is completed, this endpoint receives a -notification. If the event is equal to</p> -<p>onshape.model.translation.complete</p> -<p>We can assume that the translation has completed and we can unregister -the webhook and retrieve the translated file.</p> -<p>The complete sample including it setup and deployment can be found at: -<a href="https://github.com/onshape-public/app-gltf-viewer">https://github.com/onshape-public/app-gltf-viewer</a></p>Docs: Create an Extensionhttps://onshape-public.github.io/docs/tutorials/createextension/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/createextension/ -<p>In this example, you will create a custom web page (as shown in the image below) that is displayed in the -right-hand fly-out panel. This interface displays metadata pulled from -a third-party system when a part in Onshape is selected. This interface can also update metadata in Onshape through the <code>Update</code> functionality.</p> -<p>You can follow along with the steps below with this video: -<a href="https://onshape.wistia.com/medias/0ivxxngkjz?embedType=async&seo=false&videoFoam=true&videoWidth=640&wvideo=0ivxxngkjz)"><img src="https://onshape-public.github.io/images/ExtensionsVideoCard.png" style="width:5in" alt="OAuth app creation video"/></a></p> -<h3 id="define-the-extension">Define the extension</h3> -<p>This tutorials builds off the <a href="https://onshape-public.github.io/docs/tutorials/derivative">Generate Derivative Files</a> tutorial. Please complete that one before starting on this one.</p> -<ol> -<li> -<p>Navigate to the Developer portal from <a href="https://dev-portal.onshape.com">https://dev-portal.onshape.com</a>.</p> -</li> -<li> -<p>Click <strong>OAuth applications</strong> in the left menu.</p> -</li> -<li> -<p>Select your application, and the click the <strong>Extensions</strong> tab. -<img src="https://onshape-public.github.io/images/integrationguideimage91.png" style="width:6.5in;height:3.48958in" alt="Graphical user interface, application, Teams Description automatically generated" /></p> -</li> -<li> -<p>Click the <strong>Add Extension</strong> button on the top right.</p> -</li> -<li> -<p>Select <code>Element Right Panel</code>. -<img src="https://onshape-public.github.io/images/integrationguideimage92.png" style="width:5.05785in;height:5.66469in" alt="Graphical user interface, application Description automatically generated" /></p> -</li> -<li> -<p>Next, define the context. The context defines what parameters -can be sent from Onshape to the application. Some basic -parameters are automatically sent with any context, additional information can be passed to our -application, depending on the context selected. Click the <code>Selected part</code> option. This sends the <code>partId</code> and <code>partNumber</code> to the application, along with the <code>documentId</code>, <code>elementId</code>, and the <code>workspaceOrVersionId</code>.</p> -</li> -<li> -<p>In the <code>Action URL</code> field, fill in the URL of the page to load in the right element panel. The parameters can be added as arguments (variable that get replaced with real values when the page is loaded from Onshape).</p> -<pre tabindex="0"><code>https://ourserver.com/bom?documentId=${documentid}&amp;elementId=${elementid}&amp;partId={$partId}&amp;partNumber={$partNumber} -</code></pre></li> -<li> -<p>Finally, select an icon for the extension. This will appear on the tab that opens the right element panel.</p> -</li> -</ol> -<p>You have now defined the extension, and it will appear in the Onshape -interface.</p> -<h3 id="call-a-page-in-the-extension">Call a page in the extension</h3> -<p>The following code snippet shows how to use your previous definition to -pull data from the third-party application and send it to the web page:</p> -<div class="highlight"><pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//https://myserver.com/bom?documentId=${documentId}&amp;elementId=${elementId}&amp; -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic">//partId=${partId}&amp;partNumber=${partNumber} -</span></span></span><span style="display:flex;"><span><span style="color:#aaa;font-style:italic"></span>app.get(<span style="color:#a50">&#39;/bom&#39;</span>, (req, res) =&gt; { -</span></span><span style="display:flex;"><span> <span style="color:#00a">if</span> (req.query.partNumber !== <span style="color:#a50">&#39;${partNumber&#39;</span>}) { -</span></span><span style="display:flex;"><span> partController.getPartsList(req.query.partNumber).then((parts) =&gt; { -</span></span><span style="display:flex;"><span> catController.getCatById(parts.Category).then((cat) =&gt; { -</span></span><span style="display:flex;"><span> res.render(<span style="color:#a50">&#39;bomview&#39;</span>, { -</span></span><span style="display:flex;"><span> parts: parts, -</span></span><span style="display:flex;"><span> cat: cat -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> } <span style="color:#00a">else</span> { -</span></span><span style="display:flex;"><span> res.render(<span style="color:#a50">&#39;bomview&#39;</span>, { -</span></span><span style="display:flex;"><span> parts: { <span style="color:#a50">&#34;_id&#34;</span>: <span style="color:#099">0</span> }, -</span></span><span style="display:flex;"><span> cat: { <span style="color:#a50">&#34;_id&#34;</span>: <span style="color:#099">0</span> } -</span></span><span style="display:flex;"><span> }) -</span></span><span style="display:flex;"><span> } -</span></span><span style="display:flex;"><span>}) -</span></span></code></pre></div><p>This code checks to see if the <code>partNumber</code> parameter was actually populated (i.e., that a part number was defined for the selected part). If defined, you can use the part number to -retrieve information about the selected part from our third-party application.</p> -<p>If the part number isn’t defined, you can send an alert to the web page to notify the user that a part number must be defined to use this web page.</p> -<p>You can also use the document ID, the element ID, and the Part ID to retrieve the correct part as long as they are stored with the part in your application.</p> -<h3 id="use-the-extension">Use the extension</h3> -<ol> -<li> -<p>In Onshape, load a document. You will see your icon embedded in -the location you chose for you extension.</p> -</li> -<li> -<p>Select a part in a Part Studio, and click the icon to open the extension application: -<img src="https://onshape-public.github.io/images/integrationguideimage94.png" style="width:6.5in;height:3.94236in" alt="Graphical user interface Description automatically generated" /></p> -<p>If the part you selected has not yet been synced with your third-party application, no part number has been generated, and the system can’t find a corresponding object in our database.</p> -<p>When you select a part that has been synced, and a part number has been generated, you will see the expected result:</p> -<img src="https://onshape-public.github.io/images/integrationguideimage95.png" style="width:5.49548in;height:3.32019in" alt="Graphical user interface Description automatically generated" /> -<p>Since the context you selected for this application extension was <code>Selected Part</code>, a part must be selected to load anything in the extension. If no part is selected, you will see a notification similar to the following:</p> -<img src="https://onshape-public.github.io/images/integrationguideimage96.png" style="width:5.10442in;height:1.41408in" alt="Graphical user interface, text, application Description automatically generated" /></li> -</ol>Docs: glTF Viewerhttps://onshape-public.github.io/docs/tutorials/gltf/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/gltf/ -<p>The GLTF Viewer is a sample application that demonstrates:</p> -<ul> -<li>How to fetch a glTF representation of an Onshape model</li> -<li>How to create an app that runs as a tab inside an Onshape document</li> -<li>OAuth2 authentication</li> -<li>Use of REST APIs</li> -<li>Use of document context</li> -</ul> -<p>The application is built using Express and is deployed on Heroku.</p> -<p>Refer to the <a href="https://github.com/onshape-public/app-gltf-viewer">gltf-viewer-app README</a> for instructions on running this sample app.</p> \ No newline at end of file +Sample Apps onhttps://onshape-public.github.io/docs/tutorials/Recent content in Sample Apps onHugoen-usMon, 01 Jan 0001 00:00:00 +0000Sync Data and Metadatahttps://onshape-public.github.io/docs/tutorials/sync/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/sync/The first business case is probably the most common, “How do I sync data that I create in Onshape with my ERP or PLM system?”. There could be many reasons why you would want to sync data between two different systems. Primarily Onshape is a system that creates new data. This data is created by designers as they perform their daily tasks. While the designer works primarily in Onshape, the actual data that they create does not exist in a vacuum, it is used by other departments, other processes within the organization.Sync Releases and Revisionshttps://onshape-public.github.io/docs/tutorials/releases/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/releases/This tutorials builds off the Sync Data and Metadata tutorial. Please complete that one before starting on this one. +In this case, we’ll be looking at the ability for Onshape to sync its release data with an external system and for that system to send information back to Onshape with regards to released data. +This specific business case will look at what happens when you wish for a PLM system to control the release of data instead of Onshape having that control – this is in fact a common use case.Generate Derivative Fileshttps://onshape-public.github.io/docs/tutorials/derivative/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/derivative/This tutorials builds off the Sync Releases and Revisions tutorial. Please complete that one before starting on this one. +It’s clear by now that Onshape doesn’t use files to store its data, instead it is a data driven solution that is always up to date. Files are a snapshot in time that provide a view of the design at a specific point in time - such as at a release or version.Create an Extensionhttps://onshape-public.github.io/docs/tutorials/createextension/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/createextension/In this example, you will create a custom web page (as shown in the image below) that is displayed in the right-hand fly-out panel. This interface displays metadata pulled from a third-party system when a part in Onshape is selected. This interface can also update metadata in Onshape through the Update functionality. +You can follow along with the steps below with this video: Define the extension This tutorials builds off the Generate Derivative Files tutorial.glTF Viewerhttps://onshape-public.github.io/docs/tutorials/gltf/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/gltf/The GLTF Viewer is a sample application that demonstrates: +How to fetch a glTF representation of an Onshape model How to create an app that runs as a tab inside an Onshape document OAuth2 authentication Use of REST APIs Use of document context The application is built using Express and is deployed on Heroku. +Refer to the gltf-viewer-app README for instructions on running this sample app. \ No newline at end of file diff --git a/docs/tutorials/releases/index.html b/docs/tutorials/releases/index.html index 497d905..65200ed 100644 --- a/docs/tutorials/releases/index.html +++ b/docs/tutorials/releases/index.html @@ -1,12 +1,12 @@ -Sync Releases and Revisions | Sync Releases and Revisions |

    Sync Releases and Revisions

    This tutorials builds off the Sync Data and Metadata tutorial. Please complete that one before starting on this one.

    In this case, we’ll be looking at the ability for Onshape to sync its +This specific business case will look at what happens when you wish for a PLM system to control the release of data instead of Onshape having that control – this is in fact a common use case.">

    Sync Releases and Revisions

    This tutorials builds off the Sync Data and Metadata tutorial. Please complete that one before starting on this one.

    In this case, we’ll be looking at the ability for Onshape to sync its release data with an external system and for that system to send information back to Onshape with regards to released data.

    This specific business case will look at what happens when you wish for a PLM system to control the release of data instead of Onshape having @@ -183,4 +183,4 @@ for this reason we required the property ID of the Comment field – which we also previously stored in our release object in the database.

    Graphical user interface, text, application Description automatically generated

    Figure 45 - Release completed automatically in Onshape

    Graphical user interface, text, application, email Description automatically generated

    Figure 46 - Release -comments Updated from third-party system

    \ No newline at end of file +comments Updated from third-party system

    \ No newline at end of file diff --git a/docs/tutorials/sync/index.html b/docs/tutorials/sync/index.html index 4c01ee5..c451904 100644 --- a/docs/tutorials/sync/index.html +++ b/docs/tutorials/sync/index.html @@ -1,7 +1,4 @@ -Sync Data and Metadata |

    Sync Data and Metadata

    The first business case is probably the most common, “How do I sync data +Sync Data and Metadata |

    \ No newline at end of file +Candidate Part Number generation

    \ No newline at end of file diff --git a/index.html b/index.html index 5cc2441..42f727e 100644 --- a/index.html +++ b/index.html @@ -1,27 +1,10 @@ - -

    Welcome to the Onshape Developer Documentation. You can find resources here for developing applications that integrate with Onshape.

    The Onshape Developer Documentation consists of four parts:

    API Guide + +

    Welcome to the Onshape Developer Documentation. You can find resources here for developing applications that integrate with Onshape.

    The Onshape Developer Documentation consists of four parts:

    API Guide API Explorer
    Developer Portal -Sample Code

    If you are new to Onshape development, start with the API Guide.

    Guides
    \ No newline at end of file +Sample Code

    If you are new to Onshape development, start with the API Guide.

    Guides
    \ No newline at end of file diff --git a/index.xml b/index.xml index 2afba9f..437477c 100644 --- a/index.xml +++ b/index.xml @@ -1 +1,47 @@ -– Onshape Developer Documentationhttps://onshape-public.github.io/Recent content in Onshape Developer Documentation onHugo -- gohugo.ioen-usThu, 15 Aug 2024 00:00:00 +0000 \ No newline at end of file +Onshape Developer Documentation onhttps://onshape-public.github.io/Recent content in Onshape Developer Documentation onHugoen-usThu, 15 Aug 2024 00:00:00 +0000API Explorerhttps://onshape-public.github.io/docs/api-intro/explorer/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/explorer/We document all available Onshape REST API endpoints in our Glassworks API Explorer: +https://cad.onshape.com/glassworks/explorer/ +This API Explorer site enables you to run API requests directly within its interface and provides the output from the API call. To try an endpoint in the API Explorer, follow these steps or follow along with the video below: +Open this public Onshape document in your browser: https://cad.onshape.com/documents/e60c4803eaf2ac8be492c18e/w/d2558da712764516cc9fec62/e/6bed6b43463f6a46a37b4a22 Open the API Explorer in a new browser tab: https://cad.Architecturehttps://onshape-public.github.io/docs/api-intro/architecture/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/architecture/Design in Onshape typically beings with a document, which is the container that includes all content related to a specific design. All data in an Onshape document is stored in Elements. Part Studios and Assemblies are two of the most common element types in a design. Throughout the design process, creating versions can be useful for product development management while working on the “Main” workspace. See also: +The API Introduction page for information on how documents, workspaces, and elements are assembled into a URL.Quick Starthttps://onshape-public.github.io/docs/api-intro/quickstart/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/api-intro/quickstart/In this example, we will call an Onshape REST API endpoint to send a document name to our console. Please note that the sample shown on this page is only designed to be used as a quick start guide and does not represent a full Onshape application. +System Requirements You must be signed in to your Onshape account at https://cad.onshape.com (or https://companyName.onshape.com for Enterprise accounts). This example is coded in Python.Why Onshape?https://onshape-public.github.io/docs/api-intro/whyonshape/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/api-intro/whyonshape/Why Onshape? As long as there have been applications that manage organizational data into a database, there has been a need to share that data between different departments and therefore, usually, different systems. In a typical design/manufacturing organization, there could be at least four or five mission-critical databases that manage the data for different departments and for different stages in the product’s lifecycle. +Initially, these systems provide the capabilities required by their consumers (i.OAuthhttps://onshape-public.github.io/docs/auth/oauth/Mon, 18 May 2020 20:39:14 -0400https://onshape-public.github.io/docs/auth/oauth/See the gltf-viewer-app for a working example of OAuth2. +📘 Note +All applications submitted to the Onshape App Store (Onshape Apps) must use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.API Keyshttps://onshape-public.github.io/docs/auth/apikeys/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/auth/apikeys/📘 Note +All applications submitted to the Onshape App Store (Onshape Apps) must follow the instructions on the OAuth2 page and use OAuth2 for authorization. Automation scripts (or applications not meant for the Onshape App Store) may use either OAuth2 or API Keys for authentication. OAuth2 allows applications to call Onshape APIs on behalf of the users of the application; API keys will only perform operations on behalf of the Onshape user who generated the API keys.Assemblieshttps://onshape-public.github.io/docs/api-adv/assemblies/Tue, 13 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/assemblies/This page describes the APIs Onshape provides for working with assemblies. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2. This documentation refers to Onshape IDs in the following format: {did}, {wid}, {eid}, {pid}, {otherId}.Associativityhttps://onshape-public.github.io/docs/api-adv/associativity/Mon, 18 May 2020 20:28:26 -0400https://onshape-public.github.io/docs/api-adv/associativity/Onshape does not expose a persistent ID for any of these entities. When the model changes, the ID may change. Therefore, Onshape provides an API to enable mapping IDs from a previous microversion to the current microversion. Assuming a simple case of maintaining associativity for a face, an abstract workflow might be: +Read the tessellated model data. Select the face of interest. Store the Face ID and Document Microversion ID for the face.Billinghttps://onshape-public.github.io/docs/api-adv/billing/Mon, 18 May 2020 20:29:36 -0400https://onshape-public.github.io/docs/api-adv/billing/This document describes APIs that will allow partners to interact with the Onshape billing system. +Please address questions to &ldquo;api-support@onshape.com&rdquo; for the fastest response. +Overview All billing is done through &ldquo;plans&rdquo; that are created in the Developer Portal. A “plan” has the following attributes: +Name (also called SKU) A unique (within your company) plan name Description A user-visible description of the plan Amount The cost of the plan (may be one-time or recurring, depending on the type) Type Monthly, One-time or Consumable Onshape defines three kinds of plans:Configurationshttps://onshape-public.github.io/docs/api-adv/configs/Fri, 05 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/configs/This page describes the APIs Onshape provides for working with Configurations. +You can use Configurations to create variations of entire Part Studios, Assemblies, specific parts and more. You can configure feature and parameter values, part properties, custom part properties, face and part appearances, and sketch text. Each Part Studio can have only one Configuration, but it can contain multiple Configuration inputs. The Configuration inputs you define for a Part Studio become options when inserting that Part Studio into an Assembly or Drawing.Drawingshttps://onshape-public.github.io/docs/api-adv/drawings/Thu, 12 Oct 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/drawings/This page describes the APIs Onshape provides for creating and manipulating Onshape drawings. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Featureshttps://onshape-public.github.io/docs/api-adv/featureaccess/Mon, 18 May 2020 20:37:28 -0400https://onshape-public.github.io/docs/api-adv/featureaccess/This page describes the APIs Onshape provides for creating and manipulating features and the Feature List in a Part Studio. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Evaluating FeatureScripthttps://onshape-public.github.io/docs/api-adv/fs/Thu, 15 Aug 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/fs/This page describes some of the APIs Onshape provides for evaluating FeatureScript. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Import & Exporthttps://onshape-public.github.io/docs/api-adv/translation/Wed, 27 Sep 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/translation/This page describes the APIs Onshape provides for importing files to Onshape and exporting files from Onshape into different formats. We refer to the process of importing and exporting files from one format to another as translating the files. +Onshape provides several APIs to support this format translation. These fall into three categories: +Synchronous exports - Export Onshape content to glTF, STL, or Parasolid format. Asynchronous exports - Export Onshape content into a variety of other formats.Metadatahttps://onshape-public.github.io/docs/api-adv/metadata/Wed, 20 Dec 2023 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/metadata/This page describes the APIs Onshape provides for working with document metadata. +📘 Notes +This page provides sample code as curls. See the curl documentation for more information. All Onshape API calls must be properly authenticated by replacing the CREDENTIALS variable in the curls below. See the API Keys page for instructions and the Quick Start for an example. All applications submitted to the Onshape App Store must authenticate with OAuth2.Response Codeshttps://onshape-public.github.io/docs/api-adv/errors/Wed, 03 Apr 2024 00:00:00 +0000https://onshape-public.github.io/docs/api-adv/errors/This page details some of the response codes that may be returned by Onshape API endpoints. For each response code, we&rsquo;ve provided a brief description of the response and recommended next steps. +Success (2xx) The client call was successful. +200 - OK The client call was successful. No action needed. +204 - No Content The client call was successful, and there&rsquo;s nothing to return in the response body. The empty response body cannot be parsed.Extensionshttps://onshape-public.github.io/docs/app-dev/extensions/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/extensions/This page provides information for some of the more common options for embedding a third-party application into the Onshape interface. Onshape provides many options for embedding commands in various menus, fly-out panels, and elements. In this example, you will embed a custom web page inside a document’s right side fly-out panel. This interface will receive information from Onshape and push information from the panel back to Onshape, providing a complete, bi-directional integration scenario.Client Messaginghttps://onshape-public.github.io/docs/app-dev/clientmessaging/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-dev/clientmessaging/Application extensions and the Onshape JavaScript web client need to communicate directly, calling across the iframe containing the application extension using post message. +Onshape Client Messaging examples can be split into those that are initiated from the application extension and those that are initiated from the Onshape client. +Messages from the Extension These Client Messaging examples can be initiated from the application extension: +Click/close flyouts events: Notify the Onshape client that the user has clicked in the application extension, which should cause Onshape flyouts (versions, history, uploads, etc.Structured Storagehttps://onshape-public.github.io/docs/app-dev/structuredstorage/Mon, 18 May 2020 20:40:16 -0400https://onshape-public.github.io/docs/app-dev/structuredstorage/Sub Elements Onshape provides application elements storage that is controlled by applications through the API. These elements allow a set of named sub-elements. +The application can make changes to sub-elements independently or in arbitrary groupings. Changes may be wholesale replacements, or may be deltas. When performing a delta update, the application may post a full version as well, which allows the api to return a smaller number of deltas for subsequent queries.Webhookshttps://onshape-public.github.io/docs/app-dev/webhook/Mon, 18 May 2020 20:44:05 -0400https://onshape-public.github.io/docs/app-dev/webhook/This page describes the Webhook APIs Onshape provides for working with notifications. +Notifications are delivered to an application as an HTTP POST with a JSON body, which includes information about the identity of the registration request and information specific to the event and notification message. +Webhooks are an alternative approach to polling; instead of your application continuously asking Onshape for new information, webhooks automatically send a notification from Onshape any time an event you are subscribed to occurs.Launch Checklisthttps://onshape-public.github.io/docs/app-store/checklist/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/checklist/This checklist brings together the processes you should follow to ensure your app is launched successfully. While all tasks must be completed to submit your app to the Onshape App Store, the task sequence provided here is a suggestion. +1. Understand quality expectations These are to ensure that the Onshape App Store remains a trusted resource and that quality is maintained Review the Quality Considerations page, and reach out to the Developer Relations team with any questions.Testing Guidelineshttps://onshape-public.github.io/docs/app-store/testingguidelines/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/testingguidelines/The purpose of this document is to help you get your application and App Store entry ready for QA testing. +Application Release Workflow (ARW) Each application submitted to the Onshape App Store goes through a series of stage-gates: +Starting state: Ok to deploy to limited visibility on Production (Beta testing) Ok to make Public Goal state: Application is Public To advance to the next stage, your application must pass testing, and your App Store entry must pass review.Quality Considerationshttps://onshape-public.github.io/docs/app-store/quality/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/app-store/quality/Core App Quality Onshape users expect high-quality apps. App quality directly influences the long-term success of your app in terms of installs, user rating and reviews, engagement, and user retention. +This page helps you assess the core aspects of quality in your app, through a compact set of quality criteria and associated tests. All Onshape apps should meet these criteria. +Before publishing your apps, test them against these criteria to ensure that they function well.Sync Data and Metadatahttps://onshape-public.github.io/docs/tutorials/sync/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/sync/The first business case is probably the most common, “How do I sync data that I create in Onshape with my ERP or PLM system?”. There could be many reasons why you would want to sync data between two different systems. Primarily Onshape is a system that creates new data. This data is created by designers as they perform their daily tasks. While the designer works primarily in Onshape, the actual data that they create does not exist in a vacuum, it is used by other departments, other processes within the organization.Sync Releases and Revisionshttps://onshape-public.github.io/docs/tutorials/releases/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/releases/This tutorials builds off the Sync Data and Metadata tutorial. Please complete that one before starting on this one. +In this case, we’ll be looking at the ability for Onshape to sync its release data with an external system and for that system to send information back to Onshape with regards to released data. +This specific business case will look at what happens when you wish for a PLM system to control the release of data instead of Onshape having that control – this is in fact a common use case.Generate Derivative Fileshttps://onshape-public.github.io/docs/tutorials/derivative/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/derivative/This tutorials builds off the Sync Releases and Revisions tutorial. Please complete that one before starting on this one. +It’s clear by now that Onshape doesn’t use files to store its data, instead it is a data driven solution that is always up to date. Files are a snapshot in time that provide a view of the design at a specific point in time - such as at a release or version.Create an Extensionhttps://onshape-public.github.io/docs/tutorials/createextension/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/createextension/In this example, you will create a custom web page (as shown in the image below) that is displayed in the right-hand fly-out panel. This interface displays metadata pulled from a third-party system when a part in Onshape is selected. This interface can also update metadata in Onshape through the Update functionality. +You can follow along with the steps below with this video: Define the extension This tutorials builds off the Generate Derivative Files tutorial.glTF Viewerhttps://onshape-public.github.io/docs/tutorials/gltf/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/tutorials/gltf/The GLTF Viewer is a sample application that demonstrates: +How to fetch a glTF representation of an Onshape model How to create an app that runs as a tab inside an Onshape document OAuth2 authentication Use of REST APIs Use of document context The application is built using Express and is deployed on Heroku. +Refer to the gltf-viewer-app README for instructions on running this sample app.Changeloghttps://onshape-public.github.io/docs/changelog/Mon, 01 Jan 0001 00:00:00 +0000https://onshape-public.github.io/docs/changelog/rel-1.185 - released 2024-08-12 Updated all endpoints that return a user summary (createdBy, modifiedBy) have a new boolean property isOnshapeSupport for use to separate Onshape support employee activities. Updated all bodyDetails, tessellatededged, and tessellatedfaces endpionts (parts and Part Studios) to include errorEnum vales for detecting new mate position, curve pattern and Simulation material checks. rel-1.184 - released 2024-07-19 Updated API version to V8, (https://cad.onshape.com/api/versions), A new microversion will not be created when a document restore operation results in a no-op. \ No newline at end of file diff --git a/js/click-to-copy.min.73478a7d4807698aed7e355eb23f9890ca18fea3158604c8471746d046702bad.js b/js/click-to-copy.min.73478a7d4807698aed7e355eb23f9890ca18fea3158604c8471746d046702bad.js new file mode 100644 index 0000000..0b95e45 --- /dev/null +++ b/js/click-to-copy.min.73478a7d4807698aed7e355eb23f9890ca18fea3158604c8471746d046702bad.js @@ -0,0 +1,2 @@ +let codeListings=document.querySelectorAll(".highlight > pre");for(let t=0;t{e.setAttribute(t,o[t])}),e.classList.add("fas","fa-copy","btn","btn-sm","td-click-to-copy");const i=new bootstrap.Tooltip(e);e.onclick=()=>{copyCode(s),e.setAttribute("data-bs-original-title","Copied!"),i.show()},e.onmouseout=()=>{e.setAttribute("data-bs-original-title","Copy to clipboard"),i.hide()};const n=document.createElement("div");n.classList.add("click-to-copy"),n.append(e),codeListings[t].insertBefore(n,s)}const copyCode=e=>{navigator.clipboard.writeText(e.textContent.trim()+` +`)} \ No newline at end of file diff --git a/js/main.min.69e2c1ae9320465ab10236d9ef752c6a4442c54b48b883b17c497b7c7d96a796.js b/js/main.min.69e2c1ae9320465ab10236d9ef752c6a4442c54b48b883b17c497b7c7d96a796.js new file mode 100644 index 0000000..5fea893 --- /dev/null +++ b/js/main.min.69e2c1ae9320465ab10236d9ef752c6a4442c54b48b883b17c497b7c7d96a796.js @@ -0,0 +1,5 @@ +/*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */(function(e,t){typeof exports=="object"&&typeof module!="undefined"?module.exports=t():typeof define=="function"&&define.amd?define(t):(e=typeof globalThis!="undefined"?globalThis:e||self,e.bootstrap=t())})(this,function(){"use strict";const C=new Map,pt={set(e,t,n){C.has(e)||C.set(e,new Map);const s=C.get(e);if(!s.has(t)&&s.size!==0){console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`);return}s.set(t,n)},get(e,t){return C.has(e)?C.get(e).get(t)||null:null},remove(e,t){if(!C.has(e))return;const n=C.get(e);n.delete(t),n.size===0&&C.delete(e)}},Jr=1e6,Xr=1e3,lt="transitionend",is=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,(e,t)=>`#${CSS.escape(t)}`)),e),Gr=e=>e==null?`${e}`:Object.prototype.toString.call(e).match(/\s([a-z]+)/i)[1].toLowerCase(),Yr=e=>{do e+=Math.floor(Math.random()*Jr);while(document.getElementById(e))return e},Pr=e=>{if(!e)return 0;let{transitionDuration:t,transitionDelay:n}=window.getComputedStyle(e);const s=Number.parseFloat(t),o=Number.parseFloat(n);return!s&&!o?0:(t=t.split(",")[0],n=n.split(",")[0],(Number.parseFloat(t)+Number.parseFloat(n))*Xr)},ns=e=>{e.dispatchEvent(new Event(lt))},g=e=>!!e&&typeof e=="object"&&(typeof e.jquery!="undefined"&&(e=e[0]),typeof e.nodeType!="undefined"),w=e=>g(e)?e.jquery?e[0]:e:typeof e=="string"&&e.length>0?document.querySelector(is(e)):null,R=e=>{if(!g(e)||e.getClientRects().length===0)return!1;const n=getComputedStyle(e).getPropertyValue("visibility")==="visible",t=e.closest("details:not([open])");if(!t)return n;if(t!==e){const n=e.closest("summary");if(n&&n.parentNode!==t)return!1;if(n===null)return!1}return n},y=e=>!e||e.nodeType!==Node.ELEMENT_NODE||!!e.classList.contains("disabled")||(typeof e.disabled!="undefined"?e.disabled:e.hasAttribute("disabled")&&e.getAttribute("disabled")!=="false"),es=e=>{if(!document.documentElement.attachShadow)return null;if(typeof e.getRootNode=="function"){const t=e.getRootNode();return t instanceof ShadowRoot?t:null}return e instanceof ShadowRoot?e:e.parentNode?es(e.parentNode):null},le=()=>{},oe=e=>{e.offsetHeight},Jn=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,Ue=[],Nr=e=>{document.readyState==="loading"?(Ue.length||document.addEventListener("DOMContentLoaded",()=>{for(const e of Ue)e()}),Ue.push(e)):e()},c=()=>document.documentElement.dir==="rtl",u=e=>{Nr(()=>{const t=Jn();if(t){const n=e.NAME,s=t.fn[n];t.fn[n]=e.jQueryInterface,t.fn[n].Constructor=e,t.fn[n].noConflict=()=>(t.fn[n]=s,e.jQueryInterface)}})},o=(e,t=[],n=e)=>typeof e=="function"?e(...t):n,Zn=(e,t,n=!0)=>{if(!n){o(e);return}const a=5,r=Pr(t)+a;let s=!1;const i=({target:n})=>{if(n!==t)return;s=!0,t.removeEventListener(lt,i),o(e)};t.addEventListener(lt,i),setTimeout(()=>{s||ns(t)},r)},$e=(e,t,n,s)=>{const i=e.length;let o=e.indexOf(t);return o===-1?!n&&s?e[i-1]:e[0]:(o+=n?1:-1,s&&(o=(o+i)%i),e[Math.max(0,Math.min(o,i-1))])},zr=/[^.]*(?=\..*)\.|.*/,Tr=/\..*/,Ar=/::\d+$/,De={};let qn=1;const Un={mouseenter:"mouseover",mouseleave:"mouseout"},Er=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function Hn(e,t){return t&&`${t}::${qn++}`||e.uidEvent||qn++}function Fn(e){const t=Hn(e);return e.uidEvent=t,De[t]=De[t]||{},De[t]}function xr(t,n){return function s(o){return ht(o,{delegateTarget:t}),s.oneOff&&e.off(t,o.type,n),n.apply(t,[o])}}function Or(t,n,s){return function o(i){const a=t.querySelectorAll(n);for(let{target:r}=i;r&&r!==this;r=r.parentNode)for(const c of a){if(c!==r)continue;return ht(i,{delegateTarget:r}),o.oneOff&&e.off(t,i.type,n,s),s.apply(r,[i])}}}function Sn(e,t,n=null){return Object.values(e).find(e=>e.callable===t&&e.delegationSelector===n)}function An(e,t,n){const o=typeof t=="string",i=o?n:t||n;let s=xn(e);return Er.has(s)||(s=e),[o,i,s]}function Cn(e,t,n,s,o){if(typeof t!="string"||!e)return;let[r,i,c]=An(t,n,s);if(t in Un){const e=e=>function(t){if(!t.relatedTarget||t.relatedTarget!==t.delegateTarget&&!t.delegateTarget.contains(t.relatedTarget))return e.call(this,t)};i=e(i)}const d=Fn(e),u=d[c]||(d[c]={}),l=Sn(u,i,r?n:null);if(l){l.oneOff=l.oneOff&&o;return}const h=Hn(i,t.replace(zr,"")),a=r?Or(e,n,i):xr(e,i);a.delegationSelector=r?n:null,a.callable=i,a.oneOff=o,a.uidEvent=h,u[h]=a,e.addEventListener(c,a,r)}function dt(e,t,n,s,o){const i=Sn(t[n],s,o);if(!i)return;e.removeEventListener(n,i,Boolean(o)),delete t[n][i.uidEvent]}function wr(e,t,n,s){const o=t[n]||{};for(const[a,i]of Object.entries(o))a.includes(s)&&dt(e,t,n,i.callable,i.delegationSelector)}function xn(e){return e=e.replace(Tr,""),Un[e]||e}const e={on(e,t,n,s){Cn(e,t,n,s,!1)},one(e,t,n,s){Cn(e,t,n,s,!0)},off(e,t,n,s){if(typeof t!="string"||!e)return;const[c,a,i]=An(t,n,s),l=i!==t,o=Fn(e),r=o[i]||{},d=t.startsWith(".");if(typeof a!="undefined"){if(!Object.keys(r).length)return;dt(e,o,i,a,c?n:null);return}if(d)for(const n of Object.keys(o))wr(e,o,n,t.slice(1));for(const[s,n]of Object.entries(r)){const a=s.replace(Ar,"");(!l||t.includes(a))&&dt(e,o,i,n.callable,n.delegationSelector)}},trigger(e,t,n){if(typeof t!="string"||!e)return null;const i=Jn(),l=xn(t),d=t!==l;let s=null,a=!0,r=!0,c=!1;d&&i&&(s=i.Event(t,n),i(e).trigger(s),a=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),c=s.isDefaultPrevented());const o=ht(new Event(t,{bubbles:a,cancelable:!0}),n);return c&&o.preventDefault(),r&&e.dispatchEvent(o),o.defaultPrevented&&s&&s.preventDefault(),o}};function ht(e,t={}){for(const[n,s]of Object.entries(t))try{e[n]=s}catch{Object.defineProperty(e,n,{configurable:!0,get(){return s}})}return e}function On(e){if(e==="true")return!0;if(e==="false")return!1;if(e===Number(e).toString())return Number(e);if(e===""||e==="null")return null;if(typeof e!="string")return e;try{return JSON.parse(decodeURIComponent(e))}catch{return e}}function Le(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}const v={setDataAttribute(e,t,n){e.setAttribute(`data-bs-${Le(t)}`,n)},removeDataAttribute(e,t){e.removeAttribute(`data-bs-${Le(t)}`)},getDataAttributes(e){if(!e)return{};const t={},n=Object.keys(e.dataset).filter(e=>e.startsWith("bs")&&!e.startsWith("bsConfig"));for(const o of n){let s=o.replace(/^bs/,"");s=s.charAt(0).toLowerCase()+s.slice(1,s.length),t[s]=On(e.dataset[o])}return t},getDataAttribute(e,t){return On(e.getAttribute(`data-bs-${Le(t)}`))}};class se{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(e){return e=this._mergeConfigObj(e),e=this._configAfterMerge(e),this._typeCheckConfig(e),e}_configAfterMerge(e){return e}_mergeConfigObj(e,t){const n=g(t)?v.getDataAttribute(t,"config"):{};return{...this.constructor.Default,...typeof n=="object"?n:{},...g(t)?v.getDataAttributes(t):{},...typeof e=="object"?e:{}}}_typeCheckConfig(e,t=this.constructor.DefaultType){for(const[n,s]of Object.entries(t)){const o=e[n],i=g(o)?"element":Gr(o);if(!new RegExp(s).test(i))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${i}" but expected type "${s}".`)}}}const _r="5.3.3";class h extends se{constructor(e,t){if(super(),e=w(e),!e)return;this._element=e,this._config=this._getConfig(t),pt.set(this._element,this.constructor.DATA_KEY,this)}dispose(){pt.remove(this._element,this.constructor.DATA_KEY),e.off(this._element,this.constructor.EVENT_KEY);for(const e of Object.getOwnPropertyNames(this))this[e]=null}_queueCallback(e,t,n=!0){Zn(e,t,n)}_getConfig(e){return e=this._mergeConfigObj(e,this._element),e=this._configAfterMerge(e),this._typeCheckConfig(e),e}static getInstance(e){return pt.get(w(e),this.DATA_KEY)}static getOrCreateInstance(e,t={}){return this.getInstance(e)||new this(e,typeof t=="object"?t:null)}static get VERSION(){return _r}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(e){return`${e}${this.EVENT_KEY}`}}const tt=e=>{let t=e.getAttribute("data-bs-target");if(!t||t==="#"){let n=e.getAttribute("href");if(!n||!n.includes("#")&&!n.startsWith("."))return null;n.includes("#")&&!n.startsWith("#")&&(n=`#${n.split("#")[1]}`),t=n&&n!=="#"?n.trim():null}return t?t.split(",").map(e=>is(e)).join(","):null},t={find(e,t=document.documentElement){return[].concat(...Element.prototype.querySelectorAll.call(t,e))},findOne(e,t=document.documentElement){return Element.prototype.querySelector.call(t,e)},children(e,t){return[].concat(...e.children).filter(e=>e.matches(t))},parents(e,t){const s=[];let n=e.parentNode.closest(t);for(;n;)s.push(n),n=n.parentNode.closest(t);return s},prev(e,t){let n=e.previousElementSibling;for(;n;){if(n.matches(t))return[n];n=n.previousElementSibling}return[]},next(e,t){let n=e.nextElementSibling;for(;n;){if(n.matches(t))return[n];n=n.nextElementSibling}return[]},focusableChildren(e){const t=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(e=>`${e}:not([tabindex^="-"])`).join(",");return this.find(t,e).filter(e=>!y(e)&&R(e))},getSelectorFromElement(e){const n=tt(e);return n?t.findOne(n)?n:null:null},getElementFromSelector(e){const n=tt(e);return n?t.findOne(n):null},getMultipleElementsFromSelector(e){const n=tt(e);return n?t.find(n):[]}},_e=(n,s="hide")=>{const i=`click.dismiss${n.EVENT_KEY}`,o=n.NAME;e.on(document,i,`[data-bs-dismiss="${o}"]`,function(e){if(["A","AREA"].includes(this.tagName)&&e.preventDefault(),y(this))return;const i=t.getElementFromSelector(this)||this.closest(`.${o}`),a=n.getOrCreateInstance(i);a[s]()})},yr="alert",jr="bs.alert",jn=`.${jr}`,vr=`close${jn}`,cr=`closed${jn}`,ir="fade",Qa="show";class de extends h{static get NAME(){return yr}close(){const t=e.trigger(this._element,vr);if(t.defaultPrevented)return;this._element.classList.remove(Qa);const n=this._element.classList.contains(ir);this._queueCallback(()=>this._destroyElement(),this._element,n)}_destroyElement(){this._element.remove(),e.trigger(this._element,cr),this.dispose()}static jQueryInterface(e){return this.each(function(){const t=de.getOrCreateInstance(this);if(typeof e!="string")return;if(t[e]===void 0||e.startsWith("_")||e==="constructor")throw new TypeError(`No method named "${e}"`);t[e](this)})}}_e(de,"close"),u(de);const Ga="button",qa="bs.button",Wa=`.${qa}`,Ba=".data-api",Pa="active",fn='[data-bs-toggle="button"]',Ta=`click${Wa}${Ba}`;class fe extends h{static get NAME(){return Ga}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle(Pa))}static jQueryInterface(e){return this.each(function(){const t=fe.getOrCreateInstance(this);e==="toggle"&&t[e]()})}}e.on(document,Ta,fn,e=>{e.preventDefault();const t=e.target.closest(fn),n=fe.getOrCreateInstance(t);n.toggle()}),u(fe);const ga="swipe",P=".bs.swipe",pa=`touchstart${P}`,fa=`touchmove${P}`,ma=`touchend${P}`,ua=`pointerdown${P}`,la=`pointerup${P}`,Qi="touch",Gi="pen",Vi="pointer-event",Bi=40,Ri={endCallback:null,leftCallback:null,rightCallback:null},Ni={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class Re extends se{constructor(e,t){if(super(),this._element=e,!e||!Re.isSupported())return;this._config=this._getConfig(t),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents()}static get Default(){return Ri}static get DefaultType(){return Ni}static get NAME(){return ga}dispose(){e.off(this._element,P)}_start(e){if(!this._supportPointerEvents){this._deltaX=e.touches[0].clientX;return}this._eventIsPointerPenTouch(e)&&(this._deltaX=e.clientX)}_end(e){this._eventIsPointerPenTouch(e)&&(this._deltaX=e.clientX-this._deltaX),this._handleSwipe(),o(this._config.endCallback)}_move(e){this._deltaX=e.touches&&e.touches.length>1?0:e.touches[0].clientX-this._deltaX}_handleSwipe(){const e=Math.abs(this._deltaX);if(e<=Bi)return;const t=e/this._deltaX;if(this._deltaX=0,!t)return;o(t>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(e.on(this._element,ua,e=>this._start(e)),e.on(this._element,la,e=>this._end(e)),this._element.classList.add(Vi)):(e.on(this._element,pa,e=>this._start(e)),e.on(this._element,fa,e=>this._move(e)),e.on(this._element,ma,e=>this._end(e)))}_eventIsPointerPenTouch(e){return this._supportPointerEvents&&(e.pointerType===Gi||e.pointerType===Qi)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const Di="carousel",zi="bs.carousel",_=`.${zi}`,Kt=".data-api",Mi="ArrowLeft",Si="ArrowRight",Ei=500,ie="next",U="prev",K="left",ke="right",ji=`slide${_}`,Be=`slid${_}`,bi=`keydown${_}`,gi=`mouseenter${_}`,li=`mouseleave${_}`,ci=`dragstart${_}`,si=`load${_}${Kt}`,ei=`click${_}${Kt}`,Pt="carousel",Ce="active",Jo="slide",Zo="carousel-item-end",Qo="carousel-item-start",Xo="carousel-item-next",Go="carousel-item-prev",zt=".active",gt=".carousel-item",Ko=zt+gt,Bo=".carousel-item img",Po=".carousel-indicators",No="[data-bs-slide], [data-bs-slide-to]",Do='[data-bs-ride="carousel"]',To={[Mi]:ke,[Si]:K},Fo={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},vo={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class ee extends h{constructor(e,n){super(e,n),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=t.findOne(Po,this._element),this._addEventListeners(),this._config.ride===Pt&&this.cycle()}static get Default(){return Fo}static get DefaultType(){return vo}static get NAME(){return Di}next(){this._slide(ie)}nextWhenVisible(){!document.hidden&&R(this._element)&&this.next()}prev(){this._slide(U)}pause(){this._isSliding&&ns(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){if(!this._config.ride)return;if(this._isSliding){e.one(this._element,Be,()=>this.cycle());return}this.cycle()}to(t){const n=this._getItems();if(t>n.length-1||t<0)return;if(this._isSliding){e.one(this._element,Be,()=>this.to(t));return}const s=this._getItemIndex(this._getActive());if(s===t)return;const o=t>s?ie:U;this._slide(o,n[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(e){return e.defaultInterval=e.interval,e}_addEventListeners(){this._config.keyboard&&e.on(this._element,bi,e=>this._keydown(e)),this._config.pause==="hover"&&(e.on(this._element,gi,()=>this.pause()),e.on(this._element,li,()=>this._maybeEnableCycle())),this._config.touch&&Re.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const n of t.find(Bo,this._element))e.on(n,ci,e=>e.preventDefault());const n=()=>{if(this._config.pause!=="hover")return;this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),Ei+this._config.interval)},s={leftCallback:()=>this._slide(this._directionToOrder(K)),rightCallback:()=>this._slide(this._directionToOrder(ke)),endCallback:n};this._swipeHelper=new Re(this._element,s)}_keydown(e){if(/input|textarea/i.test(e.target.tagName))return;const t=To[e.key];t&&(e.preventDefault(),this._slide(this._directionToOrder(t)))}_getItemIndex(e){return this._getItems().indexOf(e)}_setActiveIndicatorElement(e){if(!this._indicatorsElement)return;const s=t.findOne(zt,this._indicatorsElement);s.classList.remove(Ce),s.removeAttribute("aria-current");const n=t.findOne(`[data-bs-slide-to="${e}"]`,this._indicatorsElement);n&&(n.classList.add(Ce),n.setAttribute("aria-current","true"))}_updateInterval(){const e=this._activeElement||this._getActive();if(!e)return;const t=Number.parseInt(e.getAttribute("data-bs-interval"),10);this._config.interval=t||this._config.defaultInterval}_slide(t,n=null){if(this._isSliding)return;const o=this._getActive(),a=t===ie,s=n||$e(this._getItems(),o,a,this._config.wrap);if(s===o)return;const c=this._getItemIndex(s),l=n=>e.trigger(this._element,n,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(o),to:c}),d=l(ji);if(d.defaultPrevented)return;if(!o||!s)return;const u=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(c),this._activeElement=s;const i=a?Qo:Zo,r=a?Xo:Go;s.classList.add(r),oe(s),o.classList.add(i),s.classList.add(i);const h=()=>{s.classList.remove(i,r),s.classList.add(Ce),o.classList.remove(Ce,r,i),this._isSliding=!1,l(Be)};this._queueCallback(h,o,this._isAnimated()),u&&this.cycle()}_isAnimated(){return this._element.classList.contains(Jo)}_getActive(){return t.findOne(Ko,this._element)}_getItems(){return t.find(gt,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(e){return c()?e===K?U:ie:e===K?ie:U}_orderToDirection(e){return c()?e===U?K:ke:e===U?ke:K}static jQueryInterface(e){return this.each(function(){const t=ee.getOrCreateInstance(this,e);if(typeof e=="number"){t.to(e);return}if(typeof e=="string"){if(t[e]===void 0||e.startsWith("_")||e==="constructor")throw new TypeError(`No method named "${e}"`);t[e]()}})}}e.on(document,ei,No,function(e){const s=t.getElementFromSelector(this);if(!s||!s.classList.contains(Pt))return;e.preventDefault();const n=ee.getOrCreateInstance(s),o=this.getAttribute("data-bs-slide-to");if(o){n.to(o),n._maybeEnableCycle();return}if(v.getDataAttribute(this,"slide")==="next"){n.next(),n._maybeEnableCycle();return}n.prev(),n._maybeEnableCycle()}),e.on(window,si,()=>{const e=t.find(Do);for(const t of e)ee.getOrCreateInstance(t)}),u(ee);const rs="collapse",po="bs.collapse",J=`.${po}`,co=".data-api",ao=`show${J}`,io=`shown${J}`,Js=`hide${J}`,Qs=`hidden${J}`,Gs=`click${J}${co}`,ct="show",L="collapse",pe="collapsing",Ys="collapsed",Ks=`:scope .${L} .${L}`,Us="collapse-horizontal",Ws="width",$s="height",Vs=".collapse.show, .collapse.collapsing",nt='[data-bs-toggle="collapse"]',Bs={parent:null,toggle:!0},Is={parent:"(null|element)",toggle:"boolean"};class te extends h{constructor(e,n){super(e,n),this._isTransitioning=!1,this._triggerArray=[];const s=t.find(nt);for(const e of s){const n=t.getSelectorFromElement(e),o=t.find(n).filter(e=>e===this._element);n!==null&&o.length&&this._triggerArray.push(e)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Bs}static get DefaultType(){return Is}static get NAME(){return rs}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let n=[];if(this._config.parent&&(n=this._getFirstLevelChildren(Vs).filter(e=>e!==this._element).map(e=>te.getOrCreateInstance(e,{toggle:!1}))),n.length&&n[0]._isTransitioning)return;const s=e.trigger(this._element,ao);if(s.defaultPrevented)return;for(const e of n)e.hide();const t=this._getDimension();this._element.classList.remove(L),this._element.classList.add(pe),this._element.style[t]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const o=()=>{this._isTransitioning=!1,this._element.classList.remove(pe),this._element.classList.add(L,ct),this._element.style[t]="",e.trigger(this._element,io)},i=t[0].toUpperCase()+t.slice(1),a=`scroll${i}`;this._queueCallback(o,this._element,!0),this._element.style[t]=`${this._element[a]}px`}hide(){if(this._isTransitioning||!this._isShown())return;const s=e.trigger(this._element,Js);if(s.defaultPrevented)return;const n=this._getDimension();this._element.style[n]=`${this._element.getBoundingClientRect()[n]}px`,oe(this._element),this._element.classList.add(pe),this._element.classList.remove(L,ct);for(const e of this._triggerArray){const n=t.getElementFromSelector(e);n&&!this._isShown(n)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0;const o=()=>{this._isTransitioning=!1,this._element.classList.remove(pe),this._element.classList.add(L),e.trigger(this._element,Qs)};this._element.style[n]="",this._queueCallback(o,this._element,!0)}_isShown(e=this._element){return e.classList.contains(ct)}_configAfterMerge(e){return e.toggle=Boolean(e.toggle),e.parent=w(e.parent),e}_getDimension(){return this._element.classList.contains(Us)?Ws:$s}_initializeChildren(){if(!this._config.parent)return;const e=this._getFirstLevelChildren(nt);for(const n of e){const s=t.getElementFromSelector(n);s&&this._addAriaAndCollapsedClass([n],this._isShown(s))}}_getFirstLevelChildren(e){const n=t.find(Ks,this._config.parent);return t.find(e,this._config.parent).filter(e=>!n.includes(e))}_addAriaAndCollapsedClass(e,t){if(!e.length)return;for(const n of e)n.classList.toggle(Ys,!t),n.setAttribute("aria-expanded",t)}static jQueryInterface(e){const t={};return typeof e=="string"&&/show|hide/.test(e)&&(t.toggle=!1),this.each(function(){const n=te.getOrCreateInstance(this,t);if(typeof e=="string"){if(typeof n[e]=="undefined")throw new TypeError(`No method named "${e}"`);n[e]()}})}}e.on(document,Gs,nt,function(e){(e.target.tagName==="A"||e.delegateTarget&&e.delegateTarget.tagName==="A")&&e.preventDefault();for(const e of t.getMultipleElementsFromSelector(this))te.getOrCreateInstance(e,{toggle:!1}).toggle()}),u(te);var k,A,Q,Nn,In,ae,Yn,Xn,ot,Tt,Ft,St,At,je,s="top",a="bottom",i="right",n="left",Ee="auto",Y=[s,a,i,n],T="start",q="end",Vt="clippingParents",Ve="viewport",I="popper",Ut="reference",Te=Y.reduce(function(e,t){return e.concat([t+"-"+T,t+"-"+q])},[]),Xe=[].concat(Y,[Ee]).reduce(function(e,t){return e.concat([t,t+"-"+T,t+"-"+q])},[]),Yt="beforeRead",Gt="read",Xt="afterRead",Qt="beforeMain",Zt="main",Jt="afterMain",en="beforeWrite",tn="write",nn="afterWrite",sn=[Yt,Gt,Xt,Qt,Zt,Jt,en,tn,nn];function f(e){return e?(e.nodeName||"").toLowerCase():null}function r(e){if(e==null)return window;if(e.toString()!=="[object Window]"){var t=e.ownerDocument;return t?t.defaultView||window:window}return e}function D(e){var t=r(e).Element;return e instanceof t||e instanceof Element}function l(e){var t=r(e).HTMLElement;return e instanceof t||e instanceof HTMLElement}function Me(e){if(typeof ShadowRoot=="undefined")return!1;var t=r(e).ShadowRoot;return e instanceof t||e instanceof ShadowRoot}function Hs(e){var t=e.state;Object.keys(t.elements).forEach(function(e){var o=t.styles[e]||{},s=t.attributes[e]||{},n=t.elements[e];if(!l(n)||!f(n))return;Object.assign(n.style,o),Object.keys(s).forEach(function(e){var t=s[e];t===!1?n.removeAttribute(e):n.setAttribute(e,t===!0?"":t)})})}function Ps(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach(function(e){var s=t.elements[e],o=t.attributes[e]||{},i=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]),a=i.reduce(function(e,t){return e[t]="",e},{});if(!l(s)||!f(s))return;Object.assign(s.style,a),Object.keys(o).forEach(function(e){s.removeAttribute(e)})})}}const st={name:"applyStyles",enabled:!0,phase:"write",fn:Hs,effect:Ps,requires:["computeStyles"]};function p(e){return e.split("-")[0]}k=Math.max,Q=Math.min,A=Math.round;function et(){var e=navigator.userAgentData;return e!=null&&e.brands&&Array.isArray(e.brands)?e.brands.map(function(e){return e.brand+"/"+e.version}).join(" "):navigator.userAgent}function bn(){return!/^((?!chrome|android).)*safari/i.test(et())}function X(e,t,n){t===void 0&&(t=!1),n===void 0&&(n=!1),s=e.getBoundingClientRect(),o=1,i=1,t&&l(e)&&(o=e.offsetWidth>0?A(s.width)/e.offsetWidth||1:1,i=e.offsetHeight>0?A(s.height)/e.offsetHeight||1:1);var s,o,i,f=D(e)?r(e):window,a=f.visualViewport,u=!bn()&&n,c=(s.left+(u&&a?a.offsetLeft:0))/o,d=(s.top+(u&&a?a.offsetTop:0))/i,h=s.width/o,m=s.height/i;return{width:h,height:m,top:d,right:c+h,bottom:d+m,left:c,x:c,y:d}}function ut(e){var t=X(e),n=e.offsetWidth,s=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-s)<=1&&(s=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:s}}function _n(e,t){var n,s=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(s&&Me(s)){n=t;do{if(n&&e.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function j(e){return r(e).getComputedStyle(e)}function Rs(e){return["table","td","th"].indexOf(f(e))>=0}function E(e){return((D(e)?e.ownerDocument:e.document)||window.document).documentElement}function ge(e){return f(e)==="html"?e:e.assignedSlot||e.parentNode||(Me(e)?e.host:null)||E(e)}function En(e){return!l(e)||j(e).position==="fixed"?null:e.offsetParent}function As(e){var t,n,o,s=/firefox/i.test(et()),i=/Trident/i.test(et());if(i&&l(e)&&(o=j(e),o.position==="fixed"))return null;for(t=ge(e),Me(t)&&(t=t.host);l(t)&&["html","body"].indexOf(f(t))<0;){if(n=j(t),n.transform!=="none"||n.perspective!=="none"||n.contain==="paint"||["transform","perspective"].indexOf(n.willChange)!==-1||s&&n.willChange==="filter"||s&&n.filter&&n.filter!=="none")return t;t=t.parentNode}return null}function ce(e){for(var n=r(e),t=En(e);t&&Rs(t)&&j(t).position==="static";)t=En(t);return t&&(f(t)==="html"||f(t)==="body"&&j(t).position==="static")?n:t||As(e)||n}function Qe(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function re(e,t,n){return k(e,Q(t,n))}function Cs(e,t,n){var s=re(e,t,n);return s>n?n:s}function Tn(){return{top:0,right:0,bottom:0,left:0}}function zn(e){return Object.assign({},Tn(),e)}function Dn(e,t){return t.reduce(function(t,n){return t[n]=e,t},{})}Nn=function(t,n){return t=typeof t=="function"?t(Object.assign({},n.rects,{placement:n.placement})):t,zn(typeof t!="number"?t:Dn(t,Y))};function Os(e){var r,c,d,u,f,g,v,b,j,y,_,O,x,C,E,t=e.state,S=e.name,A=e.options,h=t.elements.arrow,m=t.modifiersData.popperOffsets,w=p(t.placement),o=Qe(w),k=[n,i].indexOf(w)>=0,l=k?"height":"width";if(!h||!m)return;g=Nn(A.padding,t),v=ut(h),b=o==="y"?s:n,j=o==="y"?a:i,y=t.rects.reference[l]+t.rects.reference[o]-m[o]-t.rects.popper[l],_=m[o]-t.rects.reference[o],c=ce(h),f=c?o==="y"?c.clientHeight||0:c.clientWidth||0:0,O=y/2-_/2,x=g[b],C=f-v[l]-g[j],u=f/2-v[l]/2+O,d=re(x,u,C),E=o,t.modifiersData[S]=(r={},r[E]=d,r.centerOffset=d-u,r)}function ys(e){var n=e.state,o=e.options,s=o.element,t=s===void 0?"[data-popper-arrow]":s;if(t==null)return;if(typeof t=="string"&&(t=n.elements.popper.querySelector(t),!t))return;if(!_n(n.elements.popper,t))return;n.elements.arrow=t}const Pn={name:"arrow",enabled:!0,phase:"main",fn:Os,effect:ys,requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function V(e){return e.split("-")[1]}In={top:"auto",right:"auto",bottom:"auto",left:"auto"};function bs(e,t){var s=e.x,o=e.y,n=t.devicePixelRatio||1;return{x:A(s*n)/n||0,y:A(o*n)/n||0}}function Vn(e){var c,u,h,p,g,b,y,T,z,f=e.popper,N=e.popperRect,d=e.placement,A=e.variation,m=e.offsets,x=e.position,v=e.gpuAcceleration,S=e.adaptive,_=e.roundOffsets,M=e.isFixed,L=m.x,t=L===void 0?0:L,D=m.y,o=D===void 0?0:D,C=typeof _=="function"?_({x:t,y:o}):{x:t,y:o},t=C.x,o=C.y,F=m.hasOwnProperty("x"),k=m.hasOwnProperty("y"),w=n,O=s,l=window;return S&&(c=ce(f),g="clientHeight",y="clientWidth",c===r(f)&&(c=E(f),j(c).position!=="static"&&x==="absolute"&&(g="scrollHeight",y="scrollWidth")),c=c,(d===s||(d===n||d===i)&&A===q)&&(O=a,T=M&&c===l&&l.visualViewport?l.visualViewport.height:c[g],o-=T-N.height,o*=v?1:-1),(d===n||(d===s||d===a)&&A===q)&&(w=i,z=M&&c===l&&l.visualViewport?l.visualViewport.width:c[y],t-=z-N.width,t*=v?1:-1)),p=Object.assign({position:x},S&&In),b=_===!0?bs({x:t,y:o},r(f)):{x:t,y:o},t=b.x,o=b.y,v?Object.assign({},p,(h={},h[O]=k?"0":"",h[w]=F?"0":"",h.transform=(l.devicePixelRatio||1)<=1?"translate("+t+"px, "+o+"px)":"translate3d("+t+"px, "+o+"px, 0)",h)):Object.assign({},p,(u={},u[O]=k?o+"px":"",u[w]=F?t+"px":"",u.transform="",u))}function vs(e){var t=e.state,n=e.options,s=n.gpuAcceleration,c=s===void 0||s,o=n.adaptive,l=o===void 0||o,i=n.roundOffsets,a=i===void 0||i,r={placement:p(t.placement),variation:V(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:c,isFixed:t.options.strategy==="fixed"};t.modifiersData.popperOffsets!=null&&(t.styles.popper=Object.assign({},t.styles.popper,Vn(Object.assign({},r,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:l,roundOffsets:a})))),t.modifiersData.arrow!=null&&(t.styles.arrow=Object.assign({},t.styles.arrow,Vn(Object.assign({},r,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:a})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})}const Fe={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:vs,data:{}};ae={passive:!0};function gs(e){var n=e.state,t=e.instance,s=e.options,o=s.scroll,i=o===void 0||o,a=s.resize,c=a===void 0||a,l=r(n.elements.popper),d=[].concat(n.scrollParents.reference,n.scrollParents.popper);return i&&d.forEach(function(e){e.addEventListener("scroll",t.update,ae)}),c&&l.addEventListener("resize",t.update,ae),function(){i&&d.forEach(function(e){e.removeEventListener("scroll",t.update,ae)}),c&&l.removeEventListener("resize",t.update,ae)}}const ze={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:gs,data:{}};Yn={left:"right",right:"left",bottom:"top",top:"bottom"};function Ae(e){return e.replace(/left|right|bottom|top/g,function(e){return Yn[e]})}Xn={start:"end",end:"start"};function Qn(e){return e.replace(/start|end/g,function(e){return Xn[e]})}function We(e){var t=r(e),n=t.pageXOffset,s=t.pageYOffset;return{scrollLeft:n,scrollTop:s}}function Ke(e){return X(E(e)).left+We(e).scrollLeft}function hs(e,t){var s,d=r(e),o=E(e),n=d.visualViewport,i=o.clientWidth,a=o.clientHeight,c=0,l=0;return n&&(i=n.width,a=n.height,s=bn(),(s||!s&&t==="fixed")&&(c=n.offsetLeft,l=n.offsetTop)),{width:i,height:a,x:c+Ke(e),y:l}}function us(e){var s,n=E(e),o=We(e),t=(s=e.ownerDocument)==null?void 0:s.body,i=k(n.scrollWidth,n.clientWidth,t?t.scrollWidth:0,t?t.clientWidth:0),r=k(n.scrollHeight,n.clientHeight,t?t.scrollHeight:0,t?t.clientHeight:0),a=-o.scrollLeft+Ke(e),c=-o.scrollTop;return j(t||n).direction==="rtl"&&(a+=k(n.clientWidth,t?t.clientWidth:0)-i),{width:i,height:r,x:a,y:c}}function Je(e){var t=j(e),n=t.overflow,s=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+s)}function ss(e){return["html","body","#document"].indexOf(f(e))>=0?e.ownerDocument.body:l(e)&&Je(e)?e:ss(ge(e))}function ne(e,t){t===void 0&&(t=[]);var s,n=ss(e),o=n===((s=e.ownerDocument)==null?void 0:s.body),i=r(n),a=o?[i].concat(i.visualViewport||[],Je(n)?n:[]):n,c=t.concat(a);return o?c:c.concat(ne(ge(a)))}function rt(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function Fi(e,t){var n=X(e,!1,t==="fixed");return n.top=n.top+e.clientTop,n.left=n.left+e.clientLeft,n.bottom=n.top+e.clientHeight,n.right=n.left+e.clientWidth,n.width=e.clientWidth,n.height=e.clientHeight,n.x=n.left,n.y=n.top,n}function Mt(e,t,n){return t===Ve?rt(hs(e,n)):D(t)?Fi(t,n):rt(us(E(e)))}function ls(e){var n=ne(ge(e)),s=["absolute","fixed"].indexOf(j(e).position)>=0,t=s&&l(e)?ce(e):e;return D(t)?n.filter(function(e){return D(e)&&_n(e,t)&&f(e)!=="body"}):[]}function ds(e,t,n,s){var a=t==="clippingParents"?ls(e):[].concat(t),i=[].concat(a,[n]),r=i[0],o=i.reduce(function(t,n){var o=Mt(e,n,s);return t.top=k(o.top,t.top),t.right=Q(o.right,t.right),t.bottom=Q(o.bottom,t.bottom),t.left=k(o.left,t.left),t},Mt(e,r,s));return o.width=o.right-o.left,o.height=o.bottom-o.top,o.x=o.left,o.y=o.top,o}function ts(e){var o,r,l,t=e.reference,c=e.element,d=e.placement,u=d?p(d):null,f=d?V(d):null,h=t.x+t.width/2-c.width/2,m=t.y+t.height/2-c.height/2;switch(u){case s:o={x:h,y:t.y-c.height};break;case a:o={x:h,y:t.y+t.height};break;case i:o={x:t.x+t.width,y:m};break;case n:o={x:t.x-c.width,y:m};break;default:o={x:t.x,y:t.y}}if(r=u?Qe(u):null,r!=null)switch(l=r==="y"?"height":"width",f){case T:o[r]=o[r]-(t[l]/2-c[l]/2);break;case q:o[r]=o[r]+(t[l]/2-c[l]/2);break}return o}function N(e,t){t===void 0&&(t={});var _,n=t,v=n.placement,j=v===void 0?e.placement:v,f=n.strategy,T=f===void 0?e.strategy:f,p=n.boundary,C=p===void 0?Vt:p,O=n.rootBoundary,F=O===void 0?Ve:O,x=n.elementContext,c=x===void 0?I:x,m=n.altBoundary,M=m!==void 0&&m,b=n.padding,d=b===void 0?0:b,o=zn(typeof d!="number"?d:Dn(d,Y)),S=c===I?Ut:I,w=e.rects.popper,h=e.elements[M?S:c],r=ds(D(h)?h:h.contextElement||E(e.elements.popper),C,F,T),y=X(e.elements.reference),k=ts({reference:y,element:w,strategy:"absolute",placement:j}),A=rt(Object.assign({},w,k)),l=c===I?A:y,u={top:r.top-l.top+o.top,bottom:l.bottom-r.bottom+o.bottom,left:r.left-l.left+o.left,right:l.right-r.right+o.right},g=e.modifiersData.offset;return c===I&&g&&(_=g[j],Object.keys(u).forEach(function(e){var t=[i,a].indexOf(e)>=0?1:-1,n=[s,a].indexOf(e)>=0?"y":"x";u[e]+=_[n]*t})),u}function ms(e,t){t===void 0&&(t={});var s,n=t,c=n.placement,l=n.boundary,d=n.rootBoundary,u=n.padding,h=n.flipVariations,i=n.allowedAutoPlacements,m=i===void 0?Xe:i,a=V(c),r=a?h?Te:Te.filter(function(e){return V(e)===a}):Y,o=r.filter(function(e){return m.indexOf(e)>=0});return o.length===0&&(o=r),s=o.reduce(function(t,n){return t[n]=N(e,{placement:n,boundary:l,rootBoundary:d,padding:u})[p(n)],t},{}),Object.keys(s).sort(function(e,t){return s[e]-s[t]})}function fs(e){if(p(e)===Ee)return[];var t=Ae(e);return[Qn(e),t,Qn(t)]}function ps(e){var t=e.state,o=e.options,C=e.name;if(t.modifiersData[C]._skip)return;for(var r,c,l,u,h,g,v,y,_,x,E,k,z,M=o.mainAxis,I=M===void 0||M,D=o.altAxis,P=D===void 0||D,R=o.fallbackPlacements,L=o.padding,w=o.boundary,O=o.rootBoundary,B=o.altBoundary,F=o.flipVariations,j=F===void 0||F,$=o.allowedAutoPlacements,d=t.options.placement,K=p(d),H=K===d,q=R||(H||!j?[Ae(d)]:fs(d)),f=[d].concat(q).reduce(function(e,n){return e.concat(p(n)===Ee?ms(t,{placement:n,boundary:w,rootBoundary:O,padding:L,flipVariations:j,allowedAutoPlacements:$}):n)},[]),U=t.rects.reference,W=t.rects.popper,A=new Map,S=!0,m=f[0],b=0;b=0,_=y?"width":"height",h=N(t,{placement:r,boundary:w,rootBoundary:O,altBoundary:B,padding:L}),l=y?g?i:n:g?a:s,U[_]>W[_]&&(l=Ae(l)),z=Ae(l),c=[],I&&c.push(h[v]<=0),P&&c.push(h[l]<=0,h[z]<=0),c.every(function(e){return e})){m=r,S=!1;break}A.set(r,c)}if(S)for(k=j?3:1,E=function(t){var n=f.find(function(e){var n=A.get(e);if(n)return n.slice(0,t).every(function(e){return e})});if(n)return m=n,"break"},u=k;u>0;u--)if(x=E(u),x==="break")break;t.placement!==m&&(t.modifiersData[C]._skip=!0,t.placement=m,t.reset=!0)}const Kn={name:"flip",enabled:!0,phase:"main",fn:ps,requiresIfExists:["offset"],data:{_skip:!1}};function $n(e,t,n){return n===void 0&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function Bn(e){return[s,i,a,n].some(function(t){return e[t]>=0})}function js(e){var t=e.state,a=e.name,r=t.rects.reference,c=t.rects.popper,l=t.modifiersData.preventOverflow,d=N(t,{elementContext:"reference"}),u=N(t,{altBoundary:!0}),n=$n(d,r),s=$n(u,c,l),o=Bn(n),i=Bn(s);t.modifiersData[a]={referenceClippingOffsets:n,popperEscapeOffsets:s,isReferenceHidden:o,hasPopperEscaped:i},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":o,"data-popper-escaped":i})}const Rn={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:js};function _s(e,t,o){var c=p(e),d=[n,s].indexOf(c)>=0?-1:1,l=typeof o=="function"?o(Object.assign({},t,{placement:e})):o,a=l[0],r=l[1],a=a||0,r=(r||0)*d;return[n,i].indexOf(c)>=0?{x:r,y:a}:{x:a,y:r}}function ws(e){var t=e.state,i=e.options,a=e.name,n=i.offset,r=n===void 0?[0,0]:n,s=Xe.reduce(function(e,n){return e[n]=_s(n,t.rects,r),e},{}),o=s[t.placement],c=o.x,l=o.y;t.modifiersData.popperOffsets!=null&&(t.modifiersData.popperOffsets.x+=c,t.modifiersData.popperOffsets.y+=l),t.modifiersData[a]=s}const Ln={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:ws};function xs(e){var t=e.state,n=e.name;t.modifiersData[n]=ts({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})}const He={name:"popperOffsets",enabled:!0,phase:"read",fn:xs,data:{}};function Es(e){return e==="x"?"y":"x"}function ks(e){var fe,r,h,P,H,$,W,U,Y,Z,J,ue,v,E,K,q,te,ne,x,oe,B,ae,le,G,me,c,f,w,A,M,F,z,D,R,I,X,t=e.state,l=e.options,be=e.name,pe=l.mainAxis,ge=pe===void 0||pe,se=l.altAxis,we=se!==void 0&&se,_e=l.boundary,ye=l.rootBoundary,ve=l.altBoundary,je=l.padding,de=l.tether,d=de===void 0||de,ie=l.tetherOffset,S=ie===void 0?0:ie,O=N(t,{boundary:_e,rootBoundary:ye,padding:je,altBoundary:ve}),ee=p(t.placement),C=V(t.placement),he=!C,o=Qe(ee),j=Es(o),b=t.modifiersData.popperOffsets,u=t.rects.reference,g=t.rects.popper,_=typeof S=="function"?S(Object.assign({},t.rects,{placement:t.placement})):S,m=typeof _=="number"?{mainAxis:_,altAxis:_}:Object.assign({mainAxis:0,altAxis:0},_),y=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,L={x:0,y:0};if(!b)return;ge&&(P=o==="y"?s:n,H=o==="y"?a:i,r=o==="y"?"height":"width",h=b[o],$=h+O[P],W=h-O[H],U=d?-g[r]/2:0,J=C===T?u[r]:g[r],Z=C===T?-g[r]:-u[r],Y=t.elements.arrow,ue=d&&Y?ut(Y):{width:0,height:0},E=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:Tn(),q=E[P],K=E[H],v=re(0,u[r],ue[r]),te=he?u[r]/2-U-v-q-m.mainAxis:J-v-q-m.mainAxis,ne=he?-u[r]/2+U+v+K+m.mainAxis:Z+v+K+m.mainAxis,x=t.elements.arrow&&ce(t.elements.arrow),oe=x?o==="y"?x.clientTop||0:x.clientLeft||0:0,B=(fe=y?.[o])!=null?fe:0,ae=h+te-B-oe,le=h+ne-B,I=re(d?Q($,ae):$,h,d?k(W,le):W),b[o]=I,L[o]=I-h),we&&(G=o==="x"?s:n,me=o==="x"?a:i,c=b[j],f=j==="y"?"height":"width",R=c+O[G],D=c-O[me],w=[s,n].indexOf(ee)!==-1,z=(X=y?.[j])!=null?X:0,F=w?R:c-u[f]-g[f]-z+m.altAxis,M=w?c+u[f]+g[f]-z-m.altAxis:D,A=d&&w?Cs(F,c,M):re(d?F:R,c,d?M:D),b[j]=A,L[j]=A-c),t.modifiersData[be]=L}const kn={name:"preventOverflow",enabled:!0,phase:"main",fn:ks,requiresIfExists:["offset"]};function Ss(e){return{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}}function Ms(e){return e===r(e)||!l(e)?We(e):Ss(e)}function Fs(e){var t=e.getBoundingClientRect(),n=A(t.width)/e.offsetWidth||1,s=A(t.height)/e.offsetHeight||1;return n!==1||s!==1}function Ts(e,t,n){n===void 0&&(n=!1);var r=l(t),c=l(t)&&Fs(t),i=E(t),o=X(e,c,n),a={scrollLeft:0,scrollTop:0},s={x:0,y:0};return(r||!r&&!n)&&((f(t)!=="body"||Je(i))&&(a=Ms(t)),l(t)?(s=X(t,!0),s.x+=t.clientLeft,s.y+=t.clientTop):i&&(s.x=Ke(i))),{x:o.left+a.scrollLeft-s.x,y:o.top+a.scrollTop-s.y,width:o.width,height:o.height}}function zs(e){var n=new Map,t=new Set,s=[];e.forEach(function(e){n.set(e.name,e)});function o(e){t.add(e.name);var i=[].concat(e.requires||[],e.requiresIfExists||[]);i.forEach(function(e){if(!t.has(e)){var s=n.get(e);s&&o(s)}}),s.push(e)}return e.forEach(function(e){t.has(e.name)||o(e)}),s}function Ds(e){var t=zs(e);return sn.reduce(function(e,n){return e.concat(t.filter(function(e){return e.phase===n}))},[])}function Ns(e){var t;return function(){return t||(t=new Promise(function(n){Promise.resolve().then(function(){t=void 0,n(e())})})),t}}function Ls(e){var t=e.reduce(function(e,t){var n=e[t.name];return e[t.name]=n?Object.assign({},n,t,{options:Object.assign({},n.options,t.options),data:Object.assign({},n.data,t.data)}):t,e},{});return Object.keys(t).map(function(e){return t[e]})}ot={placement:"bottom",modifiers:[],strategy:"absolute"};function un(){for(var t=arguments.length,n=new Array(t),e=0;eNumber.parseInt(e,10)):typeof e=="function"?t=>e(t,this._element):e}_getPopperConfig(){const e={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||this._config.display==="static")&&(v.setDataAttribute(this._menu,"popper","static"),e.modifiers=[{name:"applyStyles",enabled:!1}]),{...e,...o(this._config.popperConfig,[e])}}_selectMenuItem({key:e,target:n}){const s=t.find(yo,this._menu).filter(e=>R(e));if(!s.length)return;$e(s,n,e===bt,!s.includes(n)).focus()}static jQueryInterface(e){return this.each(function(){const t=m.getOrCreateInstance(this,e);if(typeof e!="string")return;if(typeof t[e]=="undefined")throw new TypeError(`No method named "${e}"`);t[e]()})}static clearMenus(e){if(e.button===eo||e.type==="keyup"&&e.key!==jt)return;const n=t.find(go);for(const a of n){const t=m.getInstance(a);if(!t||t._config.autoClose===!1)continue;const s=e.composedPath(),o=s.includes(t._menu);if(s.includes(t._element)||t._config.autoClose==="inside"&&!o||t._config.autoClose==="outside"&&o)continue;if(t._menu.contains(e.target)&&(e.type==="keyup"&&e.key===jt||/input|select|option|textarea|form/i.test(e.target.tagName)))continue;const i={relatedTarget:t._element};e.type==="click"&&(i.clickEvent=e),t._completeHide(i)}}static dataApiKeydownHandler(e){const a=/input|textarea/i.test(e.target.tagName),s=e.key===Xs,o=[Zs,bt].includes(e.key);if(!o&&!s)return;if(a&&!s)return;e.preventDefault();const i=this.matches(z)?this:t.prev(this,z)[0]||t.next(this,z)[0]||t.findOne(z,e.delegateTarget.parentNode),n=m.getOrCreateInstance(i);if(o){e.stopPropagation(),n.show(),n._selectMenuItem(e);return}n._isShown()&&(e.stopPropagation(),n.hide(),i.focus())}}e.on(document,yt,z,m.dataApiKeydownHandler),e.on(document,yt,me,m.dataApiKeydownHandler),e.on(document,vt,m.clearMenus),e.on(document,ro,m.clearMenus),e.on(document,vt,z,function(e){e.preventDefault(),m.getOrCreateInstance(this).toggle()}),u(m);const _t="backdrop",zo="fade",wt="show",Ot=`mousedown.bs.${_t}`,Lo={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ro={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class xt extends se{constructor(e){super(),this._config=this._getConfig(e),this._isAppended=!1,this._element=null}static get Default(){return Lo}static get DefaultType(){return Ro}static get NAME(){return _t}show(e){if(!this._config.isVisible){o(e);return}this._append();const t=this._getElement();this._config.isAnimated&&oe(t),t.classList.add(wt),this._emulateAnimation(()=>{o(e)})}hide(e){if(!this._config.isVisible){o(e);return}this._getElement().classList.remove(wt),this._emulateAnimation(()=>{this.dispose(),o(e)})}dispose(){if(!this._isAppended)return;e.off(this._element,Ot),this._element.remove(),this._isAppended=!1}_getElement(){if(!this._element){const e=document.createElement("div");e.className=this._config.className,this._config.isAnimated&&e.classList.add(zo),this._element=e}return this._element}_configAfterMerge(e){return e.rootElement=w(e.rootElement),e}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),e.on(t,Ot,()=>{o(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(e){Zn(e,this._getElement(),this._config.isAnimated)}}const Ho="focustrap",Io="bs.focustrap",be=`.${Io}`,Vo=`focusin${be}`,$o=`keydown.tab${be}`,Wo="Tab",Uo="forward",kt="backward",qo={autofocus:!0,trapElement:null},Yo={autofocus:"boolean",trapElement:"element"};class Dt extends se{constructor(e){super(),this._config=this._getConfig(e),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return qo}static get DefaultType(){return Yo}static get NAME(){return Ho}activate(){if(this._isActive)return;this._config.autofocus&&this._config.trapElement.focus(),e.off(document,be),e.on(document,Vo,e=>this._handleFocusin(e)),e.on(document,$o,e=>this._handleKeydown(e)),this._isActive=!0}deactivate(){if(!this._isActive)return;this._isActive=!1,e.off(document,be)}_handleFocusin(e){const{trapElement:n}=this._config;if(e.target===document||e.target===n||n.contains(e.target))return;const s=t.focusableChildren(n);s.length===0?n.focus():this._lastTabNavDirection===kt?s[s.length-1].focus():s[0].focus()}_handleKeydown(e){if(e.key!==Wo)return;this._lastTabNavDirection=e.shiftKey?kt:Uo}}const Nt=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Lt=".sticky-top",Oe="padding-right",Rt="margin-right";class qe{constructor(){this._element=document.body}getWidth(){const e=document.documentElement.clientWidth;return Math.abs(window.innerWidth-e)}hide(){const e=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Oe,t=>t+e),this._setElementAttributes(Nt,Oe,t=>t+e),this._setElementAttributes(Lt,Rt,t=>t-e)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Oe),this._resetElementAttributes(Nt,Oe),this._resetElementAttributes(Lt,Rt)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(e,t,n){const s=this.getWidth(),o=e=>{if(e!==this._element&&window.innerWidth>e.clientWidth+s)return;this._saveInitialAttribute(e,t);const o=window.getComputedStyle(e).getPropertyValue(t);e.style.setProperty(t,`${n(Number.parseFloat(o))}px`)};this._applyManipulationCallback(e,o)}_saveInitialAttribute(e,t){const n=e.style.getPropertyValue(t);n&&v.setDataAttribute(e,t,n)}_resetElementAttributes(e,t){const n=e=>{const n=v.getDataAttribute(e,t);if(n===null){e.style.removeProperty(t);return}v.removeDataAttribute(e,t),e.style.setProperty(t,n)};this._applyManipulationCallback(e,n)}_applyManipulationCallback(e,n){if(g(e)){n(e);return}for(const s of t.find(e,this._element))n(s)}}const ti="modal",ni="bs.modal",d=`.${ni}`,oi=".data-api",ii="Escape",ai=`hide${d}`,ri=`hidePrevented${d}`,Ht=`hidden${d}`,It=`show${d}`,di=`shown${d}`,ui=`resize${d}`,hi=`click.dismiss${d}`,mi=`mousedown.dismiss${d}`,fi=`keydown.dismiss${d}`,pi=`click${d}${oi}`,Bt="modal-open",vi="fade",$t="show",Se="modal-static",yi=".modal.show",_i=".modal-dialog",wi=".modal-body",Oi='[data-bs-toggle="modal"]',xi={backdrop:!0,focus:!0,keyboard:!0},Ci={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class $ extends h{constructor(e,n){super(e,n),this._dialog=t.findOne(_i,this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new qe,this._addEventListeners()}static get Default(){return xi}static get DefaultType(){return Ci}static get NAME(){return ti}toggle(e){return this._isShown?this.hide():this.show(e)}show(t){if(this._isShown||this._isTransitioning)return;const n=e.trigger(this._element,It,{relatedTarget:t});if(n.defaultPrevented)return;this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Bt),this._adjustDialog(),this._backdrop.show(()=>this._showElement(t))}hide(){if(!this._isShown||this._isTransitioning)return;const t=e.trigger(this._element,ai);if(t.defaultPrevented)return;this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove($t),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated())}dispose(){e.off(window,d),e.off(this._dialog,d),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new xt({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Dt({trapElement:this._element})}_showElement(n){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const s=t.findOne(wi,this._dialog);s&&(s.scrollTop=0),oe(this._element),this._element.classList.add($t);const o=()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,e.trigger(this._element,di,{relatedTarget:n})};this._queueCallback(o,this._dialog,this._isAnimated())}_addEventListeners(){e.on(this._element,fi,e=>{if(e.key!==ii)return;if(this._config.keyboard){this.hide();return}this._triggerBackdropTransition()}),e.on(window,ui,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),e.on(this._element,mi,t=>{e.one(this._element,hi,e=>{if(this._element!==t.target||this._element!==e.target)return;if(this._config.backdrop==="static"){this._triggerBackdropTransition();return}this._config.backdrop&&this.hide()})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Bt),this._resetAdjustments(),this._scrollBar.reset(),e.trigger(this._element,Ht)})}_isAnimated(){return this._element.classList.contains(vi)}_triggerBackdropTransition(){const n=e.trigger(this._element,ri);if(n.defaultPrevented)return;const s=this._element.scrollHeight>document.documentElement.clientHeight,t=this._element.style.overflowY;if(t==="hidden"||this._element.classList.contains(Se))return;s||(this._element.style.overflowY="hidden"),this._element.classList.add(Se),this._queueCallback(()=>{this._element.classList.remove(Se),this._queueCallback(()=>{this._element.style.overflowY=t},this._dialog)},this._dialog),this._element.focus()}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),n=e>0;if(n&&!t){const t=c()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!n&&t){const t=c()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(e,t){return this.each(function(){const n=$.getOrCreateInstance(this,e);if(typeof e!="string")return;if(typeof n[e]=="undefined")throw new TypeError(`No method named "${e}"`);n[e](t)})}}e.on(document,pi,Oi,function(n){const s=t.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&n.preventDefault(),e.one(s,It,t=>{if(t.defaultPrevented)return;e.one(s,Ht,()=>{R(this)&&this.focus()})});const o=t.findOne(yi);o&&$.getInstance(o).hide();const i=$.getOrCreateInstance(s);i.toggle(this)}),_e($),u($);const ki="offcanvas",Ai="bs.offcanvas",b=`.${Ai}`,Wt=".data-api",cs=`load${b}${Wt}`,Ti="Escape",qt="show",on="showing",an="hiding",Li="offcanvas-backdrop",rn=".offcanvas.show",Pi=`show${b}`,Hi=`shown${b}`,Ii=`hide${b}`,cn=`hidePrevented${b}`,ln=`hidden${b}`,$i=`resize${b}`,Wi=`click${b}${Wt}`,Ui=`keydown.dismiss${b}`,Ki='[data-bs-toggle="offcanvas"]',qi={backdrop:!0,keyboard:!0,scroll:!1},Yi={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class O extends h{constructor(e,t){super(e,t),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return qi}static get DefaultType(){return Yi}static get NAME(){return ki}toggle(e){return this._isShown?this.hide():this.show(e)}show(t){if(this._isShown)return;const n=e.trigger(this._element,Pi,{relatedTarget:t});if(n.defaultPrevented)return;this._isShown=!0,this._backdrop.show(),this._config.scroll||(new qe).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(on);const s=()=>{(!this._config.scroll||this._config.backdrop)&&this._focustrap.activate(),this._element.classList.add(qt),this._element.classList.remove(on),e.trigger(this._element,Hi,{relatedTarget:t})};this._queueCallback(s,this._element,!0)}hide(){if(!this._isShown)return;const t=e.trigger(this._element,Ii);if(t.defaultPrevented)return;this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(an),this._backdrop.hide();const n=()=>{this._element.classList.remove(qt,an),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new qe).reset(),e.trigger(this._element,ln)};this._queueCallback(n,this._element,!0)}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const n=()=>{if(this._config.backdrop==="static"){e.trigger(this._element,cn);return}this.hide()},t=Boolean(this._config.backdrop);return new xt({className:Li,isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?n:null})}_initializeFocusTrap(){return new Dt({trapElement:this._element})}_addEventListeners(){e.on(this._element,Ui,t=>{if(t.key!==Ti)return;if(this._config.keyboard){this.hide();return}e.trigger(this._element,cn)})}static jQueryInterface(e){return this.each(function(){const t=O.getOrCreateInstance(this,e);if(typeof e!="string")return;if(t[e]===void 0||e.startsWith("_")||e==="constructor")throw new TypeError(`No method named "${e}"`);t[e](this)})}}e.on(document,Wi,Ki,function(n){const s=t.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&n.preventDefault(),y(this))return;e.one(s,ln,()=>{R(this)&&this.focus()});const o=t.findOne(rn);o&&o!==s&&O.getInstance(o).hide();const i=O.getOrCreateInstance(s);i.toggle(this)}),e.on(window,cs,()=>{for(const e of t.find(rn))O.getOrCreateInstance(e).show()}),e.on(window,$i,()=>{for(const e of t.find("[aria-modal][class*=show][class*=offcanvas-]"))getComputedStyle(e).position!=="fixed"&&O.getOrCreateInstance(e).hide()}),_e(O),u(O);const Xi=/^aria-[\w-]*$/i,dn={"*":["class","dir","id","lang","role",Xi],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Zi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Ji=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,ea=(e,t)=>{const n=e.nodeName.toLowerCase();return t.includes(n)?!Zi.has(n)||Boolean(Ji.test(e.nodeValue)):t.filter(e=>e instanceof RegExp).some(e=>e.test(n))};function ta(e,t,n){if(!e.length)return e;if(n&&typeof n=="function")return n(e);const o=new window.DOMParser,s=o.parseFromString(e,"text/html"),i=[].concat(...s.body.querySelectorAll("*"));for(const e of i){const n=e.nodeName.toLowerCase();if(!Object.keys(t).includes(n)){e.remove();continue}const s=[].concat(...e.attributes),o=[].concat(t["*"]||[],t[n]||[]);for(const t of s)ea(t,o)||e.removeAttribute(t.nodeName)}return s.body.innerHTML}const na="TemplateFactory",sa={allowList:dn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
    "},oa={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ia={entry:"(string|element|function|null)",selector:"(string|element)"};class aa extends se{constructor(e){super(),this._config=this._getConfig(e)}static get Default(){return sa}static get DefaultType(){return oa}static get NAME(){return na}getContent(){return Object.values(this._config.content).map(e=>this._resolvePossibleFunction(e)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(e){return this._checkContent(e),this._config.content={...this._config.content,...e},this}toHtml(){const e=document.createElement("div");e.innerHTML=this._maybeSanitize(this._config.template);for(const[t,n]of Object.entries(this._config.content))this._setContent(e,n,t);const t=e.children[0],n=this._resolvePossibleFunction(this._config.extraClass);return n&&t.classList.add(...n.split(" ")),t}_typeCheckConfig(e){super._typeCheckConfig(e),this._checkContent(e.content)}_checkContent(e){for(const[t,n]of Object.entries(e))super._typeCheckConfig({selector:t,entry:n},ia)}_setContent(e,n,s){const o=t.findOne(s,e);if(!o)return;if(n=this._resolvePossibleFunction(n),!n){o.remove();return}if(g(n)){this._putElementInTemplate(w(n),o);return}if(this._config.html){o.innerHTML=this._maybeSanitize(n);return}o.textContent=n}_maybeSanitize(e){return this._config.sanitize?ta(e,this._config.allowList,this._config.sanitizeFn):e}_resolvePossibleFunction(e){return o(e,[this])}_putElementInTemplate(e,t){if(this._config.html){t.innerHTML="",t.append(e);return}t.textContent=e.textContent}}const ra="tooltip",ca=new Set(["sanitize","allowList","sanitizeFn"]),Ze="fade",da="modal",ye="show",ha=".tooltip-inner",hn=`.${da}`,mn="hide.bs.modal",Z="hover",at="focus",va="click",ba="manual",ja="hide",ya="hidden",_a="show",wa="shown",Oa="inserted",xa="click",Ca="focusin",Ea="focusout",ka="mouseenter",Aa="mouseleave",Sa={AUTO:"auto",TOP:"top",RIGHT:c()?"left":"right",BOTTOM:"bottom",LEFT:c()?"right":"left"},Ma={allowList:dn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},Fa={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class H extends h{constructor(e,t){if(typeof Et=="undefined")throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(e,t),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return Ma}static get DefaultType(){return Fa}static get NAME(){return ra}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){if(!this._isEnabled)return;if(this._activeTrigger.click=!this._activeTrigger.click,this._isShown()){this._leave();return}this._enter()}dispose(){clearTimeout(this._timeout),e.off(this._element.closest(hn),mn,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if(this._element.style.display==="none")throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const n=e.trigger(this._element,this.constructor.eventName(_a)),s=es(this._element),o=(s||this._element.ownerDocument.documentElement).contains(this._element);if(n.defaultPrevented||!o)return;this._disposePopper();const t=this._getTipElement();this._element.setAttribute("aria-describedby",t.getAttribute("id"));const{container:i}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(i.append(t),e.trigger(this._element,this.constructor.eventName(Oa))),this._popper=this._createPopper(t),t.classList.add(ye),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))e.on(t,"mouseover",le);const a=()=>{e.trigger(this._element,this.constructor.eventName(wa)),this._isHovered===!1&&this._leave(),this._isHovered=!1};this._queueCallback(a,this.tip,this._isAnimated())}hide(){if(!this._isShown())return;const t=e.trigger(this._element,this.constructor.eventName(ja));if(t.defaultPrevented)return;const n=this._getTipElement();if(n.classList.remove(ye),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))e.off(t,"mouseover",le);this._activeTrigger[va]=!1,this._activeTrigger[at]=!1,this._activeTrigger[Z]=!1,this._isHovered=null;const s=()=>{if(this._isWithActiveTrigger())return;this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),e.trigger(this._element,this.constructor.eventName(ya))};this._queueCallback(s,this.tip,this._isAnimated())}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(e){const t=this._getTemplateFactory(e).toHtml();if(!t)return null;t.classList.remove(Ze,ye),t.classList.add(`bs-${this.constructor.NAME}-auto`);const n=Yr(this.constructor.NAME).toString();return t.setAttribute("id",n),this._isAnimated()&&t.classList.add(Ze),t}setContent(e){this._newContent=e,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(e){return this._templateFactory?this._templateFactory.changeContent(e):this._templateFactory=new aa({...this._config,content:e,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[ha]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(e){return this.constructor.getOrCreateInstance(e.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Ze)}_isShown(){return this.tip&&this.tip.classList.contains(ye)}_createPopper(e){const t=o(this._config.placement,[this,e,this._element]),n=Sa[t.toUpperCase()];return je(this._element,e,this._getPopperConfig(n))}_getOffset(){const{offset:e}=this._config;return typeof e=="string"?e.split(",").map(e=>Number.parseInt(e,10)):typeof e=="function"?t=>e(t,this._element):e}_resolvePossibleFunction(e){return o(e,[this._element])}_getPopperConfig(e){const t={placement:e,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:e=>{this._getTipElement().setAttribute("data-popper-placement",e.state.placement)}}]};return{...t,...o(this._config.popperConfig,[t])}}_setListeners(){const t=this._config.trigger.split(" ");for(const n of t)if(n==="click")e.on(this._element,this.constructor.eventName(xa),this._config.selector,e=>{const t=this._initializeOnDelegatedTarget(e);t.toggle()});else if(n!==ba){const t=n===Z?this.constructor.eventName(ka):this.constructor.eventName(Ca),s=n===Z?this.constructor.eventName(Aa):this.constructor.eventName(Ea);e.on(this._element,t,this._config.selector,e=>{const t=this._initializeOnDelegatedTarget(e);t._activeTrigger[e.type==="focusin"?at:Z]=!0,t._enter()}),e.on(this._element,s,this._config.selector,e=>{const t=this._initializeOnDelegatedTarget(e);t._activeTrigger[e.type==="focusout"?at:Z]=t._element.contains(e.relatedTarget),t._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},e.on(this._element.closest(hn),mn,this._hideModalHandler)}_fixTitle(){const e=this._element.getAttribute("title");if(!e)return;!this._element.getAttribute("aria-label")&&!this._element.textContent.trim()&&this._element.setAttribute("aria-label",e),this._element.setAttribute("data-bs-original-title",e),this._element.removeAttribute("title")}_enter(){if(this._isShown()||this._isHovered){this._isHovered=!0;return}this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show)}_leave(){if(this._isWithActiveTrigger())return;this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide)}_setTimeout(e,t){clearTimeout(this._timeout),this._timeout=setTimeout(e,t)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(e){const t=v.getDataAttributes(this._element);for(const e of Object.keys(t))ca.has(e)&&delete t[e];return e={...t,...typeof e=="object"&&e?e:{}},e=this._mergeConfigObj(e),e=this._configAfterMerge(e),this._typeCheckConfig(e),e}_configAfterMerge(e){return e.container=e.container===!1?document.body:w(e.container),typeof e.delay=="number"&&(e.delay={show:e.delay,hide:e.delay}),typeof e.title=="number"&&(e.title=e.title.toString()),typeof e.content=="number"&&(e.content=e.content.toString()),e}_getDelegateConfig(){const e={};for(const[t,n]of Object.entries(this._config))this.constructor.Default[t]!==n&&(e[t]=n);return e.selector=!1,e.trigger="manual",e}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(e){return this.each(function(){const t=H.getOrCreateInstance(this,e);if(typeof e!="string")return;if(typeof t[e]=="undefined")throw new TypeError(`No method named "${e}"`);t[e]()})}}u(H);const za="popover",Da=".popover-header",Na=".popover-body",La={...H.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},Ra={...H.DefaultType,content:"(null|string|element|function)"};class mt extends H{static get Default(){return La}static get DefaultType(){return Ra}static get NAME(){return za}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[Da]:this._getTitle(),[Na]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(e){return this.each(function(){const t=mt.getOrCreateInstance(this,e);if(typeof e!="string")return;if(typeof t[e]=="undefined")throw new TypeError(`No method named "${e}"`);t[e]()})}}u(mt);const Ha="scrollspy",Ia="bs.scrollspy",Ie=`.${Ia}`,Va=".data-api",$a=`activate${Ie}`,pn=`click${Ie}`,Ua=`load${Ie}${Va}`,Ka="dropdown-item",W="active",Ya='[data-bs-spy="scroll"]',Ge="[href]",Xa=".nav, .list-group",gn=".nav-link",Za=".nav-item",Ja=".list-group-item",er=`${gn}, ${Za} > ${gn}, ${Ja}`,tr=".dropdown",nr=".dropdown-toggle",sr={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},or={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class xe extends h{constructor(e,t){super(e,t),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement=getComputedStyle(this._element).overflowY==="visible"?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return sr}static get DefaultType(){return or}static get NAME(){return Ha}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const e of this._observableSections.values())this._observer.observe(e)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(e){return e.target=w(e.target)||document.body,e.rootMargin=e.offset?`${e.offset}px 0px -30%`:e.rootMargin,typeof e.threshold=="string"&&(e.threshold=e.threshold.split(",").map(e=>Number.parseFloat(e))),e}_maybeEnableSmoothScroll(){if(!this._config.smoothScroll)return;e.off(this._config.target,pn),e.on(this._config.target,pn,Ge,e=>{const t=this._observableSections.get(e.target.hash);if(t){e.preventDefault();const n=this._rootElement||window,s=t.offsetTop-this._element.offsetTop;if(n.scrollTo){n.scrollTo({top:s,behavior:"smooth"});return}n.scrollTop=s}})}_getNewObserver(){const e={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(e=>this._observerCallback(e),e)}_observerCallback(e){const n=e=>this._targetLinks.get(`#${e.target.id}`),s=e=>{this._previousScrollData.visibleEntryTop=e.target.offsetTop,this._process(n(e))},t=(this._rootElement||document.documentElement).scrollTop,o=t>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=t;for(const i of e){if(!i.isIntersecting){this._activeTarget=null,this._clearActiveClass(n(i));continue}const a=i.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(o&&a){if(s(i),!t)return;continue}!o&&!a&&s(i)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const e=t.find(Ge,this._config.target);for(const n of e){if(!n.hash||y(n))continue;const s=t.findOne(decodeURI(n.hash),this._element);R(s)&&(this._targetLinks.set(decodeURI(n.hash),n),this._observableSections.set(n.hash,s))}}_process(t){if(this._activeTarget===t)return;this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(W),this._activateParents(t),e.trigger(this._element,$a,{relatedTarget:t})}_activateParents(e){if(e.classList.contains(Ka)){t.findOne(nr,e.closest(tr)).classList.add(W);return}for(const n of t.parents(e,Xa))for(const e of t.prev(n,er))e.classList.add(W)}_clearActiveClass(e){e.classList.remove(W);const n=t.find(`${Ge}.${W}`,e);for(const e of n)e.classList.remove(W)}static jQueryInterface(e){return this.each(function(){const t=xe.getOrCreateInstance(this,e);if(typeof e!="string")return;if(t[e]===void 0||e.startsWith("_")||e==="constructor")throw new TypeError(`No method named "${e}"`);t[e]()})}}e.on(window,Ua,()=>{for(const e of t.find(Ya))xe.getOrCreateInstance(e)}),u(xe);const ar="tab",rr="bs.tab",M=`.${rr}`,lr=`hide${M}`,dr=`hidden${M}`,ur=`show${M}`,hr=`shown${M}`,mr=`click${M}`,fr=`keydown${M}`,pr=`load${M}`,gr="ArrowLeft",vn="ArrowRight",br="ArrowUp",yn="ArrowDown",ft="Home",wn="End",S="active",Mn="fade",Ye="show",Cr="dropdown",Wn=".dropdown-toggle",kr=".dropdown-menu",Ne=`:not(${Wn})`,Sr='.list-group, .nav, [role="tablist"]',Mr=".nav-item, .list-group-item",Fr=`.nav-link${Ne}, .list-group-item${Ne}, [role="tab"]${Ne}`,Gn='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Pe=`${Fr}, ${Gn}`,Dr=`.${S}[data-bs-toggle="tab"], .${S}[data-bs-toggle="pill"], .${S}[data-bs-toggle="list"]`;class B extends h{constructor(t){if(super(t),this._parent=this._element.closest(Sr),!this._parent)return;this._setInitialAttributes(this._parent,this._getChildren()),e.on(this._element,fr,e=>this._keydown(e))}static get NAME(){return ar}show(){const t=this._element;if(this._elemIsActive(t))return;const n=this._getActiveElem(),s=n?e.trigger(n,lr,{relatedTarget:t}):null,o=e.trigger(t,ur,{relatedTarget:n});if(o.defaultPrevented||s&&s.defaultPrevented)return;this._deactivate(n,t),this._activate(t,n)}_activate(n,s){if(!n)return;n.classList.add(S),this._activate(t.getElementFromSelector(n));const o=()=>{if(n.getAttribute("role")!=="tab"){n.classList.add(Ye);return}n.removeAttribute("tabindex"),n.setAttribute("aria-selected",!0),this._toggleDropDown(n,!0),e.trigger(n,hr,{relatedTarget:s})};this._queueCallback(o,n,n.classList.contains(Mn))}_deactivate(n,s){if(!n)return;n.classList.remove(S),n.blur(),this._deactivate(t.getElementFromSelector(n));const o=()=>{if(n.getAttribute("role")!=="tab"){n.classList.remove(Ye);return}n.setAttribute("aria-selected",!1),n.setAttribute("tabindex","-1"),this._toggleDropDown(n,!1),e.trigger(n,dr,{relatedTarget:s})};this._queueCallback(o,n,n.classList.contains(Mn))}_keydown(e){if(![gr,vn,br,yn,ft,wn].includes(e.key))return;e.stopPropagation(),e.preventDefault();const n=this._getChildren().filter(e=>!y(e));let t;if([ft,wn].includes(e.key))t=n[e.key===ft?0:n.length-1];else{const s=[vn,yn].includes(e.key);t=$e(n,e.target,s,!0)}t&&(t.focus({preventScroll:!0}),B.getOrCreateInstance(t).show())}_getChildren(){return t.find(Pe,this._parent)}_getActiveElem(){return this._getChildren().find(e=>this._elemIsActive(e))||null}_setInitialAttributes(e,t){this._setAttributeIfNotExists(e,"role","tablist");for(const e of t)this._setInitialAttributesOnChild(e)}_setInitialAttributesOnChild(e){e=this._getInnerElement(e);const t=this._elemIsActive(e),n=this._getOuterElement(e);e.setAttribute("aria-selected",t),n!==e&&this._setAttributeIfNotExists(n,"role","presentation"),t||e.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(e,"role","tab"),this._setInitialAttributesOnTargetPanel(e)}_setInitialAttributesOnTargetPanel(e){const n=t.getElementFromSelector(e);if(!n)return;this._setAttributeIfNotExists(n,"role","tabpanel"),e.id&&this._setAttributeIfNotExists(n,"aria-labelledby",`${e.id}`)}_toggleDropDown(e,n){const s=this._getOuterElement(e);if(!s.classList.contains(Cr))return;const o=(e,o)=>{const i=t.findOne(e,s);i&&i.classList.toggle(o,n)};o(Wn,S),o(kr,Ye),s.setAttribute("aria-expanded",n)}_setAttributeIfNotExists(e,t,n){e.hasAttribute(t)||e.setAttribute(t,n)}_elemIsActive(e){return e.classList.contains(S)}_getInnerElement(e){return e.matches(Pe)?e:t.findOne(Pe,e)}_getOuterElement(e){return e.closest(Mr)||e}static jQueryInterface(e){return this.each(function(){const t=B.getOrCreateInstance(this);if(typeof e!="string")return;if(t[e]===void 0||e.startsWith("_")||e==="constructor")throw new TypeError(`No method named "${e}"`);t[e]()})}}e.on(document,mr,Gn,function(e){if(["A","AREA"].includes(this.tagName)&&e.preventDefault(),y(this))return;B.getOrCreateInstance(this).show()}),e.on(window,pr,()=>{for(const e of t.find(Dr))B.getOrCreateInstance(e)}),u(B);const Lr="toast",Rr="bs.toast",x=`.${Rr}`,Hr=`mouseover${x}`,Ir=`mouseout${x}`,Br=`focusin${x}`,Vr=`focusout${x}`,$r=`hide${x}`,Wr=`hidden${x}`,Ur=`show${x}`,Kr=`shown${x}`,qr="fade",os="hide",ve="show",he="showing",Qr={animation:"boolean",autohide:"boolean",delay:"number"},Zr={animation:!0,autohide:!0,delay:5e3};class ue extends h{constructor(e,t){super(e,t),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Zr}static get DefaultType(){return Qr}static get NAME(){return Lr}show(){const t=e.trigger(this._element,Ur);if(t.defaultPrevented)return;this._clearTimeout(),this._config.animation&&this._element.classList.add(qr);const n=()=>{this._element.classList.remove(he),e.trigger(this._element,Kr),this._maybeScheduleHide()};this._element.classList.remove(os),oe(this._element),this._element.classList.add(ve,he),this._queueCallback(n,this._element,this._config.animation)}hide(){if(!this.isShown())return;const t=e.trigger(this._element,$r);if(t.defaultPrevented)return;const n=()=>{this._element.classList.add(os),this._element.classList.remove(he,ve),e.trigger(this._element,Wr)};this._element.classList.add(he),this._queueCallback(n,this._element,this._config.animation)}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(ve),super.dispose()}isShown(){return this._element.classList.contains(ve)}_maybeScheduleHide(){if(!this._config.autohide)return;if(this._hasMouseInteraction||this._hasKeyboardInteraction)return;this._timeout=setTimeout(()=>{this.hide()},this._config.delay)}_onInteraction(e,t){switch(e.type){case"mouseover":case"mouseout":{this._hasMouseInteraction=t;break}case"focusin":case"focusout":{this._hasKeyboardInteraction=t;break}}if(t){this._clearTimeout();return}const n=e.relatedTarget;if(this._element===n||this._element.contains(n))return;this._maybeScheduleHide()}_setListeners(){e.on(this._element,Hr,e=>this._onInteraction(e,!0)),e.on(this._element,Ir,e=>this._onInteraction(e,!1)),e.on(this._element,Br,e=>this._onInteraction(e,!0)),e.on(this._element,Vr,e=>this._onInteraction(e,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(e){return this.each(function(){const t=ue.getOrCreateInstance(this,e);if(typeof e=="string"){if(typeof t[e]=="undefined")throw new TypeError(`No method named "${e}"`);t[e](this)}})}}_e(ue),u(ue);const ec={Alert:de,Button:fe,Carousel:ee,Collapse:te,Dropdown:m,Modal:$,Offcanvas:O,Popover:mt,ScrollSpy:xe,Tab:B,Toast:ue,Tooltip:H};return ec}),function(e){"use strict";e(function(){e('[data-bs-toggle="tooltip"]').tooltip(),e('[data-bs-toggle="popover"]').popover(),e(".popover-dismiss").popover({trigger:"focus"})});function t(e){return e.offset().top+e.outerHeight()}e(function(){var n,o,i,s=e(".js-td-cover");if(!s.length)return;o=t(s),i=e(".js-navbar-scroll").offset().top,n=Math.ceil(e(".js-navbar-scroll").outerHeight()),o-i{o(e(n.target)),t.blur()}),t.closest("form").on("submit",()=>!1);let n=null;const s=new Map;e.ajax(t.data("offline-search-index-json-src")).then(e=>{n=lunr(function(){this.ref("ref"),this.field("title",{boost:5}),this.field("categories",{boost:3}),this.field("tags",{boost:3}),this.field("description",{boost:2}),this.field("body"),e.forEach(e=>{this.add(e),s.set(e.ref,{title:e.title,excerpt:e.excerpt})})}),t.trigger("change")});const o=o=>{{let e=bootstrap.Popover.getInstance(o[0]);e!==null&&e.dispose()}if(n===null)return;const i=o.val();if(i==="")return;const c=n.query(e=>{const t=lunr.tokenizer(i.toLowerCase());t.forEach(t=>{const n=t.toString();e.term(n,{boost:100}),e.term(n,{wildcard:lunr.Query.wildcard.LEADING|lunr.Query.wildcard.TRAILING,boost:10}),e.term(n,{editDistance:2})})}).slice(0,o.data("offline-search-max-results")),a=e("
    ");a.append(e("
    ").css({display:"flex",justifyContent:"space-between",marginBottom:"1em"}).append(e("").text("Search results").css({fontWeight:"bold"})).append(e("").addClass("td-offline-search-results__close-button")));const r=e("
    ").css({maxHeight:`calc(100vh - ${o.offset().top-e(window).scrollTop()+180}px)`,overflowY:"auto"});a.append(r),c.length===0?r.append(e("

    ").text(`No results found for query "${i}"`)):c.forEach(n=>{const i=s.get(n.ref),a=t.data("offline-search-base-href")+n.ref.replace(/^\//,""),o=e("

    ").addClass("mt-4");o.append(e("").addClass("d-block text-body-secondary").text(n.ref)),o.append(e("").addClass("d-block").css({fontSize:"1.2rem"}).attr("href",a).text(i.title)),o.append(e("

    ").text(i.excerpt)),r.append(o)}),o.one("shown.bs.popover",()=>{e(".td-offline-search-results__close-button").on("click",()=>{o.val(""),o.trigger("change")})});const l=new bootstrap.Popover(o,{content:a[0],html:!0,customClass:"td-offline-search-results",placement:"bottom"});l.show()}})}(jQuery) \ No newline at end of file diff --git a/js/main.min.a8aca58be32dafbc1f83ea37498f84156385fd2ded5d1776c98a24db210d3ec6.js b/js/main.min.a8aca58be32dafbc1f83ea37498f84156385fd2ded5d1776c98a24db210d3ec6.js deleted file mode 100644 index 01d2bb8..0000000 --- a/js/main.min.a8aca58be32dafbc1f83ea37498f84156385fd2ded5d1776c98a24db210d3ec6.js +++ /dev/null @@ -1 +0,0 @@ -(function(e){"use strict";e(function(){e('[data-toggle="tooltip"]').tooltip(),e('[data-toggle="popover"]').popover(),e(".popover-dismiss").popover({trigger:"focus"})});function t(e){return e.offset().top+e.outerHeight()}e(function(){var n,o,i,s=e(".js-td-cover");if(!s.length)return;o=t(s),i=e(".js-navbar-scroll").offset().top,n=Math.ceil(e(".js-navbar-scroll").outerHeight()),o-i',t.href="#"+e.id,e.insertAdjacentElement("beforeend",t),e.addEventListener("mouseenter",function(){t.style.visibility="initial"}),e.addEventListener("mouseleave",function(){t.style.visibility="hidden"})}})})}(jQuery),function(e){"use strict";e(document).ready(function(){const t=e(".td-search-input");t.data("html",!0),t.data("placement","bottom"),t.data("template",'

    '),t.on("change",n=>{o(e(n.target)),t.blur()}),t.closest("form").on("submit",()=>!1);let n=null;const s=new Map;e.ajax(t.data("offline-search-index-json-src")).then(e=>{n=lunr(function(){this.ref("ref"),this.field("title",{boost:5}),this.field("categories",{boost:3}),this.field("tags",{boost:3}),this.field("description",{boost:2}),this.field("body"),e.forEach(e=>{this.add(e),s.set(e.ref,{title:e.title,excerpt:e.excerpt})})}),t.trigger("change")});const o=o=>{if(o.popover("dispose"),n===null)return;const i=o.val();if(i==="")return;const c=n.query(e=>{const t=lunr.tokenizer(i.toLowerCase());t.forEach(t=>{const n=t.toString();e.term(n,{boost:100}),e.term(n,{wildcard:lunr.Query.wildcard.LEADING|lunr.Query.wildcard.TRAILING,boost:10}),e.term(n,{editDistance:2})})}).slice(0,o.data("offline-search-max-results")),a=e("
    ");a.append(e("
    ").css({display:"flex",justifyContent:"space-between",marginBottom:"1em"}).append(e("").text("Search results").css({fontWeight:"bold"})).append(e("").addClass("fas fa-times search-result-close-button").css({cursor:"pointer"})));const r=e("
    ").css({maxHeight:`calc(100vh - ${o.offset().top-e(window).scrollTop()+180}px)`,overflowY:"auto"});a.append(r),c.length===0?r.append(e("

    ").text(`No results found for query "${i}"`)):c.forEach(n=>{const i=s.get(n.ref),a=t.data("offline-search-base-href")+n.ref.replace(/^\//,""),o=e("

    ").addClass("mt-4");o.append(e("").addClass("d-block text-muted").text(n.ref)),o.append(e("").addClass("d-block").css({fontSize:"1.2rem"}).attr("href",a).text(i.title)),o.append(e("

    ").text(i.excerpt)),r.append(o)}),o.on("shown.bs.popover",()=>{e(".search-result-close-button").on("click",()=>{o.val(""),o.trigger("change")})});const l=e.fn.tooltip.Constructor.Default.whiteList;l["*"].push("style"),o.data("content",a[0].outerHTML).popover({whiteList:l}).popover("show")}})}(jQuery),function(e){var t,n,o,s=!1;if(e(".language-mermaid").parent().replaceWith(function(){return s=!0,e('

    ').text(e(this).text())}),!s){mermaid.initialize({startOnLoad:!1});return}o={enable:!0},t=function(e,n){var s={};for(const o in e){const i=o.toLowerCase();e.hasOwnProperty(o)&&n.hasOwnProperty(i)&&(typeof e[o]=="object"?s[o]=t(e[o],n[i]):s[o]=n[i])}return s},n=t(mermaid.mermaidAPI.defaultConfig,o),n.startOnLoad=!0,mermaid.initialize(n)}(jQuery),function(){var e,t,n=function(){e=document.createElement("div"),e.classList.add("drawioframe"),t=document.createElement("iframe"),e.appendChild(t),document.body.appendChild(e)},s=function(){e&&(document.body.removeChild(e),e=void 0,t=void 0)},o=function(e,o){var i,a,r="https://embed.diagrams.net/";r+="?embed=1&ui=atlas&spin=1&modified=unsavedChanges&proto=json&saveAndEdit=1&noSaveBtn=1",i=document.createElement("div"),i.classList.add("drawio"),e.parentNode.insertBefore(i,e),i.appendChild(e),a=document.createElement("button"),a.classList.add("drawiobtn"),a.insertAdjacentHTML("beforeend",''),i.appendChild(a),a.addEventListener("click",function(){if(t)return;n();var a=function(n){var i,c,r=t.contentWindow;if(n.data.length>0&&n.source==r){if(i=JSON.parse(n.data),i.event=="init")r.postMessage(JSON.stringify({action:"load",xml:o}),"*");else if(i.event=="save")c=o.indexOf("data:image/png")==0?"xmlpng":"xmlsvg",r.postMessage(JSON.stringify({action:"export",format:c}),"*");else if(i.event=="export"){const n=e.src.replace(/^.*?([^/]+)$/,"$1"),t=document.createElement("a");t.setAttribute("href",i.data),t.setAttribute("download",n),document.body.appendChild(t),t.click(),t.parentNode.removeChild(t)}(i.event=="exit"||i.event=="export")&&(window.removeEventListener("message",a),s())}};window.addEventListener("message",a),t.setAttribute("src",r)})};document.addEventListener("DOMContentLoaded",function(){for(const s of document.getElementsByTagName("img")){const n=s,t=n.getAttribute("src");if(!t.endsWith(".svg")&&!t.endsWith(".png"))continue;const e=new XMLHttpRequest;e.responseType="blob",e.open("GET",t),e.addEventListener("load",function(){const t=new FileReader;t.addEventListener("load",function(){if(t.result.indexOf("mxfile")!=-1){const t=new FileReader;t.addEventListener("load",function(){const e=t.result;o(n,e)}),t.readAsDataURL(e.response)}}),t.readAsBinaryString(e.response)}),e.send()}})}()
    \ No newline at end of file
    diff --git a/js/prism.js b/js/prism.js
    index ae881ac..15f0f78 100644
    --- a/js/prism.js
    +++ b/js/prism.js
    @@ -1,21 +1,21 @@
    -/* PrismJS 1.21.0
    +/* PrismJS 1.28.0
     https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+go+java+markdown+python+scss+sql+toml+yaml&plugins=toolbar+copy-to-clipboard */
    -var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(u){var c=/\blang(?:uage)?-([\w-]+)\b/i,n=0,M={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof W?new W(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=l.reach);k+=y.value.length,y=y.next){var b=y.value;if(t.length>n.length)return;if(!(b instanceof W)){var x=1;if(h&&y!=t.tail.prev){m.lastIndex=k;var w=m.exec(n);if(!w)break;var A=w.index+(f&&w[1]?w[1].length:0),P=w.index+w[0].length,S=k;for(S+=y.value.length;S<=A;)y=y.next,S+=y.value.length;if(S-=y.value.length,k=S,y.value instanceof W)continue;for(var E=y;E!==t.tail&&(Sl.reach&&(l.reach=j);var C=y.prev;L&&(C=I(t,C,L),k+=L.length),z(t,C,x);var _=new W(o,g?M.tokenize(O,g):O,v,O);y=I(t,C,_),N&&I(t,y,N),1"+a.content+""},!u.document)return u.addEventListener&&(M.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),t=n.language,r=n.code,a=n.immediateClose;u.postMessage(M.highlight(r,M.languages[t],t)),a&&u.close()},!1)),M;var e=M.util.currentScript();function t(){M.manual||M.highlightAll()}if(e&&(M.filename=e.src,e.hasAttribute("data-manual")&&(M.manual=!0)),!M.manual){var r=document.readyState;"loading"===r||"interactive"===r&&e&&e.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)}return M}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
    -Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/,name:/[^\s<>'"]+/}},cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var n={"included-cdata":{pattern://i,inside:s}};n["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var t={};t[a]={pattern:RegExp("(<__[^]*?>)(?:))*\\]\\]>|(?!)".replace(/__/g,function(){return a}),"i"),lookbehind:!0,greedy:!0,inside:n},Prism.languages.insertBefore("markup","cdata",t)}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;
    -!function(e){var s=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+s.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+s.source+"$"),alias:"url"}}},selector:RegExp("[^{}\\s](?:[^{};\"']|"+s.source+")*?(?=\\s*\\{)"),string:{pattern:s,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/!important\b/i,function:/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var t=e.languages.markup;t&&(t.tag.addInlined("style","css"),e.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:t.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:e.languages.css}},alias:"language-css"}},t.tag))}(Prism);
    -Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
    -Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
    -!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|x[0-9a-fA-F]{1,2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b\w+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+?)\s*(?:\r?\n|\r)[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s*(?:\r?\n|\r)[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\2)[^\\])*\2/,lookbehind:!0,greedy:!0,inside:n}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|aptitude|apt-cache|apt-get|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:if|then|else|elif|fi|for|while|in|case|esac|function|select|do|done|until)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|break|cd|continue|eval|exec|exit|export|getopts|hash|pwd|readonly|return|shift|test|times|trap|umask|unset|alias|bind|builtin|caller|command|declare|echo|enable|help|let|local|logout|mapfile|printf|read|readarray|source|type|typeset|ulimit|unalias|set|shopt)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:true|false)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}};for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],r=n.variable[1].inside,s=0;s>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/,number:/(?:\b0x(?:[\da-f]+\.?[\da-f]*|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],comment:Prism.languages.c.comment,directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:Prism.languages.c}}},constant:/\b(?:__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr)\b/}),delete Prism.languages.c.boolean;
    -!function(s){function a(e,s){return e.replace(/<<(\d+)>>/g,function(e,n){return"(?:"+s[+n]+")"})}function t(e,n,s){return RegExp(a(e,n),s||"")}function e(e,n){for(var s=0;s>/g,function(){return"(?:"+e+")"});return e.replace(/<>/g,"[^\\s\\S]")}var n="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface struct",i="add alias and ascending async await by descending from get global group into join let nameof not notnull on or orderby partial remove select set unmanaged value when where where",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var d=l(r),p=RegExp(l(n+" "+r+" "+i+" "+o)),c=l(r+" "+i+" "+o),u=l(n+" "+r+" "+o),g=e("<(?:[^<>;=+\\-*/%&|^]|<>)*>",2),b=e("\\((?:[^()]|<>)*\\)",2),h="@?\\b[A-Za-z_]\\w*\\b",f=a("<<0>>(?:\\s*<<1>>)?",[h,g]),m=a("(?!<<0>>)<<1>>(?:\\s*\\.\\s*<<1>>)*",[c,f]),k="\\[\\s*(?:,\\s*)*\\]",y=a("<<0>>(?:\\s*(?:\\?\\s*)?<<1>>)*(?:\\s*\\?)?",[m,k]),w=a("(?:<<0>>|<<1>>)(?:\\s*(?:\\?\\s*)?<<2>>)*(?:\\s*\\?)?",[a("\\(<<0>>+(?:,<<0>>+)+\\)",[a("[^,()<>[\\];=+\\-*/%&|^]|<<0>>|<<1>>|<<2>>",[g,b,k])]),m,k]),v={keyword:p,punctuation:/[<>()?,.:[\]]/},x="'(?:[^\r\n'\\\\]|\\\\.|\\\\[Uux][\\da-fA-F]{1,8})'",$='"(?:\\\\.|[^\\\\"\r\n])*"';s.languages.csharp=s.languages.extend("clike",{string:[{pattern:t("(^|[^$\\\\])<<0>>",['@"(?:""|\\\\[^]|[^\\\\"])*"(?!")']),lookbehind:!0,greedy:!0},{pattern:t("(^|[^@$\\\\])<<0>>",[$]),lookbehind:!0,greedy:!0},{pattern:RegExp(x),greedy:!0,alias:"character"}],"class-name":[{pattern:t("(\\busing\\s+static\\s+)<<0>>(?=\\s*;)",[m]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+<<0>>\\s*=\\s*)<<1>>(?=\\s*;)",[h,w]),lookbehind:!0,inside:v},{pattern:t("(\\busing\\s+)<<0>>(?=\\s*=)",[h]),lookbehind:!0},{pattern:t("(\\b<<0>>\\s+)<<1>>",[d,f]),lookbehind:!0,inside:v},{pattern:t("(\\bcatch\\s*\\(\\s*)<<0>>",[m]),lookbehind:!0,inside:v},{pattern:t("(\\bwhere\\s+)<<0>>",[h]),lookbehind:!0},{pattern:t("(\\b(?:is(?:\\s+not)?|as)\\s+)<<0>>",[y]),lookbehind:!0,inside:v},{pattern:t("\\b<<0>>(?=\\s+(?!<<1>>)<<2>>(?:\\s*[=,;:{)\\]]|\\s+(?:in|when)\\b))",[w,u,h]),inside:v}],keyword:p,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:ul|lu|[dflmu])?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),s.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),s.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:t("([(,]\\s*)<<0>>(?=\\s*:)",[h]),lookbehind:!0,alias:"punctuation"}}),s.languages.insertBefore("csharp","class-name",{namespace:{pattern:t("(\\b(?:namespace|using)\\s+)<<0>>(?:\\s*\\.\\s*<<0>>)*(?=\\s*[;{])",[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:t("(\\b(?:default|typeof|sizeof)\\s*\\(\\s*)(?:[^()\\s]|\\s(?!\\s*\\))|<<0>>)*(?=\\s*\\))",[b]),lookbehind:!0,alias:"class-name",inside:v},"return-type":{pattern:t("<<0>>(?=\\s+(?:<<1>>\\s*(?:=>|[({]|\\.\\s*this\\s*\\[)|this\\s*\\[))",[w,m]),inside:v,alias:"class-name"},"constructor-invocation":{pattern:t("(\\bnew\\s+)<<0>>(?=\\s*[[({])",[w]),lookbehind:!0,inside:v,alias:"class-name"},"generic-method":{pattern:t("<<0>>\\s*<<1>>(?=\\s*\\()",[h,g]),inside:{function:t("^<<0>>",[h]),generic:{pattern:RegExp(g),alias:"class-name",inside:v}}},"type-list":{pattern:t("\\b((?:<<0>>\\s+<<1>>|where\\s+<<2>>)\\s*:\\s*)(?:<<3>>|<<4>>)(?:\\s*,\\s*(?:<<3>>|<<4>>))*(?=\\s*(?:where|[{;]|=>|$))",[d,f,h,w,p.source]),lookbehind:!0,inside:{keyword:p,"class-name":{pattern:RegExp(w),greedy:!0,inside:v},punctuation:/,/}},preprocessor:{pattern:/(^\s*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(\s*#)\b(?:define|elif|else|endif|endregion|error|if|line|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var _=$+"|"+x,B=a("/(?![*/])|//[^\r\n]*[\r\n]|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>",[_]),E=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),R="\\b(?:assembly|event|field|method|module|param|property|return|type)\\b",P=a("<<0>>(?:\\s*\\(<<1>>*\\))?",[m,E]);s.languages.insertBefore("csharp","class-name",{attribute:{pattern:t("((?:^|[^\\s\\w>)?])\\s*\\[\\s*)(?:<<0>>\\s*:\\s*)?<<1>>(?:\\s*,\\s*<<1>>)*(?=\\s*\\])",[R,P]),lookbehind:!0,greedy:!0,inside:{target:{pattern:t("^<<0>>(?=\\s*:)",[R]),alias:"keyword"},"attribute-arguments":{pattern:t("\\(<<0>>*\\)",[E]),inside:s.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var z=":[^}\r\n]+",S=e(a("[^\"'/()]|<<0>>|\\(<>*\\)",[B]),2),j=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[S,z]),A=e(a("[^\"'/()]|/(?!\\*)|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>|\\(<>*\\)",[_]),2),F=a("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[A,z]);function U(e,n){return{interpolation:{pattern:t("((?:^|[^{])(?:\\{\\{)*)<<0>>",[e]),lookbehind:!0,inside:{"format-string":{pattern:t("(^\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\}$)",[n,z]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:s.languages.csharp}}},string:/[\s\S]+/}}s.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:t('(^|[^\\\\])(?:\\$@|@\\$)"(?:""|\\\\[^]|\\{\\{|<<0>>|[^\\\\{"])*"',[j]),lookbehind:!0,greedy:!0,inside:U(j,S)},{pattern:t('(^|[^@\\\\])\\$"(?:\\\\.|\\{\\{|<<0>>|[^\\\\"{])*"',[F]),lookbehind:!0,greedy:!0,inside:U(F,A)}]})}(Prism),Prism.languages.dotnet=Prism.languages.cs=Prism.languages.csharp;
    -!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char8_t|char16_t|char32_t|class|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|co_await|co_return|co_yield|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/;e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!)\\w+".replace(//g,function(){return t.source})),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+\.?[\da-f']*|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+\.?[\d']*|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]*/i,greedy:!0},operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:true|false)\b/}),e.languages.insertBefore("cpp","string",{"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)(?:[^;{}"'])+?(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","operator",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism);
    -Prism.languages.go=Prism.languages.extend("clike",{keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,builtin:/\b(?:bool|byte|complex(?:64|128)|error|float(?:32|64)|rune|string|u?int(?:8|16|32|64)?|uintptr|append|cap|close|complex|copy|delete|imag|len|make|new|panic|print(?:ln)?|real|recover)\b/,boolean:/\b(?:_|iota|nil|true|false)\b/,operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,number:/(?:\b0x[a-f\d]+|(?:\b\d+\.?\d*|\B\.\d+)(?:e[-+]?\d+)?)i?/i,string:{pattern:/(["'`])(?:\\[\s\S]|(?!\1)[^\\])*\1/,greedy:!0}}),delete Prism.languages.go["class-name"];
    -!function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|null|open|opens|package|private|protected|provides|public|record|requires|return|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,a=/\b[A-Z](?:\w*[a-z]\w*)?\b/;e.languages.java=e.languages.extend("clike",{"class-name":[a,/\b[A-Z]\w*(?=\s+\w+\s*[;,=())])/],keyword:t,function:[e.languages.clike.function,{pattern:/(\:\:)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x[\da-f_]*\.?[\da-f_p+-]+\b|(?:\b\d[\d_]*\.?[\d_]*|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0}}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"}}),e.languages.insertBefore("java","class-name",{annotation:{alias:"punctuation",pattern:/(^|[^.])@\w+/,lookbehind:!0},namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,function(){return t.source})),lookbehind:!0,inside:{punctuation:/\./}},generics:{pattern:/<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<(?:[\w\s,.&?]|<[\w\s,.&?]*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}}})}(Prism);
    -!function(d){function n(n){return n=n.replace(//g,function(){return"(?:\\\\.|[^\\\\\n\r]|(?:\n|\r\n?)(?!\n|\r\n?))"}),RegExp("((?:^|[^\\\\])(?:\\\\{2})*)(?:"+n+")")}var e="(?:\\\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\\\|\r\n`])+",t="\\|?__(?:\\|__)+\\|?(?:(?:\n|\r\n?)|$)".replace(/__/g,function(){return e}),a="\\|?[ \t]*:?-{3,}:?[ \t]*(?:\\|[ \t]*:?-{3,}:?[ \t]*)+\\|?(?:\n|\r\n?)";d.languages.markdown=d.languages.extend("markup",{}),d.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+t+a+"(?:"+t+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+t+a+")(?:"+t+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(e),inside:d.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+t+")"+a+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+t+"$"),inside:{"table-header":{pattern:RegExp(e),alias:"important",inside:d.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/``.+?``|`[^`\r\n]+`/,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n("\\b__(?:(?!_)|_(?:(?!_))+_)+__\\b|\\*\\*(?:(?!\\*)|\\*(?:(?!\\*))+\\*)+\\*\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n("\\b_(?:(?!_)|__(?:(?!_))+__)+_\\b|\\*(?:(?!\\*)|\\*\\*(?:(?!\\*))+\\*\\*)+\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n("(~~?)(?:(?!~))+?\\2"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},url:{pattern:n('!?\\[(?:(?!\\]))+\\](?:\\([^\\s)]+(?:[\t ]+"(?:\\\\.|[^"\\\\])*")?\\)| ?\\[(?:(?!\\]))+\\])'),lookbehind:!0,greedy:!0,inside:{variable:{pattern:/(\[)[^\]]+(?=\]$)/,lookbehind:!0},content:{pattern:/(^!?\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),["url","bold","italic","strike"].forEach(function(e){["url","bold","italic","strike"].forEach(function(n){e!==n&&(d.languages.markdown[e].inside.content.inside[n]=d.languages.markdown[n])})}),d.hooks.add("after-tokenize",function(n){"markdown"!==n.language&&"md"!==n.language||!function n(e){if(e&&"string"!=typeof e)for(var t=0,a=e.length;t]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;
    -Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-]+(?:\([^()]+\)|[^(])*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()]|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}]+[:{][^}]+))/m,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[\w-]|\$[-\w]+|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:if|else(?: if)?|for|each|while|import|extend|debug|warn|mixin|include|function|return|content)/i,{pattern:/( +)(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),Prism.languages.insertBefore("scss","function",{placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:true|false)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|or|not)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.languages.scss;
    -Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:_INSERT|COL)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:S|ING)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:TRUE|FALSE|NULL)\b/i,number:/\b0x[\da-f]+\b|\b\d+\.?\d*|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|IN|LIKE|NOT|OR|IS|DIV|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/};
    -!function(e){function n(e){return e.replace(/__/g,function(){return"(?:[\\w-]+|'[^'\n\r]*'|\"(?:\\\\.|[^\\\\\"\r\n])*\")"})}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n("(^\\s*\\[\\s*(?:\\[\\s*)?)__(?:\\s*\\.\\s*__)*(?=\\s*\\])"),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n("(^\\s*|[{,]\\s*)__(?:\\s*\\.\\s*__)*(?=\\s*=)"),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:true|false)\b/,punctuation:/[.,=[\]{}]/}}(Prism);
    -!function(n){var t=/[*&][^\s[\]{},]+/,e=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+e.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+e.source+")?)";function a(n,t){t=(t||"").replace(/m/g,"")+"m";var e="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|]|}|\\s*#))".replace(/<>/g,function(){return r}).replace(/<>/g,function(){return n});return RegExp(e,t)}n.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\\2[^\r\n]+)*)".replace(/<>/g,function(){return r})),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)[^\r\n{[\\]},#\\s]+?(?=\\s*:\\s)".replace(/<>/g,function(){return r})),lookbehind:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:a("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?)?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:a("true|false","i"),lookbehind:!0,alias:"important"},null:{pattern:a("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:a("(\"|')(?:(?!\\2)[^\\\\\r\n]|\\\\.)*\\2"),lookbehind:!0,greedy:!0},number:{pattern:a("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+\\.?\\d*|\\.?\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:e,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},n.languages.yml=n.languages.yaml}(Prism);
    -!function(){if("undefined"!=typeof self&&self.Prism&&self.document){var i=[],l={},c=function(){};Prism.plugins.toolbar={};var e=Prism.plugins.toolbar.registerButton=function(e,n){var t;t="function"==typeof n?n:function(e){var t;return"function"==typeof n.onClick?((t=document.createElement("button")).type="button",t.addEventListener("click",function(){n.onClick.call(this,e)})):"string"==typeof n.url?(t=document.createElement("a")).href=n.url:t=document.createElement("span"),n.className&&t.classList.add(n.className),t.textContent=n.text,t},e in l?console.warn('There is a button with the key "'+e+'" registered already.'):i.push(l[e]=t)},t=Prism.plugins.toolbar.hook=function(a){var e=a.element.parentNode;if(e&&/pre/i.test(e.nodeName)&&!e.parentNode.classList.contains("code-toolbar")){var t=document.createElement("div");t.classList.add("code-toolbar"),e.parentNode.insertBefore(t,e),t.appendChild(e);var r=document.createElement("div");r.classList.add("toolbar");var n=i,o=function(e){for(;e;){var t=e.getAttribute("data-toolbar-order");if(null!=t)return(t=t.trim()).length?t.split(/\s*,\s*/g):[];e=e.parentElement}}(a.element);o&&(n=o.map(function(e){return l[e]||c})),n.forEach(function(e){var t=e(a);if(t){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(t),r.appendChild(n)}}),t.appendChild(r)}};e("label",function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-label")){var n,a,r=t.getAttribute("data-label");try{a=document.querySelector("template#"+r)}catch(e){}return a?n=a.content:(t.hasAttribute("data-url")?(n=document.createElement("a")).href=t.getAttribute("data-url"):n=document.createElement("span"),n.textContent=r),n}}),Prism.hooks.add("complete",t)}}();
    -!function(){if("undefined"!=typeof self&&self.Prism&&self.document)if(Prism.plugins.toolbar){var i=window.ClipboardJS||void 0;i||"function"!=typeof require||(i=require("clipboard"));var c=[];if(!i){var o=document.createElement("script"),t=document.querySelector("head");o.onload=function(){if(i=window.ClipboardJS)for(;c.length;)c.pop()()},o.src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js",t.appendChild(o)}Prism.plugins.toolbar.registerButton("copy-to-clipboard",function(o){var t=document.createElement("button");t.textContent="Copy";var e=o.element;return i?n():c.push(n),t;function n(){var o=new i(t,{text:function(){return e.textContent}});o.on("success",function(){t.textContent="Copied!",r()}),o.on("error",function(){t.textContent="Press Ctrl+C to copy",r()})}function r(){setTimeout(function(){t.textContent="Copy"},5e3)}})}else console.warn("Copy to Clipboard plugin loaded before Toolbar plugin.")}();
    +var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
    +Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;
    +!function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|"+e.source+")*?(?:;|(?=\\s*\\{))"),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(Prism);
    +Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/};
    +Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp("(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])"),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp("((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))"),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:Prism.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),Prism.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.markup.tag.addAttribute("on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)","javascript")),Prism.languages.js=Prism.languages.javascript;
    +!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},a={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:a},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:a},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:a.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:a.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=a.variable[1].inside,i=0;i>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),Prism.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),Prism.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],char:Prism.languages.c.char,comment:Prism.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:Prism.languages.c}}}}),Prism.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete Prism.languages.c.boolean;
    +!function(e){function n(e,n){return e.replace(/<<(\d+)>>/g,(function(e,s){return"(?:"+n[+s]+")"}))}function s(e,s,a){return RegExp(n(e,s),a||"")}function a(e,n){for(var s=0;s>/g,(function(){return"(?:"+e+")"}));return e.replace(/<>/g,"[^\\s\\S]")}var t="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var d=l(r),p=RegExp(l(t+" "+r+" "+i+" "+o)),c=l(r+" "+i+" "+o),u=l(t+" "+r+" "+o),g=a("<(?:[^<>;=+\\-*/%&|^]|<>)*>",2),b=a("\\((?:[^()]|<>)*\\)",2),h="@?\\b[A-Za-z_]\\w*\\b",f=n("<<0>>(?:\\s*<<1>>)?",[h,g]),m=n("(?!<<0>>)<<1>>(?:\\s*\\.\\s*<<1>>)*",[c,f]),k="\\[\\s*(?:,\\s*)*\\]",y=n("<<0>>(?:\\s*(?:\\?\\s*)?<<1>>)*(?:\\s*\\?)?",[m,k]),w=n("[^,()<>[\\];=+\\-*/%&|^]|<<0>>|<<1>>|<<2>>",[g,b,k]),v=n("\\(<<0>>+(?:,<<0>>+)+\\)",[w]),x=n("(?:<<0>>|<<1>>)(?:\\s*(?:\\?\\s*)?<<2>>)*(?:\\s*\\?)?",[v,m,k]),$={keyword:p,punctuation:/[<>()?,.:[\]]/},_="'(?:[^\r\n'\\\\]|\\\\.|\\\\[Uux][\\da-fA-F]{1,8})'",B='"(?:\\\\.|[^\\\\"\r\n])*"';e.languages.csharp=e.languages.extend("clike",{string:[{pattern:s("(^|[^$\\\\])<<0>>",['@"(?:""|\\\\[^]|[^\\\\"])*"(?!")']),lookbehind:!0,greedy:!0},{pattern:s("(^|[^@$\\\\])<<0>>",[B]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:s("(\\busing\\s+static\\s+)<<0>>(?=\\s*;)",[m]),lookbehind:!0,inside:$},{pattern:s("(\\busing\\s+<<0>>\\s*=\\s*)<<1>>(?=\\s*;)",[h,x]),lookbehind:!0,inside:$},{pattern:s("(\\busing\\s+)<<0>>(?=\\s*=)",[h]),lookbehind:!0},{pattern:s("(\\b<<0>>\\s+)<<1>>",[d,f]),lookbehind:!0,inside:$},{pattern:s("(\\bcatch\\s*\\(\\s*)<<0>>",[m]),lookbehind:!0,inside:$},{pattern:s("(\\bwhere\\s+)<<0>>",[h]),lookbehind:!0},{pattern:s("(\\b(?:is(?:\\s+not)?|as)\\s+)<<0>>",[y]),lookbehind:!0,inside:$},{pattern:s("\\b<<0>>(?=\\s+(?!<<1>>|with\\s*\\{)<<2>>(?:\\s*[=,;:{)\\]]|\\s+(?:in|when)\\b))",[x,u,h]),inside:$}],keyword:p,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:s("([(,]\\s*)<<0>>(?=\\s*:)",[h]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:s("(\\b(?:namespace|using)\\s+)<<0>>(?:\\s*\\.\\s*<<0>>)*(?=\\s*[;{])",[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:s("(\\b(?:default|sizeof|typeof)\\s*\\(\\s*(?!\\s))(?:[^()\\s]|\\s(?!\\s)|<<0>>)*(?=\\s*\\))",[b]),lookbehind:!0,alias:"class-name",inside:$},"return-type":{pattern:s("<<0>>(?=\\s+(?:<<1>>\\s*(?:=>|[({]|\\.\\s*this\\s*\\[)|this\\s*\\[))",[x,m]),inside:$,alias:"class-name"},"constructor-invocation":{pattern:s("(\\bnew\\s+)<<0>>(?=\\s*[[({])",[x]),lookbehind:!0,inside:$,alias:"class-name"},"generic-method":{pattern:s("<<0>>\\s*<<1>>(?=\\s*\\()",[h,g]),inside:{function:s("^<<0>>",[h]),generic:{pattern:RegExp(g),alias:"class-name",inside:$}}},"type-list":{pattern:s("\\b((?:<<0>>\\s+<<1>>|record\\s+<<1>>\\s*<<5>>|where\\s+<<2>>)\\s*:\\s*)(?:<<3>>|<<4>>|<<1>>\\s*<<5>>|<<6>>)(?:\\s*,\\s*(?:<<3>>|<<4>>|<<6>>))*(?=\\s*(?:where|[{;]|=>|$))",[d,f,h,x,p.source,b,"\\bnew\\s*\\(\\s*\\)"]),lookbehind:!0,inside:{"record-arguments":{pattern:s("(^(?!new\\s*\\()<<0>>\\s*)<<1>>",[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:p,"class-name":{pattern:RegExp(x),greedy:!0,inside:$},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var E=B+"|"+_,R=n("/(?![*/])|//[^\r\n]*[\r\n]|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>",[E]),z=a(n("[^\"'/()]|<<0>>|\\(<>*\\)",[R]),2),S="\\b(?:assembly|event|field|method|module|param|property|return|type)\\b",j=n("<<0>>(?:\\s*\\(<<1>>*\\))?",[m,z]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:s("((?:^|[^\\s\\w>)?])\\s*\\[\\s*)(?:<<0>>\\s*:\\s*)?<<1>>(?:\\s*,\\s*<<1>>)*(?=\\s*\\])",[S,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:s("^<<0>>(?=\\s*:)",[S]),alias:"keyword"},"attribute-arguments":{pattern:s("\\(<<0>>*\\)",[z]),inside:e.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var A=":[^}\r\n]+",F=a(n("[^\"'/()]|<<0>>|\\(<>*\\)",[R]),2),P=n("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[F,A]),U=a(n("[^\"'/()]|/(?!\\*)|/\\*(?:[^*]|\\*(?!/))*\\*/|<<0>>|\\(<>*\\)",[E]),2),Z=n("\\{(?!\\{)(?:(?![}:])<<0>>)*<<1>>?\\}",[U,A]);function q(n,a){return{interpolation:{pattern:s("((?:^|[^{])(?:\\{\\{)*)<<0>>",[n]),lookbehind:!0,inside:{"format-string":{pattern:s("(^\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\}$)",[a,A]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:s('(^|[^\\\\])(?:\\$@|@\\$)"(?:""|\\\\[^]|\\{\\{|<<0>>|[^\\\\{"])*"',[P]),lookbehind:!0,greedy:!0,inside:q(P,F)},{pattern:s('(^|[^@\\\\])\\$"(?:\\\\.|\\{\\{|<<0>>|[^\\\\"{])*"',[Z]),lookbehind:!0,greedy:!0,inside:q(Z,U)}],char:{pattern:RegExp(_),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(Prism);
    +!function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n="\\b(?!)\\w+(?:\\s*\\.\\s*\\w+)*\\b".replace(//g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp("(\\b(?:class|concept|enum|struct|typename)\\s+)(?!)\\w+".replace(//g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp('(\\b(?:import|module)\\s+)(?:"(?:\\\\(?:\r\n|[^])|[^"\\\\\r\n])*"|<[^<>\r\n]*>|'+"(?:\\s*:\\s*)?|:\\s*".replace(//g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(Prism);
    +Prism.languages.go=Prism.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),Prism.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete Prism.languages.go["class-name"];
    +!function(e){var n=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,t="(?:[a-z]\\w*\\s*\\.\\s*)*(?:[A-Z]\\w*\\s*\\.\\s*)*",s={pattern:RegExp("(^|[^\\w.])"+t+"[A-Z](?:[\\d_A-Z]*[a-z]\\w*)?\\b"),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[s,{pattern:RegExp("(^|[^\\w.])"+t+"[A-Z]\\w*(?=\\s+\\w+\\s*[;,=()]|\\s*(?:\\[[\\s,]*\\]\\s*)?::\\s*new\\b)"),lookbehind:!0,inside:s.inside},{pattern:RegExp("(\\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\\s+)"+t+"[A-Z]\\w*\\b"),lookbehind:!0,inside:s.inside}],keyword:n,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":s,keyword:n,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp("(\\bimport\\s+)"+t+"(?:[A-Z]\\w*|\\*)(?=\\s*;)"),lookbehind:!0,inside:{namespace:s.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp("(\\bimport\\s+static\\s+)"+t+"(?:\\w+|\\*)(?=\\s*;)"),lookbehind:!0,alias:"static",inside:{namespace:s.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp("(\\b(?:exports|import(?:\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\s+)(?!)[a-z]\\w*(?:\\.[a-z]\\w*)*\\.?".replace(//g,(function(){return n.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(Prism);
    +!function(n){function e(n){return n=n.replace(//g,(function(){return"(?:\\\\.|[^\\\\\n\r]|(?:\n|\r\n?)(?![\r\n]))"})),RegExp("((?:^|[^\\\\])(?:\\\\{2})*)(?:"+n+")")}var t="(?:\\\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\\\|\r\n`])+",a="\\|?__(?:\\|__)+\\|?(?:(?:\n|\r\n?)|(?![^]))".replace(/__/g,(function(){return t})),i="\\|?[ \t]*:?-{3,}:?[ \t]*(?:\\|[ \t]*:?-{3,}:?[ \t]*)+\\|?(?:\n|\r\n?)";n.languages.markdown=n.languages.extend("markup",{}),n.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:n.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+i+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+i+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(t),inside:n.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+i+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(t),alias:"important",inside:n.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:e("\\b__(?:(?!_)|_(?:(?!_))+_)+__\\b|\\*\\*(?:(?!\\*)|\\*(?:(?!\\*))+\\*)+\\*\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:e("\\b_(?:(?!_)|__(?:(?!_))+__)+_\\b|\\*(?:(?!\\*)|\\*\\*(?:(?!\\*))+\\*\\*)+\\*"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:e("(~~?)(?:(?!~))+\\2"),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:e('!?\\[(?:(?!\\]))+\\](?:\\([^\\s)]+(?:[\t ]+"(?:\\\\.|[^"\\\\])*")?\\)|[ \t]?\\[(?:(?!\\]))+\\])'),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(e){["url","bold","italic","strike","code-snippet"].forEach((function(t){e!==t&&(n.languages.markdown[e].inside.content.inside[t]=n.languages.markdown[t])}))})),n.hooks.add("after-tokenize",(function(n){"markdown"!==n.language&&"md"!==n.language||function n(e){if(e&&"string"!=typeof e)for(var t=0,a=e.length;t",quot:'"'},l=String.fromCodePoint||String.fromCharCode;n.languages.md=n.languages.markdown}(Prism);
    +Prism.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},Prism.languages.python["string-interpolation"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;
    +Prism.languages.scss=Prism.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),Prism.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),Prism.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),Prism.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),Prism.languages.scss.atrule.inside.rest=Prism.languages.scss;
    +Prism.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/};
    +!function(e){function n(e){return e.replace(/__/g,(function(){return"(?:[\\w-]+|'[^'\n\r]*'|\"(?:\\\\.|[^\\\\\"\r\n])*\")"}))}e.languages.toml={comment:{pattern:/#.*/,greedy:!0},table:{pattern:RegExp(n("(^[\t ]*\\[\\s*(?:\\[\\s*)?)__(?:\\s*\\.\\s*__)*(?=\\s*\\])"),"m"),lookbehind:!0,greedy:!0,alias:"class-name"},key:{pattern:RegExp(n("(^[\t ]*|[{,]\\s*)__(?:\\s*\\.\\s*__)*(?=\\s*=)"),"m"),lookbehind:!0,greedy:!0,alias:"property"},string:{pattern:/"""(?:\\[\s\S]|[^\\])*?"""|'''[\s\S]*?'''|'[^'\n\r]*'|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},date:[{pattern:/\b\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?\b/i,alias:"number"},{pattern:/\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b/,alias:"number"}],number:/(?:\b0(?:x[\da-zA-Z]+(?:_[\da-zA-Z]+)*|o[0-7]+(?:_[0-7]+)*|b[10]+(?:_[10]+)*))\b|[-+]?\b\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?\b|[-+]?\b(?:inf|nan)\b/,boolean:/\b(?:false|true)\b/,punctuation:/[.,=[\]{}]/}}(Prism);
    +!function(e){var n=/[*&][^\s[\]{},]+/,r=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,t="(?:"+r.source+"(?:[ \t]+"+n.source+")?|"+n.source+"(?:[ \t]+"+r.source+")?)",a="(?:[^\\s\\x00-\\x08\\x0e-\\x1f!\"#%&'*,\\-:>?@[\\]`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*".replace(//g,(function(){return"[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]"})),d="\"(?:[^\"\\\\\r\n]|\\\\.)*\"|'(?:[^'\\\\\r\n]|\\\\.)*'";function o(e,n){n=(n||"").replace(/m/g,"")+"m";var r="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\\]|\\}|(?:[\r\n]\\s*)?#))".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return e}));return RegExp(r,n)}e.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\\S[^\r\n]*(?:\\2[^\r\n]+)*)".replace(/<>/g,(function(){return t}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\\s*:\\s)".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return"(?:"+a+"|"+d+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:o("false|true","i"),lookbehind:!0,alias:"important"},null:{pattern:o("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:o(d),lookbehind:!0,greedy:!0},number:{pattern:o("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:r,important:n,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism);
    +!function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){var e=[],t={},n=function(){};Prism.plugins.toolbar={};var a=Prism.plugins.toolbar.registerButton=function(n,a){var r;r="function"==typeof a?a:function(e){var t;return"function"==typeof a.onClick?((t=document.createElement("button")).type="button",t.addEventListener("click",(function(){a.onClick.call(this,e)}))):"string"==typeof a.url?(t=document.createElement("a")).href=a.url:t=document.createElement("span"),a.className&&t.classList.add(a.className),t.textContent=a.text,t},n in t?console.warn('There is a button with the key "'+n+'" registered already.'):e.push(t[n]=r)},r=Prism.plugins.toolbar.hook=function(a){var r=a.element.parentNode;if(r&&/pre/i.test(r.nodeName)&&!r.parentNode.classList.contains("code-toolbar")){var o=document.createElement("div");o.classList.add("code-toolbar"),r.parentNode.insertBefore(o,r),o.appendChild(r);var i=document.createElement("div");i.classList.add("toolbar");var l=e,d=function(e){for(;e;){var t=e.getAttribute("data-toolbar-order");if(null!=t)return(t=t.trim()).length?t.split(/\s*,\s*/g):[];e=e.parentElement}}(a.element);d&&(l=d.map((function(e){return t[e]||n}))),l.forEach((function(e){var t=e(a);if(t){var n=document.createElement("div");n.classList.add("toolbar-item"),n.appendChild(t),i.appendChild(n)}})),o.appendChild(i)}};a("label",(function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute("data-label")){var n,a,r=t.getAttribute("data-label");try{a=document.querySelector("template#"+r)}catch(e){}return a?n=a.content:(t.hasAttribute("data-url")?(n=document.createElement("a")).href=t.getAttribute("data-url"):n=document.createElement("span"),n.textContent=r),n}})),Prism.hooks.add("complete",r)}}();
    +!function(){function t(t){var e=document.createElement("textarea");e.value=t.getText(),e.style.top="0",e.style.left="0",e.style.position="fixed",document.body.appendChild(e),e.focus(),e.select();try{var o=document.execCommand("copy");setTimeout((function(){o?t.success():t.error()}),1)}catch(e){setTimeout((function(){t.error(e)}),1)}document.body.removeChild(e)}"undefined"!=typeof Prism&&"undefined"!=typeof document&&(Prism.plugins.toolbar?Prism.plugins.toolbar.registerButton("copy-to-clipboard",(function(e){var o=e.element,n=function(t){var e={copy:"Copy","copy-error":"Press Ctrl+C to copy","copy-success":"Copied!","copy-timeout":5e3};for(var o in e){for(var n="data-prismjs-"+o,c=t;c&&!c.hasAttribute(n);)c=c.parentElement;c&&(e[o]=c.getAttribute(n))}return e}(o),c=document.createElement("button");c.className="copy-to-clipboard-button",c.setAttribute("type","button");var r=document.createElement("span");return c.appendChild(r),u("copy"),function(e,o){e.addEventListener("click",(function(){!function(e){navigator.clipboard?navigator.clipboard.writeText(e.getText()).then(e.success,(function(){t(e)})):t(e)}(o)}))}(c,{getText:function(){return o.textContent},success:function(){u("copy-success"),i()},error:function(){u("copy-error"),setTimeout((function(){!function(t){window.getSelection().selectAllChildren(t)}(o)}),1),i()}}),c;function i(){setTimeout((function(){u("copy")}),n["copy-timeout"])}function u(t){r.textContent=n[t],c.setAttribute("data-copy-state",t)}})):console.warn("Copy to Clipboard plugin loaded before Toolbar plugin."))}();
    diff --git a/js/swagger-ui-bundle.js b/js/swagger-ui-bundle.js
    deleted file mode 100644
    index c48cc4c..0000000
    --- a/js/swagger-ui-bundle.js
    +++ /dev/null
    @@ -1,134 +0,0 @@
    -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(function(){try{return require("esprima")}catch(e){}}()):"function"==typeof define&&define.amd?define(["esprima"],t):"object"==typeof exports?exports.SwaggerUIBundle=t(function(){try{return require("esprima")}catch(e){}}()):e.SwaggerUIBundle=t(e.esprima)}(window,function(e){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=488)}([function(e,t,n){"use strict";e.exports=n(104)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return a(e)?e:J(e)}function r(e){return s(e)?e:K(e)}function o(e){return u(e)?e:Y(e)}function i(e){return a(e)&&!c(e)?e:$(e)}function a(e){return!(!e||!e[p])}function s(e){return!(!e||!e[f])}function u(e){return!(!e||!e[h])}function c(e){return s(e)||u(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(i,n),n.isIterable=a,n.isKeyed=s,n.isIndexed=u,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=i;var p="@@__IMMUTABLE_ITERABLE__@@",f="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m=5,v=1<>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?C(e)+t:t}function O(){return!0}function A(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function j(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var I=0,M=1,N=2,R="function"==typeof Symbol&&Symbol.iterator,D="@@iterator",L=R||D;function U(e){this.next=e}function q(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function F(){return{value:void 0,done:!0}}function B(e){return!!H(e)}function z(e){return e&&"function"==typeof e.next}function V(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(R&&e[R]||e[D]);if("function"==typeof t)return t}function W(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():a(e)?e.toSeq():function(e){var t=ue(e)||"object"==typeof e&&new te(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}(e)}function K(e){return null==e?ie().toKeyedSeq():a(e)?s(e)?e.toSeq():e.fromEntrySeq():ae(e)}function Y(e){return null==e?ie():a(e)?s(e)?e.entrySeq():e.toIndexedSeq():se(e)}function $(e){return(null==e?ie():a(e)?s(e)?e.entrySeq():e:se(e)).toSetSeq()}U.prototype.toString=function(){return"[Iterator]"},U.KEYS=I,U.VALUES=M,U.ENTRIES=N,U.prototype.inspect=U.prototype.toSource=function(){return this.toString()},U.prototype[L]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return ce(this,e,t,!0)},J.prototype.__iterator=function(e,t){return le(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return ce(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return le(this,e,t,!1)},t($,J),$.of=function(){return $(arguments)},$.prototype.toSetSeq=function(){return this},J.isSeq=oe,J.Keyed=K,J.Set=$,J.Indexed=Y;var G,Z,X,Q="@@__IMMUTABLE_SEQ__@@";function ee(e){this._array=e,this.size=e.length}function te(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function ne(e){this._iterable=e,this.size=e.length||e.size}function re(e){this._iterator=e,this._iteratorCache=[]}function oe(e){return!(!e||!e[Q])}function ie(){return G||(G=new ee([]))}function ae(e){var t=Array.isArray(e)?new ee(e).fromEntrySeq():z(e)?new re(e).fromEntrySeq():B(e)?new ne(e).fromEntrySeq():"object"==typeof e?new te(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function se(e){var t=ue(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function ue(e){return W(e)?new ee(e):z(e)?new re(e):B(e)?new ne(e):void 0}function ce(e,t,n,r){var o=e._cache;if(o){for(var i=o.length-1,a=0;a<=i;a++){var s=o[n?i-a:a];if(!1===t(s[1],r?s[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function le(e,t,n,r){var o=e._cache;if(o){var i=o.length-1,a=0;return new U(function(){var e=o[n?i-a:a];return a++>i?{value:void 0,done:!0}:q(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function pe(e,t){return t?function e(t,n,r,o){return Array.isArray(n)?t.call(o,r,Y(n).map(function(r,o){return e(t,r,o,n)})):he(n)?t.call(o,r,K(n).map(function(r,o){return e(t,r,o,n)})):n}(t,e,"",{"":e}):fe(e)}function fe(e){return Array.isArray(e)?Y(e).map(fe).toList():he(e)?K(e).map(fe).toMap():e}function he(e){return e&&(e.constructor===Object||void 0===e.constructor)}function de(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function me(e,t){if(e===t)return!0;if(!a(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||s(e)!==s(t)||u(e)!==u(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!c(e);if(l(e)){var r=e.entries();return t.every(function(e,t){var o=r.next().value;return o&&de(o[1],e)&&(n||de(o[0],t))})&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var i=e;e=t,t=i}var p=!0,f=t.__iterate(function(t,r){if(n?!e.has(t):o?!de(t,e.get(r,y)):!de(e.get(r,y),t))return p=!1,!1});return p&&e.size===f}function ve(e,t){if(!(this instanceof ve))return new ve(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(Z)return Z;Z=this}}function ge(e,t){if(!e)throw new Error(t)}function ye(e,t,n){if(!(this instanceof ye))return new ye(e,t,n);if(ge(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?{value:void 0,done:!0}:q(e,o,n[t?r-o++:o++])})},t(te,K),te.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},te.prototype.has=function(e){return this._object.hasOwnProperty(e)},te.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,i=0;i<=o;i++){var a=r[t?o-i:i];if(!1===e(n[a],a,this))return i+1}return i},te.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,i=0;return new U(function(){var a=r[t?o-i:i];return i++>o?{value:void 0,done:!0}:q(e,a,n[a])})},te.prototype[d]=!0,t(ne,Y),ne.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=V(this._iterable),r=0;if(z(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},ne.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=V(this._iterable);if(!z(n))return new U(F);var r=0;return new U(function(){var t=n.next();return t.done?t:q(e,r++,t.value)})},t(re,Y),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return q(e,o,r[o++])})},t(ve,Y),ve.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},ve.prototype.get=function(e,t){return this.has(e)?this._value:t},ve.prototype.includes=function(e){return de(this._value,e)},ve.prototype.slice=function(e,t){var n=this.size;return A(e,t,n)?this:new ve(this._value,j(t,n)-T(e,n))},ve.prototype.reverse=function(){return this},ve.prototype.indexOf=function(e){return de(this._value,e)?0:-1},ve.prototype.lastIndexOf=function(e){return de(this._value,e)?this.size:-1},ve.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?{value:void 0,done:!0}:q(e,i++,a)})},ye.prototype.equals=function(e){return e instanceof ye?this._start===e._start&&this._end===e._end&&this._step===e._step:me(this,e)},t(be,n),t(_e,be),t(we,be),t(xe,be),be.Keyed=_e,be.Indexed=we,be.Set=xe;var Ee="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Se(e){return e>>>1&1073741824|3221225471&e}function Ce(e){if(!1===e||null==e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null==e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Se(n)}if("string"===t)return e.length>Me?function(e){var t=De[e];return void 0===t&&(t=ke(e),Re===Ne&&(Re=0,De={}),Re++,De[e]=t),t}(e):ke(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return function(e){var t;if(je&&void 0!==(t=Oe.get(e)))return t;if(void 0!==(t=e[Ie]))return t;if(!Te){if(void 0!==(t=e.propertyIsEnumerable&&e.propertyIsEnumerable[Ie]))return t;if(void 0!==(t=function(e){if(e&&e.nodeType>0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}(e)))return t}if(t=++Pe,1073741824&Pe&&(Pe=0),je)Oe.set(e,t);else{if(void 0!==Ae&&!1===Ae(e))throw new Error("Non-extensible objects are not allowed as keys.");if(Te)Object.defineProperty(e,Ie,{enumerable:!1,configurable:!1,writable:!1,value:t});else if(void 0!==e.propertyIsEnumerable&&e.propertyIsEnumerable===e.constructor.prototype.propertyIsEnumerable)e.propertyIsEnumerable=function(){return this.constructor.prototype.propertyIsEnumerable.apply(this,arguments)},e.propertyIsEnumerable[Ie]=t;else{if(void 0===e.nodeType)throw new Error("Unable to set a non-enumerable property on object.");e[Ie]=t}}return t}(e);if("function"==typeof e.toString)return ke(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ke(e){for(var t=0,n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}})},Ue.prototype.toString=function(){return this.__toString("Map {","}")},Ue.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},Ue.prototype.set=function(e,t){return Qe(this,e,t)},Ue.prototype.setIn=function(e,t){return this.updateIn(e,y,function(){return t})},Ue.prototype.remove=function(e){return Qe(this,e,y)},Ue.prototype.deleteIn=function(e){return this.updateIn(e,function(){return y})},Ue.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},Ue.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=function e(t,n,r,o){var i=t===y,a=n.next();if(a.done){var s=i?r:t,u=o(s);return u===s?t:u}ge(i||t&&t.set,"invalid keyPath");var c=a.value,l=i?y:t.get(c,y),p=e(l,n,r,o);return p===l?t:p===y?t.remove(c):(i?Xe():t).set(c,p)}(this,rn(e),t,n);return r===y?void 0:r},Ue.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):Xe()},Ue.prototype.merge=function(){return rt(this,void 0,arguments)},Ue.prototype.mergeWith=function(t){var n=e.call(arguments,1);return rt(this,t,n)},Ue.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]})},Ue.prototype.mergeDeep=function(){return rt(this,ot,arguments)},Ue.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return rt(this,it(t),n)},Ue.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]})},Ue.prototype.sort=function(e){return Tt(Jt(this,e))},Ue.prototype.sortBy=function(e,t){return Tt(Jt(this,t,e))},Ue.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},Ue.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new E)},Ue.prototype.asImmutable=function(){return this.__ensureOwner()},Ue.prototype.wasAltered=function(){return this.__altered},Ue.prototype.__iterator=function(e,t){return new Ye(this,e,t)},Ue.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},Ue.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Ue.isMap=qe;var Fe,Be="@@__IMMUTABLE_MAP__@@",ze=Ue.prototype;function Ve(e,t){this.ownerID=e,this.entries=t}function He(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function We(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Je(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Ke(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function Ye(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&Ge(e._root)}function $e(e,t){return q(e,t[0],t[1])}function Ge(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var o=Object.create(ze);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Xe(){return Fe||(Fe=Ze(0))}function Qe(e,t,n){var r,o;if(e._root){var i=w(b),a=w(_);if(r=et(e._root,e.__ownerID,0,void 0,t,n,i,a),!a.value)return e;o=e.size+(i.value?n===y?-1:1:0)}else{if(n===y)return e;o=1,r=new Ve(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?Ze(o,r):Xe()}function et(e,t,n,r,o,i,a,s){return e?e.update(t,n,r,o,i,a,s):i===y?e:(x(s),x(a),new Ke(t,r,[o,i]))}function tt(e){return e.constructor===Ke||e.constructor===Je}function nt(e,t,n,r,o){if(e.keyHash===r)return new Je(t,r,[e.entry,o]);var i,a=(0===n?e.keyHash:e.keyHash>>>n)&g,s=(0===n?r:r>>>n)&g;return new He(t,1<>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function ut(e,t,n,r){var o=r?e:S(e);return o[t]=n,o}ze[Be]=!0,ze.delete=ze.remove,ze.removeIn=ze.deleteIn,Ve.prototype.get=function(e,t,n,r){for(var o=this.entries,i=0,a=o.length;i=ct)return function(e,t,n,r){e||(e=new E);for(var o=new Ke(e,Ce(n),[n,r]),i=0;i>>e)&g),i=this.bitmap;return 0==(i&o)?r:this.nodes[st(i&o-1)].get(e+m,t,n,r)},He.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var s=(0===t?n:n>>>t)&g,u=1<=lt)return function(e,t,n,r,o){for(var i=0,a=new Array(v),s=0;0!==n;s++,n>>>=1)a[s]=1&n?t[i++]:void 0;return a[r]=o,new We(e,i+1,a)}(e,f,c,s,d);if(l&&!d&&2===f.length&&tt(f[1^p]))return f[1^p];if(l&&d&&1===f.length&&tt(d))return d;var b=e&&e===this.ownerID,_=l?d?c:c^u:c|u,w=l?d?ut(f,p,d,b):function(e,t,n){var r=e.length-1;if(n&&t===r)return e.pop(),e;for(var o=new Array(r),i=0,a=0;a>>e)&g,i=this.nodes[o];return i?i.get(e+m,t,n,r):r},We.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var s=(0===t?n:n>>>t)&g,u=o===y,c=this.nodes,l=c[s];if(u&&!l)return this;var p=et(l,e,t+m,n,r,o,i,a);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&r=0&&e=e.size||t<0)return e.withMutations(function(e){t<0?kt(e,t).set(0,n):kt(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,o=e._root,i=w(_);return t>=At(e._capacity)?r=Et(r,e.__ownerID,0,t,n,i):o=Et(o,e.__ownerID,e._level,t,n,i),i.value?e.__ownerID?(e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e):wt(e._origin,e._capacity,e._level,o,r):e}(this,e,t)},ft.prototype.remove=function(e){return this.has(e)?0===e?this.shift():e===this.size-1?this.pop():this.splice(e,1):this},ft.prototype.insert=function(e,t){return this.splice(e,0,t)},ft.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=this._origin=this._capacity=0,this._level=m,this._root=this._tail=null,this.__hash=void 0,this.__altered=!0,this):xt()},ft.prototype.push=function(){var e=arguments,t=this.size;return this.withMutations(function(n){kt(n,0,t+e.length);for(var r=0;r>>t&g;if(r>=this.array.length)return new vt([],e);var o,i=0===r;if(t>0){var a=this.array[r];if((o=a&&a.removeBefore(e,t-m,n))===a&&i)return this}if(i&&!o)return this;var s=St(this,e);if(!i)for(var u=0;u>>t&g;if(o>=this.array.length)return this;if(t>0){var i=this.array[o];if((r=i&&i.removeAfter(e,t-m,n))===i&&o===this.array.length-1)return this}var a=St(this,e);return a.array.splice(o+1),r&&(a.array[o]=r),a};var gt,yt,bt={};function _t(e,t){var n=e._origin,r=e._capacity,o=At(r),i=e._tail;return a(e._root,e._level,0);function a(e,s,u){return 0===s?function(e,a){var s=a===o?i&&i.array:e&&e.array,u=a>n?0:n-a,c=r-a;return c>v&&(c=v),function(){if(u===c)return bt;var e=t?--c:u++;return s&&s[e]}}(e,u):function(e,o,i){var s,u=e&&e.array,c=i>n?0:n-i>>o,l=1+(r-i>>o);return l>v&&(l=v),function(){for(;;){if(s){var e=s();if(e!==bt)return e;s=null}if(c===l)return bt;var n=t?--l:c++;s=a(u&&u[n],o-m,i+(n<>>n&g,u=e&&s0){var c=e&&e.array[s],l=Et(c,t,n-m,r,o,i);return l===c?e:((a=St(e,t)).array[s]=l,a)}return u&&e.array[s]===o?e:(x(i),a=St(e,t),void 0===o&&s===a.array.length-1?a.array.pop():a.array[s]=o,a)}function St(e,t){return t&&e&&t===e.ownerID?e:new vt(e?e.array.slice():[],t)}function Ct(e,t){if(t>=At(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&g],r-=m;return n}}function kt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new E,o=e._origin,i=e._capacity,a=o+t,s=void 0===n?i:n<0?i+n:o+n;if(a===o&&s===i)return e;if(a>=s)return e.clear();for(var u=e._level,c=e._root,l=0;a+l<0;)c=new vt(c&&c.array.length?[void 0,c]:[],r),l+=1<<(u+=m);l&&(a+=l,o+=l,s+=l,i+=l);for(var p=At(i),f=At(s);f>=1<p?new vt([],r):h;if(h&&f>p&&am;y-=m){var b=p>>>y&g;v=v.array[b]=St(v.array[b],r)}v.array[p>>>m&g]=h}if(s=f)a-=f,s-=f,u=m,c=null,d=d&&d.removeBefore(r,0,a);else if(a>o||f>>u&g;if(_!==f>>>u&g)break;_&&(l+=(1<o&&(c=c.removeBefore(r,u,a-l)),c&&fi&&(i=c.size),a(u)||(c=c.map(function(e){return pe(e)})),r.push(c)}return i>e.size&&(e=e.setSize(i)),at(e,t,r)}function At(e){return e>>m<=v&&a.size>=2*i.size?(r=(o=a.filter(function(e,t){return void 0!==e&&s!==t})).toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=i.remove(t),o=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=i,o=a.set(s,[t,n])}else r=i.set(t,a.size),o=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Pt(r,o)}function Nt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Rt(e){this._iter=e,this.size=e.size}function Dt(e){this._iter=e,this.size=e.size}function Lt(e){this._iter=e,this.size=e.size}function Ut(e){var t=en(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=tn,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===N){var r=e.__iterator(t,n);return new U(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===M?I:M,n)},t}function qt(e,t,n){var r=en(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var i=e.get(r,y);return i===y?o:t.call(n,i,r,e)},r.__iterateUncached=function(r,o){var i=this;return e.__iterate(function(e,o,a){return!1!==r(t.call(n,e,o,a),o,i)},o)},r.__iteratorUncached=function(r,o){var i=e.__iterator(N,o);return new U(function(){var o=i.next();if(o.done)return o;var a=o.value,s=a[0];return q(r,s,t.call(n,a[1],s,e),o)})},r}function Ft(e,t){var n=en(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Ut(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=tn,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function Bt(e,t,n,r){var o=en(e);return r&&(o.has=function(r){var o=e.get(r,y);return o!==y&&!!t.call(n,o,r,e)},o.get=function(r,o){var i=e.get(r,y);return i!==y&&t.call(n,i,r,e)?i:o}),o.__iterateUncached=function(o,i){var a=this,s=0;return e.__iterate(function(e,i,u){if(t.call(n,e,i,u))return s++,o(e,r?i:s-1,a)},i),s},o.__iteratorUncached=function(o,i){var a=e.__iterator(N,i),s=0;return new U(function(){for(;;){var i=a.next();if(i.done)return i;var u=i.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return q(o,r?c:s++,l,i)}})},o}function zt(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),A(t,n,o))return e;var i=T(t,o),a=j(n,o);if(i!=i||a!=a)return zt(e.toSeq().cacheResult(),t,n,r);var s,u=a-i;u==u&&(s=u<0?0:u);var c=en(e);return c.size=0===s?s:e.size&&s||void 0,!r&&oe(e)&&s>=0&&(c.get=function(t,n){return(t=k(this,t))>=0&&ts)return{value:void 0,done:!0};var e=o.next();return r||t===M?e:q(t,u-1,t===I?void 0:e.value[1],e)})},c}function Vt(e,t,n,r){var o=en(e);return o.__iterateUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterate(o,i);var s=!0,u=0;return e.__iterate(function(e,i,c){if(!s||!(s=t.call(n,e,i,c)))return u++,o(e,r?i:u-1,a)}),u},o.__iteratorUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterator(o,i);var s=e.__iterator(N,i),u=!0,c=0;return new U(function(){var e,i,l;do{if((e=s.next()).done)return r||o===M?e:q(o,c++,o===I?void 0:e.value[1],e);var p=e.value;i=p[0],l=p[1],u&&(u=t.call(n,l,i,a))}while(u);return o===N?e:q(o,i,l,e)})},o}function Ht(e,t){var n=s(e),o=[e].concat(t).map(function(e){return a(e)?n&&(e=r(e)):e=n?ae(e):se(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===o.length)return e;if(1===o.length){var i=o[0];if(i===e||n&&s(i)||u(e)&&u(i))return i}var c=new ee(o);return n?c=c.toKeyedSeq():u(e)||(c=c.toSetSeq()),(c=c.flatten(!0)).size=o.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),c}function Wt(e,t,n){var r=en(e);return r.__iterateUncached=function(r,o){var i=0,s=!1;return function e(u,c){var l=this;u.__iterate(function(o,u){return(!t||c0}function $t(e,t,r){var o=en(e);return o.size=new ee(r).map(function(e){return e.size}).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(M,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var i=r.map(function(e){return e=n(e),V(o?e.reverse():e)}),a=0,s=!1;return new U(function(){var n;return s||(n=i.map(function(e){return e.next()}),s=n.some(function(e){return e.done})),s?{value:void 0,done:!0}:q(e,a++,t.apply(null,n.map(function(e){return e.value})))})},o}function Gt(e,t){return oe(e)?t:e.constructor(t)}function Zt(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Xt(e){return Le(e.size),C(e)}function Qt(e){return s(e)?r:u(e)?o:i}function en(e){return Object.create((s(e)?K:u(e)?Y:$).prototype)}function tn(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function nn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):An(e,t)},En.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Le(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):An(t,n)},En.prototype.pop=function(){return this.slice(1)},En.prototype.unshift=function(){return this.push.apply(this,arguments)},En.prototype.unshiftAll=function(e){return this.pushAll(e)},En.prototype.shift=function(){return this.pop.apply(this,arguments)},En.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Tn()},En.prototype.slice=function(e,t){if(A(e,t,this.size))return this;var n=T(e,this.size);if(j(t,this.size)!==this.size)return we.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):An(r,o)},En.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?An(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},En.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},En.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new U(function(){if(r){var t=r.value;return r=r.next,q(e,n++,t)}return{value:void 0,done:!0}})},En.isStack=Sn;var Cn,kn="@@__IMMUTABLE_STACK__@@",On=En.prototype;function An(e,t,n,r){var o=Object.create(On);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Tn(){return Cn||(Cn=An(0))}function jn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}On[kn]=!0,On.withMutations=ze.withMutations,On.asMutable=ze.asMutable,On.asImmutable=ze.asImmutable,On.wasAltered=ze.wasAltered,n.Iterator=U,jn(n,{toArray:function(){Le(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new Rt(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new Nt(this,!0)},toMap:function(){return Ue(this.toKeyedSeq())},toObject:function(){Le(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Tt(this.toKeyedSeq())},toOrderedSet:function(){return gn(s(this)?this.valueSeq():this)},toSet:function(){return cn(s(this)?this.valueSeq():this)},toSetSeq:function(){return new Dt(this)},toSeq:function(){return u(this)?this.toIndexedSeq():s(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return En(s(this)?this.valueSeq():this)},toList:function(){return ft(s(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){var t=e.call(arguments,0);return Gt(this,Ht(this,t))},includes:function(e){return this.some(function(t){return de(t,e)})},entries:function(){return this.__iterator(N)},every:function(e,t){Le(this.size);var n=!0;return this.__iterate(function(r,o,i){if(!e.call(t,r,o,i))return n=!1,!1}),n},filter:function(e,t){return Gt(this,Bt(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Le(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Le(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!=r?r.toString():""}),t},keys:function(){return this.__iterator(I)},map:function(e,t){return Gt(this,qt(this,e,t))},reduce:function(e,t,n){var r,o;return Le(this.size),arguments.length<2?o=!0:r=t,this.__iterate(function(t,i,a){o?(o=!1,r=t):r=e.call(n,r,t,i,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Gt(this,Ft(this,!0))},slice:function(e,t){return Gt(this,zt(this,e,t,!0))},some:function(e,t){return!this.every(Rn(e),t)},sort:function(e){return Gt(this,Jt(this,e))},values:function(){return this.__iterator(M)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return C(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return function(e,t,n){var r=Ue().asMutable();return e.__iterate(function(o,i){r.update(t.call(n,o,i,e),0,function(e){return e+1})}),r.asImmutable()}(this,e,t)},equals:function(e){return me(this,e)},entrySeq:function(){var e=this;if(e._cache)return new ee(e._cache);var t=e.toSeq().map(Nn).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Rn(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,o,i){if(e.call(t,n,o,i))return r=[o,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(O)},flatMap:function(e,t){return Gt(this,function(e,t,n){var r=Qt(e);return e.toSeq().map(function(o,i){return r(t.call(n,o,i,e))}).flatten(!0)}(this,e,t))},flatten:function(e){return Gt(this,Wt(this,e,!0))},fromEntrySeq:function(){return new Lt(this)},get:function(e,t){return this.find(function(t,n){return de(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,o=rn(e);!(n=o.next()).done;){var i=n.value;if((r=r&&r.get?r.get(i,y):y)===y)return t}return r},groupBy:function(e,t){return function(e,t,n){var r=s(e),o=(l(e)?Tt():Ue()).asMutable();e.__iterate(function(i,a){o.update(t.call(n,i,a,e),function(e){return(e=e||[]).push(r?[a,i]:i),e})});var i=Qt(e);return o.map(function(t){return Gt(e,i(t))})}(this,e,t)},has:function(e){return this.get(e,y)!==y},hasIn:function(e){return this.getIn(e,y)!==y},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey(function(t){return de(t,e)})},keySeq:function(){return this.toSeq().map(Mn).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return Kt(this,e)},maxBy:function(e,t){return Kt(this,t,e)},min:function(e){return Kt(this,e?Dn(e):qn)},minBy:function(e,t){return Kt(this,t?Dn(t):qn,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Gt(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Gt(this,Vt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Rn(e),t)},sortBy:function(e,t){return Gt(this,Jt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Gt(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Gt(this,function(e,t,n){var r=en(e);return r.__iterateUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterate(r,o);var a=0;return e.__iterate(function(e,o,s){return t.call(n,e,o,s)&&++a&&r(e,o,i)}),a},r.__iteratorUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterator(r,o);var a=e.__iterator(N,o),s=!0;return new U(function(){if(!s)return{value:void 0,done:!0};var e=a.next();if(e.done)return e;var o=e.value,u=o[0],c=o[1];return t.call(n,c,u,i)?r===N?e:q(r,u,c,e):(s=!1,{value:void 0,done:!0})})},r}(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Rn(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=function(e){if(e.size===1/0)return 0;var t=l(e),n=s(e),r=t?1:0;return function(e,t){return t=Ee(t,3432918353),t=Ee(t<<15|t>>>-15,461845907),t=Ee(t<<13|t>>>-13,5),t=Ee((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Se((t=Ee(t^t>>>13,3266489909))^t>>>16)}(e.__iterate(n?t?function(e,t){r=31*r+Fn(Ce(e),Ce(t))|0}:function(e,t){r=r+Fn(Ce(e),Ce(t))|0}:t?function(e){r=31*r+Ce(e)|0}:function(e){r=r+Ce(e)|0}),r)}(this))}});var Pn=n.prototype;Pn[p]=!0,Pn[L]=Pn.values,Pn.__toJS=Pn.toArray,Pn.__toStringMapper=Ln,Pn.inspect=Pn.toSource=function(){return this.toString()},Pn.chain=Pn.flatMap,Pn.contains=Pn.includes,jn(r,{flip:function(){return Gt(this,Ut(this))},mapEntries:function(e,t){var n=this,r=0;return Gt(this,this.toSeq().map(function(o,i){return e.call(t,[i,o],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Gt(this,this.toSeq().flip().map(function(r,o){return e.call(t,r,o,n)}).flip())}});var In=r.prototype;function Mn(e,t){return t}function Nn(e,t){return[t,e]}function Rn(e){return function(){return!e.apply(this,arguments)}}function Dn(e){return function(){return-e.apply(this,arguments)}}function Ln(e){return"string"==typeof e?JSON.stringify(e):String(e)}function Un(){return S(arguments)}function qn(e,t){return et?-1:0}function Fn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return In[f]=!0,In[L]=Pn.entries,In.__toJS=Pn.toObject,In.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+Ln(e)},jn(o,{toKeyedSeq:function(){return new Nt(this,!1)},filter:function(e,t){return Gt(this,Bt(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Gt(this,Ft(this,!1))},slice:function(e,t){return Gt(this,zt(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=T(e,e<0?this.count():this.size);var r=this.slice(0,e);return Gt(this,1===n?r:r.concat(S(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Gt(this,Wt(this,e,!1))},get:function(e,t){return(e=k(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=k(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,o,i,a,s=e.textContent,u=0,c=s[0],l=1,p=e.innerHTML="",f=0;r=n,n=f<7&&"\\"==n?1:l;){if(l=c,c=s[++u],i=p.length>1,!l||f>8&&"\n"==l||[/\S/.test(l),1,1,!/[$\w]/.test(l),("/"==n||"\n"==n)&&i,'"'==n&&i,"'"==n&&i,s[u-4]+r+n=="--\x3e",r+n=="*/"][f])for(p&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][f?f<3?2:f>6?4:f>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(p):0]),a.appendChild(t.createTextNode(p))),o=f&&f<7?f:o,p="",f=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(l),/[\])]/.test(l),/[$\w]/.test(l),"/"==l&&o<2&&"<"!=n,'"'==l,"'"==l,l+c+s[u+1]+s[u+2]=="\x3c!--",l+c=="/*",l+c=="//","#"==l][--f];);p+=l}}(e)}function Q(e){var t;if([/filename\*=[^']+'\w*'"([^"]+)";?/i,/filename\*=[^']+'\w*'([^;]+);?/i,/filename="([^;]*);?"/i,/filename=([^;]*);?/i].some(function(n){return null!==(t=n.exec(e))}),null!==t&&t.length>1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function ee(e){return t=e.replace(/\.[^.\/]*$/,""),b()(g()(t));var t}var te=function(e,t){if(e>t)return"Value must be less than Maximum"},ne=function(e,t){if(et)return"Value must be less than MaxLength"},pe=function(e,t){if(e.length2&&void 0!==arguments[2]?arguments[2]:{},r=n.isOAS3,o=void 0!==r&&r,i=n.bypassRequiredCheck,a=void 0!==i&&i,s=[],u=e.get("required"),c=Object(P.a)(e,{isOAS3:o}),p=c.schema,h=c.parameterContentMediaType;if(!p)return s;var m=p.get("required"),v=p.get("maximum"),g=p.get("minimum"),y=p.get("type"),b=p.get("format"),_=p.get("maxLength"),w=p.get("minLength"),x=p.get("pattern");if(y&&(u||m||t)){var E="string"===y&&t,S="array"===y&&l()(t)&&t.length,C="array"===y&&d.a.List.isList(t)&&t.count(),k="array"===y&&"string"==typeof t&&t,O="file"===y&&t instanceof A.a.File,T="boolean"===y&&(t||!1===t),j="number"===y&&(t||0===t),I="integer"===y&&(t||0===t),M="object"===y&&"object"===f()(t)&&null!==t,N="object"===y&&"string"==typeof t&&t,R=[E,S,C,k,O,T,j,I,M,N],D=R.some(function(e){return!!e});if((u||m)&&!D&&!a)return s.push("Required field is not provided"),s;if("object"===y&&"string"==typeof t&&(null===h||"application/json"===h))try{JSON.parse(t)}catch(e){return s.push("Parameter string value must be valid JSON"),s}if(x){var L=fe(t,x);L&&s.push(L)}if(_||0===_){var U=le(t,_);U&&s.push(U)}if(w){var q=pe(t,w);q&&s.push(q)}if(v||0===v){var F=te(t,v);F&&s.push(F)}if(g||0===g){var B=ne(t,g);B&&s.push(B)}if("string"===y){var z;if(!(z="date-time"===b?ue(t):"uuid"===b?ce(t):se(t)))return s;s.push(z)}else if("boolean"===y){var V=ae(t);if(!V)return s;s.push(V)}else if("number"===y){var H=re(t);if(!H)return s;s.push(H)}else if("integer"===y){var W=oe(t);if(!W)return s;s.push(W)}else if("array"===y){var J;if(!C||!t.count())return s;J=p.getIn(["items","type"]),t.forEach(function(e,t){var n;"number"===J?n=re(e):"integer"===J?n=oe(e):"string"===J&&(n=se(e)),n&&s.push({index:t,error:n})})}else if("file"===y){var K=ie(t);if(!K)return s;s.push(K)}}return s},de=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return Object(k.memoizedCreateXMLExample)(e,n)}var i=Object(k.memoizedSampleFromSchema)(e,n);return"object"===f()(i)?o()(i,null,2):i},me=function(){var e={},t=A.a.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)n.hasOwnProperty(r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},ve=function(t){return(t instanceof e?t:new e(t.toString(),"utf-8")).toString("base64")},ge={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},ye=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},be=function(e,t,n){return!!E()(n,function(n){return C()(e[n],t[n])})};function _e(e){return"string"!=typeof e||""===e?"":Object(m.sanitizeUrl)(e)}function we(e){if(!d.a.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&u()(e.get("content")||{}).length>0}),n=e.get("default")||d.a.OrderedMap(),r=(n.get("content")||d.a.OrderedMap()).keySeq().toJS().length?n:null;return t||r}var xe=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"%20"):""},Ee=function(e){return j()(xe(e).replace(/%20/g,"_"))},Se=function(e){return e.filter(function(e,t){return/^x-/.test(t)})},Ce=function(e){return e.filter(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)})};function ke(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==f()(e)||l()(e)||null===e||!t)return e;var r=a()({},e);return u()(r).forEach(function(e){e===t&&n(r[e],e)?delete r[e]:r[e]=ke(r[e],t,n)}),r}function Oe(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"===f()(e)&&null!==e)try{return o()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function Ae(e){return"number"==typeof e?e.toString():e}function Te(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.returnAll,r=void 0!==n&&n,o=t.allowHashes,i=void 0===o||o;if(!d.a.Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");var a=e.get("name"),s=e.get("in"),u=[];return e&&e.hashCode&&s&&a&&i&&u.push("".concat(s,".").concat(a,".hash-").concat(e.hashCode())),s&&a&&u.push("".concat(s,".").concat(a)),u.push(a),r?u:u[0]||""}function je(e,t){return Te(e,{returnAll:!0}).map(function(e){return t[e]}).filter(function(e){return void 0!==e})[0]}function Pe(){return Me(M()(32).toString("base64"))}function Ie(e){return Me(R()("sha256").update(e).digest("base64"))}function Me(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}}).call(this,n(64).Buffer)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){var r=n(54);function o(e,t){for(var n=0;n1?t-1:0),o=1;o2?n-2:0),i=2;i>",i={listOf:function(e){return c(e,"List",r.List.isList)},mapOf:function(e,t){return l(e,t,"Map",r.Map.isMap)},orderedMapOf:function(e,t){return l(e,t,"OrderedMap",r.OrderedMap.isOrderedMap)},setOf:function(e){return c(e,"Set",r.Set.isSet)},orderedSetOf:function(e){return c(e,"OrderedSet",r.OrderedSet.isOrderedSet)},stackOf:function(e){return c(e,"Stack",r.Stack.isStack)},iterableOf:function(e){return c(e,"Iterable",r.Iterable.isIterable)},recordOf:function(e){return s(function(t,n,o,i,s){for(var u=arguments.length,c=Array(u>5?u-5:0),l=5;l6?u-6:0),l=6;l5?c-5:0),p=5;p5?i-5:0),s=5;s key("+l[p]+")"].concat(a));if(h instanceof Error)return h}})).apply(void 0,i);var u})}function p(e){var t=void 0===arguments[1]?"Iterable":arguments[1],n=void 0===arguments[2]?r.Iterable.isIterable:arguments[2];return s(function(r,o,i,s,u){for(var c=arguments.length,l=Array(c>5?c-5:0),p=5;p4)}function u(e){var t=e.get("swagger");return"string"==typeof t&&t.startsWith("2.0")}function c(e){return function(t,n){return function(r){return n&&n.specSelectors&&n.specSelectors.specJson?s(n.specSelectors.specJson())?a.a.createElement(e,o()({},r,n,{Ori:t})):a.a.createElement(t,r):(console.warn("OAS3 wrapper: couldn't get spec"),null)}}}},function(e,t,n){"use strict";
    -/*
    -object-assign
    -(c) Sindre Sorhus
    -@license MIT
    -*/var r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable;function a(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map(function(e){return t[e]}).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach(function(e){r[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=a(e),c=1;c0){var o=n.map(function(e){return console.error(e),e.line=e.fullPath?g(y,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",A()(e,"message",{enumerable:!0,value:e.message}),e});i.newThrownErrBatch(o)}return r.updateResolved(t)})}},_e=[],we=V()(k()(S.a.mark(function e(){var t,n,r,o,i,a,s,u,c,l,p,f,h,d,m,v,g;return S.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=_e.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,i=o.resolveSubtree,a=o.AST,s=void 0===a?{}:a,u=t.specSelectors,c=t.specActions,i){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return l=s.getLineNumberForPath?s.getLineNumberForPath:function(){},p=u.specStr(),f=t.getConfigs(),h=f.modelPropertyMacro,d=f.parameterMacro,m=f.requestInterceptor,v=f.responseInterceptor,e.prev=11,e.next=14,_e.reduce(function(){var e=k()(S.a.mark(function e(t,o){var a,s,c,f,g,y,b;return S.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return a=e.sent,s=a.resultMap,c=a.specWithCurrentSubtrees,e.next=7,i(c,o,{baseDoc:u.url(),modelPropertyMacro:h,parameterMacro:d,requestInterceptor:m,responseInterceptor:v});case 7:return f=e.sent,g=f.errors,y=f.spec,r.allErrors().size&&n.clearBy(function(e){return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!e.get("fullPath").every(function(e,t){return e===o[t]||void 0===o[t]})}),j()(g)&&g.length>0&&(b=g.map(function(e){return e.line=e.fullPath?l(p,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",A()(e,"message",{enumerable:!0,value:e.message}),e}),n.newThrownErrBatch(b)),W()(s,o,y),W()(c,o,y),e.abrupt("return",{resultMap:s,specWithCurrentSubtrees:c});case 15:case"end":return e.stop()}},e)}));return function(t,n){return e.apply(this,arguments)}}(),x.a.resolve({resultMap:(u.specResolvedSubtree([])||Object(R.Map)()).toJS(),specWithCurrentSubtrees:u.specJson().toJS()}));case 14:g=e.sent,delete _e.system,_e=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:c.updateResolvedSubtree([],g.resultMap);case 23:case"end":return e.stop()}},e,null,[[11,19]])})),35),xe=function(e){return function(t){_e.map(function(e){return e.join("@@")}).indexOf(e.join("@@"))>-1||(_e.push(e),_e.system=t,we())}};function Ee(e,t,n,r,o){return{type:X,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}}function Se(e,t,n,r){return{type:X,payload:{path:e,param:t,value:n,isXml:r}}}var Ce=function(e,t){return{type:le,payload:{path:e,value:t}}},ke=function(){return{type:le,payload:{path:[],value:Object(R.Map)()}}},Oe=function(e,t){return{type:ee,payload:{pathMethod:e,isOAS3:t}}},Ae=function(e,t,n,r){return{type:Q,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};function Te(e){return{type:se,payload:{pathMethod:e}}}function je(e,t){return{type:ue,payload:{path:e,value:t,key:"consumes_value"}}}function Pe(e,t){return{type:ue,payload:{path:e,value:t,key:"produces_value"}}}var Ie=function(e,t,n){return{payload:{path:e,method:t,res:n},type:te}},Me=function(e,t,n){return{payload:{path:e,method:t,req:n},type:ne}},Ne=function(e,t,n){return{payload:{path:e,method:t,req:n},type:re}},Re=function(e){return{payload:e,type:oe}},De=function(e){return function(t){var n=t.fn,r=t.specActions,o=t.specSelectors,i=t.getConfigs,a=t.oas3Selectors,s=e.pathName,u=e.method,c=e.operation,l=i(),p=l.requestInterceptor,f=l.responseInterceptor,h=c.toJS();if(c&&c.get("parameters")&&c.get("parameters").filter(function(e){return e&&!0===e.get("allowEmptyValue")}).forEach(function(t){if(o.parameterInclusionSettingFor([s,u],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};var n=Object(J.C)(t,e.parameters);(!n||n&&0===n.size)&&(e.parameters[t.get("name")]="")}}),e.contextUrl=L()(o.url()).toString(),h&&h.operationId?e.operationId=h.operationId:h&&s&&u&&(e.operationId=n.opId(h,s,u)),o.isOAS3()){var d="".concat(s,":").concat(u);e.server=a.selectedServer(d)||a.selectedServer();var m=a.serverVariables({server:e.server,namespace:d}).toJS(),g=a.serverVariables({server:e.server}).toJS();e.serverVariables=_()(m).length?m:g,e.requestContentType=a.requestContentType(s,u),e.responseContentType=a.responseContentType(s,u)||"*/*";var b=a.requestBodyValue(s,u);Object(J.t)(b)?e.requestBody=JSON.parse(b):b&&b.toJS?e.requestBody=b.toJS():e.requestBody=b}var w=y()({},e);w=n.buildRequest(w),r.setRequest(e.pathName,e.method,w);e.requestInterceptor=function(t){var n=p.apply(this,[t]),o=y()({},n);return r.setMutatedRequest(e.pathName,e.method,o),n},e.responseInterceptor=f;var x=v()();return n.execute(e).then(function(t){t.duration=v()()-x,r.setResponse(e.pathName,e.method,t)}).catch(function(t){console.error(t),r.setResponse(e.pathName,e.method,{error:!0,err:q()(t)})})}},Le=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=d()(e,["path","method"]);return function(e){var o=e.fn.fetch,i=e.specSelectors,a=e.specActions,s=i.specJsonWithResolvedSubtrees().toJS(),u=i.operationScheme(t,n),c=i.contentTypeValues([t,n]).toJS(),l=c.requestContentType,p=c.responseContentType,f=/xml/i.test(l),h=i.parameterValues([t,n],f).toJS();return a.executeRequest(Y({},r,{fetch:o,spec:s,pathName:t,method:n,parameters:h,requestContentType:l,scheme:u,responseContentType:p}))}};function Ue(e,t){return{type:ie,payload:{path:e,method:t}}}function qe(e,t){return{type:ae,payload:{path:e,method:t}}}function Fe(e,t,n){return{type:pe,payload:{scheme:e,path:t,method:n}}}},function(e,t,n){var r=n(32),o=n(22),i=n(63),a=n(77),s=n(75),u=function(e,t,n){var c,l,p,f=e&u.F,h=e&u.G,d=e&u.S,m=e&u.P,v=e&u.B,g=e&u.W,y=h?o:o[t]||(o[t]={}),b=y.prototype,_=h?r:d?r[t]:(r[t]||{}).prototype;for(c in h&&(n=t),n)(l=!f&&_&&void 0!==_[c])&&s(y,c)||(p=l?_[c]:n[c],y[c]=h&&"function"!=typeof _[c]?n[c]:v&&l?i(p,r):g&&_[c]==p?function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(p):m&&"function"==typeof p?i(Function.call,p):p,m&&((y.virtual||(y.virtual={}))[c]=p,e&u.R&&b&&!b[c]&&a(b,c,p)))};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t,n){"use strict";var r=n(138),o=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],i=["scalar","sequence","mapping"];e.exports=function(e,t){var n,a;if(t=t||{},Object.keys(t).forEach(function(t){if(-1===o.indexOf(t))throw new r('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')}),this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.defaultStyle=t.defaultStyle||null,this.styleAliases=(n=t.styleAliases||null,a={},null!==n&&Object.keys(n).forEach(function(e){n[e].forEach(function(t){a[String(t)]=e})}),a),-1===i.indexOf(this.kind))throw new r('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){var r=n(197)("wks"),o=n(199),i=n(41).Symbol,a="function"==typeof i;(e.exports=function(e){return r[e]||(r[e]=a&&i[e]||(a?i:o)("Symbol."+e))}).store=r},function(e,t,n){var r=n(214)("wks"),o=n(159),i=n(32).Symbol,a="function"==typeof i;(e.exports=function(e){return r[e]||(r[e]=a&&i[e]||(a?i:o)("Symbol."+e))}).store=r},function(e,t,n){var r=n(41),o=n(72),i=n(81),a=n(97),s=n(153),u=function(e,t,n){var c,l,p,f,h=e&u.F,d=e&u.G,m=e&u.S,v=e&u.P,g=e&u.B,y=d?r:m?r[t]||(r[t]={}):(r[t]||{}).prototype,b=d?o:o[t]||(o[t]={}),_=b.prototype||(b.prototype={});for(c in d&&(n=t),n)p=((l=!h&&y&&void 0!==y[c])?y:n)[c],f=g&&l?s(p,r):v&&"function"==typeof p?s(Function.call,p):p,y&&a(y,c,p,e&u.U),b[c]!=p&&i(b,c,f),v&&_[c]!=p&&(_[c]=p)};r.core=o,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t){var n=Array.isArray;e.exports=n},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=o},function(e,t,n){"use strict";var r=Object.prototype.hasOwnProperty;function o(e,t){return!!e&&r.call(e,t)}var i=/\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;function a(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function s(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}var u=/&([a-z#][a-z0-9]{1,31});/gi,c=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,l=n(463);function p(e,t){var n=0;return o(l,t)?l[t]:35===t.charCodeAt(0)&&c.test(t)&&a(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?s(n):e}var f=/[&<>"]/,h=/[&<>"]/g,d={"&":"&","<":"<",">":">",'"':"""};function m(e){return d[e]}t.assign=function(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=o,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(i,"$1")},t.isValidEntityCode=a,t.fromCodePoint=s,t.replaceEntities=function(e){return e.indexOf("&")<0?e:e.replace(u,p)},t.escapeHtml=function(e){return f.test(e)?e.replace(h,m):e}},function(e,t,n){var r=n(55),o=n(771);e.exports=function(e,t){if(null==e)return{};var n,i,a=o(e,t);if(r){var s=r(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){var r=n(35),o=n(99),i=n(73),a=/"/g,s=function(e,t,n,r){var o=String(i(e)),s="<"+t;return""!==n&&(s+=" "+n+'="'+String(r).replace(a,""")+'"'),s+">"+o+""};e.exports=function(e,t){var n={};n[e]=t(s),r(r.P+r.F*o(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){"use strict";n.r(t),n.d(t,"NEW_THROWN_ERR",function(){return i}),n.d(t,"NEW_THROWN_ERR_BATCH",function(){return a}),n.d(t,"NEW_SPEC_ERR",function(){return s}),n.d(t,"NEW_SPEC_ERR_BATCH",function(){return u}),n.d(t,"NEW_AUTH_ERR",function(){return c}),n.d(t,"CLEAR",function(){return l}),n.d(t,"CLEAR_BY",function(){return p}),n.d(t,"newThrownErr",function(){return f}),n.d(t,"newThrownErrBatch",function(){return h}),n.d(t,"newSpecErr",function(){return d}),n.d(t,"newSpecErrBatch",function(){return m}),n.d(t,"newAuthErr",function(){return v}),n.d(t,"clear",function(){return g}),n.d(t,"clearBy",function(){return y});var r=n(119),o=n.n(r),i="err_new_thrown_err",a="err_new_thrown_err_batch",s="err_new_spec_err",u="err_new_spec_err_batch",c="err_new_auth_err",l="err_clear",p="err_clear_by";function f(e){return{type:i,payload:o()(e)}}function h(e){return{type:a,payload:e}}function d(e){return{type:s,payload:e}}function m(e){return{type:u,payload:e}}function v(e){return{type:c,payload:e}}function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:l,payload:e}}function y(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:p,payload:e}}},function(e,t,n){var r=n(98);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){var r=n(43);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){var r=n(64),o=r.Buffer;function i(e,t){for(var n in e)t[n]=e[n]}function a(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(i(r,t),t.Buffer=a),i(o,a),a.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},a.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},a.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},a.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){var r=n(46),o=n(349),i=n(218),a=Object.defineProperty;t.f=n(50)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){e.exports=!n(82)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){var r=n(366),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();e.exports=i},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";e.exports={debugTool:null}},function(e,t,n){e.exports=n(573)},function(e,t,n){e.exports=n(770)},function(e,t,n){e.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=45)}([function(e,t){e.exports=n(17)},function(e,t){e.exports=n(14)},function(e,t){e.exports=n(26)},function(e,t){e.exports=n(16)},function(e,t){e.exports=n(123)},function(e,t){e.exports=n(60)},function(e,t){e.exports=n(61)},function(e,t){e.exports=n(55)},function(e,t){e.exports=n(2)},function(e,t){e.exports=n(54)},function(e,t){e.exports=n(94)},function(e,t){e.exports=n(28)},function(e,t){e.exports=n(930)},function(e,t){e.exports=n(12)},function(e,t){e.exports=n(192)},function(e,t){e.exports=n(936)},function(e,t){e.exports=n(93)},function(e,t){e.exports=n(193)},function(e,t){e.exports=n(939)},function(e,t){e.exports=n(943)},function(e,t){e.exports=n(944)},function(e,t){e.exports=n(92)},function(e,t){e.exports=n(13)},function(e,t){e.exports=n(146)},function(e,t){e.exports=n(4)},function(e,t){e.exports=n(5)},function(e,t){e.exports=n(946)},function(e,t){e.exports=n(421)},function(e,t){e.exports=n(949)},function(e,t){e.exports=n(52)},function(e,t){e.exports=n(64)},function(e,t){e.exports=n(283)},function(e,t){e.exports=n(272)},function(e,t){e.exports=n(950)},function(e,t){e.exports=n(145)},function(e,t){e.exports=n(951)},function(e,t){e.exports=n(959)},function(e,t){e.exports=n(960)},function(e,t){e.exports=n(961)},function(e,t){e.exports=n(40)},function(e,t){e.exports=n(264)},function(e,t){e.exports=n(37)},function(e,t){e.exports=n(964)},function(e,t){e.exports=n(965)},function(e,t){e.exports=n(966)},function(e,t,n){e.exports=n(50)},function(e,t){e.exports=n(967)},function(e,t){e.exports=n(968)},function(e,t){e.exports=n(969)},function(e,t){e.exports=n(970)},function(e,t,n){"use strict";n.r(t);var r={};n.r(r),n.d(r,"path",function(){return mn}),n.d(r,"query",function(){return vn}),n.d(r,"header",function(){return yn}),n.d(r,"cookie",function(){return bn});var o=n(9),i=n.n(o),a=n(10),s=n.n(a),u=n(5),c=n.n(u),l=n(6),p=n.n(l),f=n(7),h=n.n(f),d=n(0),m=n.n(d),v=n(8),g=n.n(v),y=(n(46),n(15)),b=n.n(y),_=n(20),w=n.n(_),x=n(12),E=n.n(x),S=n(4),C=n.n(S),k=n(22),O=n.n(k),A=n(11),T=n.n(A),j=n(2),P=n.n(j),I=n(1),M=n.n(I),N=n(17),R=n.n(N),D=(n(47),n(26)),L=n.n(D),U=n(23),q=n.n(U),F=n(31),B=n.n(F),z={serializeRes:J,mergeInQueryOrForm:Z};function V(e){return H.apply(this,arguments)}function H(){return(H=R()(C.a.mark(function e(t){var n,r,o,i,a,s=arguments;return C.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(n=s.length>1&&void 0!==s[1]?s[1]:{},"object"===P()(t)&&(t=(n=t).url),n.headers=n.headers||{},z.mergeInQueryOrForm(n),n.headers&&m()(n.headers).forEach(function(e){var t=n.headers[e];"string"==typeof t&&(n.headers[e]=t.replace(/\n+/g," "))}),!n.requestInterceptor){e.next=12;break}return e.next=8,n.requestInterceptor(n);case 8:if(e.t0=e.sent,e.t0){e.next=11;break}e.t0=n;case 11:n=e.t0;case 12:return r=n.headers["content-type"]||n.headers["Content-Type"],/multipart\/form-data/i.test(r)&&(delete n.headers["content-type"],delete n.headers["Content-Type"]),e.prev=14,e.next=17,(n.userFetch||fetch)(n.url,n);case 17:return o=e.sent,e.next=20,z.serializeRes(o,t,n);case 20:if(o=e.sent,!n.responseInterceptor){e.next=28;break}return e.next=24,n.responseInterceptor(o);case 24:if(e.t1=e.sent,e.t1){e.next=27;break}e.t1=o;case 27:o=e.t1;case 28:e.next=38;break;case 30:if(e.prev=30,e.t2=e.catch(14),o){e.next=34;break}throw e.t2;case 34:throw(i=new Error(o.statusText)).statusCode=i.status=o.status,i.responseError=e.t2,i;case 38:if(o.ok){e.next=43;break}throw(a=new Error(o.statusText)).statusCode=a.status=o.status,a.response=o,a;case 43:return e.abrupt("return",o);case 44:case"end":return e.stop()}},e,null,[[14,30]])}))).apply(this,arguments)}var W=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return/(json|xml|yaml|text)\b/.test(e)};function J(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).loadSpec,r=void 0!==n&&n,o={ok:e.ok,url:e.url||t,status:e.status,statusText:e.statusText,headers:K(e.headers)},i=o.headers["content-type"],a=r||W(i);return(a?e.text:e.blob||e.buffer).call(e).then(function(e){if(o.text=e,o.data=e,a)try{var t=function(e,t){return t&&(0===t.indexOf("application/json")||t.indexOf("+json")>0)?JSON.parse(e):q.a.safeLoad(e)}(e,i);o.body=t,o.obj=t}catch(e){o.parseError=e}return o})}function K(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t={};return"function"==typeof e.forEach?(e.forEach(function(e,n){void 0!==t[n]?(t[n]=M()(t[n])?t[n]:[t[n]],t[n].push(e)):t[n]=e}),t):t}function Y(e,t){return t||"undefined"==typeof navigator||(t=navigator),t&&"ReactNative"===t.product?!(!e||"object"!==P()(e)||"string"!=typeof e.uri):"undefined"!=typeof File?e instanceof File:null!==e&&"object"===P()(e)&&"function"==typeof e.pipe}function $(e,t){var n=e.collectionFormat,r=e.allowEmptyValue,o="object"===P()(e)?e.value:e;if(void 0===o&&r)return"";if(Y(o)||"boolean"==typeof o)return o;var i=encodeURIComponent;return t&&(i=B()(o)?function(e){return e}:function(e){return T()(e)}),"object"!==P()(o)||M()(o)?M()(o)?M()(o)&&!n?o.map(i).join(","):"multi"===n?o.map(i):o.map(i).join({csv:",",ssv:"%20",tsv:"%09",pipes:"|"}[n]):i(o):""}function G(e){var t=m()(e).reduce(function(t,n){var r,o=e[n],i=!!o.skipEncoding,a=i?n:encodeURIComponent(n),s=(r=o)&&"object"===P()(r)&&!M()(o);return t[a]=$(s?o:{value:o},i),t},{});return L.a.stringify(t,{encode:!1,indices:!1})||""}function Z(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=void 0===t?"":t,o=e.query,i=e.form;if(i){var a=m()(i).some(function(e){return Y(i[e].value)}),s=e.headers["content-type"]||e.headers["Content-Type"];if(a||/multipart\/form-data/i.test(s)){var u=n(48);e.body=new u,m()(i).forEach(function(t){e.body.append(t,$(i[t],!0))})}else e.body=G(i);delete e.form}if(o){var c=r.split("?"),l=O()(c,2),p=l[0],f=l[1],h="";if(f){var d=L.a.parse(f);m()(o).forEach(function(e){return delete d[e]}),h=L.a.stringify(d,{encode:!0})}var v=function(){for(var e=arguments.length,t=new Array(e),n=0;n0){var o=t(e,n[n.length-1],n);o&&(r=r.concat(o))}if(M()(e)){var i=e.map(function(e,r){return Ce(e,t,n.concat(r))});i&&(r=r.concat(i))}else if(Te(e)){var a=m()(e).map(function(r){return Ce(e[r],t,n.concat(r))});a&&(r=r.concat(a))}return r=Oe(r)}function ke(e){return M()(e)?e:[e]}function Oe(e){var t;return(t=[]).concat.apply(t,he()(e.map(function(e){return M()(e)?Oe(e):e})))}function Ae(e){return e.filter(function(e){return void 0!==e})}function Te(e){return e&&"object"===P()(e)}function je(e){return e&&"function"==typeof e}function Pe(e){if(Ne(e)){var t=e.op;return"add"===t||"remove"===t||"replace"===t}return!1}function Ie(e){return Pe(e)||Ne(e)&&"mutation"===e.type}function Me(e){return Ie(e)&&("add"===e.op||"replace"===e.op||"merge"===e.op||"mergeDeep"===e.op)}function Ne(e){return e&&"object"===P()(e)}function Re(e,t){try{return me.a.getValueByPointer(e,t)}catch(e){return console.error(e),{}}}var De=n(35),Le=n.n(De),Ue=n(36),qe=n(28),Fe=n.n(qe);function Be(e,t){function n(){Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack;for(var e=arguments.length,n=new Array(e),r=0;r-1&&-1===We.indexOf(n)||Je.indexOf(r)>-1||Ke.some(function(e){return r.indexOf(e)>-1})}function $e(e,t){var n=e.split("#"),r=O()(n,2),o=r[0],i=r[1],a=E.a.resolve(o||"",t||"");return i?"".concat(a,"#").concat(i):a}var Ge="application/json, application/yaml",Ze=new RegExp("^([a-z]+://|//)","i"),Xe=Be("JSONRefError",function(e,t,n){this.originalError=n,ie()(this,t||{})}),Qe={},et=new Le.a,tt=[function(e){return"paths"===e[0]&&"responses"===e[3]&&"content"===e[5]&&"example"===e[7]},function(e){return"paths"===e[0]&&"requestBody"===e[3]&&"content"===e[4]&&"example"===e[6]}],nt={key:"$ref",plugin:function(e,t,n,r){var o=r.getInstance(),i=n.slice(0,-1);if(!Ye(i)&&(a=i,!tt.some(function(e){return e(a)}))){var a,s=r.getContext(n).baseDoc;if("string"!=typeof e)return new Xe("$ref: must be a string (JSON-Ref)",{$ref:e,baseDoc:s,fullPath:n});var u,c,l,p=st(e),f=p[0],h=p[1]||"";try{u=s||f?it(f,s):null}catch(t){return at(t,{pointer:h,$ref:e,basePath:u,fullPath:n})}if(function(e,t,n,r){var o=et.get(r);o||(o={},et.set(r,o));var i=function(e){if(0===e.length)return"";return"/".concat(e.map(ht).join("/"))}(n),a="".concat(t||"","#").concat(e),s=i.replace(/allOf\/\d+\/?/g,""),u=r.contextTree.get([]).baseDoc;if(t==u&&mt(s,e))return!0;var c="";if(n.some(function(e){return c="".concat(c,"/").concat(ht(e)),o[c]&&o[c].some(function(e){return mt(e,a)||mt(a,e)})}))return!0;o[s]=(o[s]||[]).concat(a)}(h,u,i,r)&&!o.useCircularStructures){var d=$e(e,u);return e===d?null:_e.replace(n,d)}if(null==u?(l=pt(h),void 0===(c=r.get(l))&&(c=new Xe("Could not resolve reference: ".concat(e),{pointer:h,$ref:e,baseDoc:s,fullPath:n}))):c=null!=(c=ut(u,h)).__value?c.__value:c.catch(function(t){throw at(t,{pointer:h,$ref:e,baseDoc:s,fullPath:n})}),c instanceof Error)return[_e.remove(n),c];var v=$e(e,u),g=_e.replace(i,c,{$$ref:v});if(u&&u!==s)return[g,_e.context(i,{baseDoc:u})];try{if(!function(e,t){var n=[e];return t.path.reduce(function(e,t){return n.push(e[t]),e[t]},e),function e(t){return _e.isObject(t)&&(n.indexOf(t)>=0||m()(t).some(function(n){return e(t[n])}))}(t.value)}(r.state,g)||o.useCircularStructures)return g}catch(e){return null}}}},rt=ie()(nt,{docCache:Qe,absoluteify:it,clearCache:function(e){void 0!==e?delete Qe[e]:m()(Qe).forEach(function(e){delete Qe[e]})},JSONRefError:Xe,wrapError:at,getDoc:ct,split:st,extractFromDoc:ut,fetchJSON:function(e){return Object(Ue.fetch)(e,{headers:{Accept:Ge},loadSpec:!0}).then(function(e){return e.text()}).then(function(e){return q.a.safeLoad(e)})},extract:lt,jsonPointerToArray:pt,unescapeJsonPointerToken:ft}),ot=rt;function it(e,t){if(!Ze.test(e)){if(!t)throw new Xe("Tried to resolve a relative URL, without having a basePath. path: '".concat(e,"' basePath: '").concat(t,"'"));return E.a.resolve(t,e)}return e}function at(e,t){var n;return n=e&&e.response&&e.response.body?"".concat(e.response.body.code," ").concat(e.response.body.message):e.message,new Xe("Could not resolve reference: ".concat(n),t,e)}function st(e){return(e+"").split("#")}function ut(e,t){var n=Qe[e];if(n&&!_e.isPromise(n))try{var r=lt(t,n);return ie()(Q.a.resolve(r),{__value:r})}catch(e){return Q.a.reject(e)}return ct(e).then(function(e){return lt(t,e)})}function ct(e){var t=Qe[e];return t?_e.isPromise(t)?t:Q.a.resolve(t):(Qe[e]=rt.fetchJSON(e).then(function(t){return Qe[e]=t,t}),Qe[e])}function lt(e,t){var n=pt(e);if(n.length<1)return t;var r=_e.getIn(t,n);if(void 0===r)throw new Xe("Could not resolve pointer: ".concat(e," does not exist in document"),{pointer:e});return r}function pt(e){if("string"!=typeof e)throw new TypeError("Expected a string, got a ".concat(P()(e)));return"/"===e[0]&&(e=e.substr(1)),""===e?[]:e.split("/").map(ft)}function ft(e){return"string"!=typeof e?e:Fe.a.unescape(e.replace(/~1/g,"/").replace(/~0/g,"~"))}function ht(e){return Fe.a.escape(e.replace(/~/g,"~0").replace(/\//g,"~1"))}var dt=function(e){return!e||"/"===e||"#"===e};function mt(e,t){if(dt(t))return!0;var n=e.charAt(t.length),r=t.slice(-1);return 0===e.indexOf(t)&&(!n||"/"===n||"#"===n)&&"#"!==r}var vt={key:"allOf",plugin:function(e,t,n,r,o){if(!o.meta||!o.meta.$$ref){var i=n.slice(0,-1);if(!Ye(i)){if(!M()(e)){var a=new TypeError("allOf must be an array");return a.fullPath=n,a}var s=!1,u=o.value;i.forEach(function(e){u&&(u=u[e])}),delete(u=ie()({},u)).allOf;var c=[];return c.push(r.replace(i,{})),e.forEach(function(e,t){if(!r.isObject(e)){if(s)return null;s=!0;var o=new TypeError("Elements in allOf must be objects");return o.fullPath=n,c.push(o)}c.push(r.mergeDeep(i,e));var a=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.specmap,o=n.getBaseUrlForNodePath,i=void 0===o?function(e){return r.getContext([].concat(he()(t),he()(e))).baseDoc}:o,a=n.targetKeys,s=void 0===a?["$ref","$$ref"]:a,u=[];return Ve()(e).forEach(function(){if(s.indexOf(this.key)>-1){var e=this.path,n=t.concat(this.path),o=$e(this.node,i(e));u.push(r.replace(n,o))}}),u}(e,n.slice(0,-1),{getBaseUrlForNodePath:function(e){return r.getContext([].concat(he()(n),[t],he()(e))).baseDoc},specmap:r});c.push.apply(c,he()(a))}),c.push(r.mergeDeep(i,u)),u.$$ref||c.push(r.remove([].concat(i,"$$ref"))),c}}}},gt={key:"parameters",plugin:function(e,t,n,r,o){if(M()(e)&&e.length){var i=ie()([],e),a=n.slice(0,-1),s=ie()({},_e.getIn(r.spec,a));return e.forEach(function(e,t){try{i[t].default=r.parameterMacro(s,e)}catch(e){var o=new Error(e);return o.fullPath=n,o}}),_e.replace(n,i)}return _e.replace(n,e)}},yt={key:"properties",plugin:function(e,t,n,r){var o=ie()({},e);for(var i in e)try{o[i].default=r.modelPropertyMacro(o[i])}catch(e){var a=new Error(e);return a.fullPath=n,a}return _e.replace(n,o)}};function bt(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}var _t=function(){function e(t){se()(this,e),this.root=wt(t||{})}return ce()(e,[{key:"set",value:function(e,t){var n=this.getParent(e,!0);if(n){var r=e[e.length-1],o=n.children;o[r]?xt(o[r],t,n):o[r]=wt(t,n)}else xt(this.root,t,null)}},{key:"get",value:function(e){if((e=e||[]).length<1)return this.root.value;for(var t,n,r=this.root,o=0;o1?n-1:0),o=1;o1?n-1:0),o=1;o0})}},{key:"nextPromisedPatch",value:function(){if(this.promisedPatches.length>0)return Q.a.race(this.promisedPatches.map(function(e){return e.value}))}},{key:"getPluginHistory",value:function(e){var t=this.getPluginName(e);return this.pluginHistory[t]||[]}},{key:"getPluginRunCount",value:function(e){return this.getPluginHistory(e).length}},{key:"getPluginHistoryTip",value:function(e){var t=this.getPluginHistory(e);return t&&t[t.length-1]||{}}},{key:"getPluginMutationIndex",value:function(e){var t=this.getPluginHistoryTip(e).mutationIndex;return"number"!=typeof t?-1:t}},{key:"getPluginName",value:function(e){return e.pluginName}},{key:"updatePluginHistory",value:function(e,t){var n=this.getPluginName(e);(this.pluginHistory[n]=this.pluginHistory[n]||[]).push(t)}},{key:"updatePatches",value:function(e,t){var n=this;_e.normalizeArray(e).forEach(function(e){if(e instanceof Error)n.errors.push(e);else try{if(!_e.isObject(e))return void n.debug("updatePatches","Got a non-object patch",e);if(n.showDebug&&n.allPatches.push(e),_e.isPromise(e.value))return n.promisedPatches.push(e),void n.promisedPatchThen(e);if(_e.isContextPatch(e))return void n.setContext(e.path,e.value);if(_e.isMutation(e))return void n.updateMutations(e)}catch(e){console.error(e),n.errors.push(e)}})}},{key:"updateMutations",value:function(e){"object"===P()(e.value)&&!M()(e.value)&&this.allowMetaPatches&&(e.value=ie()({},e.value));var t=_e.applyPatch(this.state,e,{allowMetaPatches:this.allowMetaPatches});t&&(this.mutations.push(e),this.state=t)}},{key:"removePromisedPatch",value:function(e){var t=this.promisedPatches.indexOf(e);t<0?this.debug("Tried to remove a promisedPatch that isn't there!"):this.promisedPatches.splice(t,1)}},{key:"promisedPatchThen",value:function(e){var t=this;return e.value=e.value.then(function(n){var r=ie()({},e,{value:n});t.removePromisedPatch(e),t.updatePatches(r)}).catch(function(n){t.removePromisedPatch(e),t.updatePatches(n)})}},{key:"getMutations",value:function(e,t){return e=e||0,"number"!=typeof t&&(t=this.mutations.length),this.mutations.slice(e,t)}},{key:"getCurrentMutations",value:function(){return this.getMutationsForPlugin(this.getCurrentPlugin())}},{key:"getMutationsForPlugin",value:function(e){var t=this.getPluginMutationIndex(e);return this.getMutations(t+1)}},{key:"getCurrentPlugin",value:function(){return this.currentPlugin}},{key:"getPatchesOfType",value:function(e,t){return e.filter(t)}},{key:"getLib",value:function(){return this.libMethods}},{key:"_get",value:function(e){return _e.getIn(this.state,e)}},{key:"_getContext",value:function(e){return this.contextTree.get(e)}},{key:"setContext",value:function(e,t){return this.contextTree.set(e,t)}},{key:"_hasRun",value:function(e){return this.getPluginRunCount(this.getCurrentPlugin())>(e||0)}},{key:"_clone",value:function(e){return JSON.parse(T()(e))}},{key:"dispatch",value:function(){var e=this,t=this,n=this.nextPlugin();if(!n){var r=this.nextPromisedPatch();if(r)return r.then(function(){return e.dispatch()}).catch(function(){return e.dispatch()});var o={spec:this.state,errors:this.errors};return this.showDebug&&(o.patches=this.allPatches),Q.a.resolve(o)}if(t.pluginCount=t.pluginCount||{},t.pluginCount[n]=(t.pluginCount[n]||0)+1,t.pluginCount[n]>100)return Q.a.resolve({spec:t.state,errors:t.errors.concat(new Error("We've reached a hard limit of ".concat(100," plugin runs")))});if(n!==this.currentPlugin&&this.promisedPatches.length){var i=this.promisedPatches.map(function(e){return e.value});return Q.a.all(i.map(function(e){return e.then(Function,Function)})).then(function(){return e.dispatch()})}return function(){t.currentPlugin=n;var e=t.getCurrentMutations(),r=t.mutations.length-1;try{if(n.isGenerator){var o=!0,i=!1,s=void 0;try{for(var u,c=te()(n(e,t.getLib()));!(o=(u=c.next()).done);o=!0){a(u.value)}}catch(e){i=!0,s=e}finally{try{o||null==c.return||c.return()}finally{if(i)throw s}}}else{a(n(e,t.getLib()))}}catch(e){console.error(e),a([ie()(re()(e),{plugin:n})])}finally{t.updatePluginHistory(n,{mutationIndex:r})}return t.dispatch()}();function a(e){e&&(e=_e.fullyNormalizeArray(e),t.updatePatches(e,n))}}}]),e}();var St={refs:ot,allOf:vt,parameters:gt,properties:yt},Ct=n(29),kt=n.n(Ct),Ot=function(e){return String.prototype.toLowerCase.call(e)},At=function(e){return e.replace(/[^\w]/gi,"_")};function Tt(e){var t=e.openapi;return!!t&&w()(t,"3")}function jt(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=(arguments.length>3&&void 0!==arguments[3]?arguments[3]:{}).v2OperationIdCompatibilityMode;return e&&"object"===P()(e)?(e.operationId||"").replace(/\s/g,"").length?At(e.operationId):function(e,t){if((arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).v2OperationIdCompatibilityMode){var n="".concat(t.toLowerCase(),"_").concat(e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|.\/?,\\'""-]/g,"_");return(n=n||"".concat(e.substring(1),"_").concat(t)).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return"".concat(Ot(t)).concat(At(e))}(t,n,{v2OperationIdCompatibilityMode:r}):null}function Pt(e,t){return"".concat(Ot(t),"-").concat(e)}function It(e,t){return e&&e.paths?function(e,t){return Mt(e,t,!0)||null}(e,function(e){var n=e.pathName,r=e.method,o=e.operation;if(!o||"object"!==P()(o))return!1;var i=o.operationId;return[jt(o,n,r),Pt(n,r),i].some(function(e){return e&&e===t})}):null}function Mt(e,t,n){if(!e||"object"!==P()(e)||!e.paths||"object"!==P()(e.paths))return null;var r=e.paths;for(var o in r)for(var i in r[o])if("PARAMETERS"!==i.toUpperCase()){var a=r[o][i];if(a&&"object"===P()(a)){var s={spec:e,pathName:o,method:i.toUpperCase(),operation:a},u=t(s);if(n&&u)return s}}}function Nt(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var o in n){var i=n[o];if(kt()(i)){var a=i.parameters,s=function(e){var n=i[e];if(!kt()(n))return"continue";var s=jt(n,o,e);if(s){r[s]?r[s].push(n):r[s]=[n];var u=r[s];if(u.length>1)u.forEach(function(e,t){e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId="".concat(s).concat(t+1)});else if(void 0!==n.operationId){var c=u[0];c.__originalOperationId=c.__originalOperationId||n.operationId,c.operationId=s}}if("parameters"!==e){var l=[],p={};for(var f in t)"produces"!==f&&"consumes"!==f&&"security"!==f||(p[f]=t[f],l.push(p));if(a&&(p.parameters=a,l.push(p)),l.length)for(var h=0,d=l;h1&&void 0!==arguments[1]?arguments[1]:{},n=t.requestInterceptor,r=t.responseInterceptor,o=e.withCredentials?"include":"same-origin";return function(t){return e({url:t,loadSpec:!0,requestInterceptor:n,responseInterceptor:r,headers:{Accept:Ge},credentials:o}).then(function(e){return e.body})}}function Dt(e){var t=e.fetch,n=e.spec,r=e.url,o=e.mode,i=e.allowMetaPatches,a=void 0===i||i,s=e.pathDiscriminator,u=e.modelPropertyMacro,c=e.parameterMacro,l=e.requestInterceptor,p=e.responseInterceptor,f=e.skipNormalization,h=e.useCircularStructures,d=e.http,m=e.baseDoc;return m=m||r,d=t||d||V,n?v(n):Rt(d,{requestInterceptor:l,responseInterceptor:p})(m).then(v);function v(e){m&&(St.refs.docCache[m]=e),St.refs.fetchJSON=Rt(d,{requestInterceptor:l,responseInterceptor:p});var t,n=[St.refs];return"function"==typeof c&&n.push(St.parameters),"function"==typeof u&&n.push(St.properties),"strict"!==o&&n.push(St.allOf),(t={spec:e,context:{baseDoc:m},plugins:n,allowMetaPatches:a,pathDiscriminator:s,parameterMacro:c,modelPropertyMacro:u,useCircularStructures:h},new Et(t).dispatch()).then(f?function(){var e=R()(C.a.mark(function e(t){return C.a.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",t);case 1:case"end":return e.stop()}},e)}));return function(t){return e.apply(this,arguments)}}():Nt)}}var Lt=n(16),Ut=n.n(Lt);function qt(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Ft(e){for(var t=1;t2&&void 0!==m[2]?m[2]:{},o=r.returnEntireTree,i=r.baseDoc,a=r.requestInterceptor,s=r.responseInterceptor,u=r.parameterMacro,c=r.modelPropertyMacro,l=r.useCircularStructures,p={pathDiscriminator:n,baseDoc:i,requestInterceptor:a,responseInterceptor:s,parameterMacro:u,modelPropertyMacro:c,useCircularStructures:l},f=Nt({spec:t}),h=f.spec,e.next=6,Dt(Ft({},p,{spec:h,allowMetaPatches:!0,skipNormalization:!0}));case 6:return d=e.sent,!o&&M()(n)&&n.length&&(d.spec=Ut()(d.spec,n)||null),e.abrupt("return",d);case 9:case"end":return e.stop()}},e)}))).apply(this,arguments)}var zt=n(38),Vt=n.n(zt);function Ht(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Wt(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=t.pathName,r=t.method,o=t.operationId;return function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.execute(Wt({spec:e.spec},Vt()(e,"requestInterceptor","responseInterceptor","userFetch"),{pathName:n,method:r,parameters:t,operationId:o},i))}}}};var $t=n(39),Gt=n.n($t),Zt=n(40),Xt=n.n(Zt),Qt=n(41),en=n.n(Qt),tn=n(19),nn=n.n(tn),rn=n(42),on=n.n(rn),an={body:function(e){var t=e.req,n=e.value;t.body=n},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},void 0!==r&&(t.headers[n.name]=r)},query:function(e){var t=e.req,n=e.value,r=e.parameter;t.query=t.query||{},!1===n&&"boolean"===r.type&&(n="false");0===n&&["number","integer"].indexOf(r.type)>-1&&(n="0");if(n)t.query[r.name]={collectionFormat:r.collectionFormat,value:n};else if(r.allowEmptyValue&&void 0!==n){var o=r.name;t.query[o]=t.query[o]||{},t.query[o].allowEmptyValue=!0}},path:function(e){var t=e.req,n=e.value,r=e.parameter;t.url=t.url.split("{".concat(r.name,"}")).join(encodeURIComponent(n))},formData:function(e){var t=e.req,n=e.value,r=e.parameter;(n||r.allowEmptyValue)&&(t.form=t.form||{},t.form[r.name]={value:n,allowEmptyValue:r.allowEmptyValue,collectionFormat:r.collectionFormat})}};n(49);var sn=n(43),un=n.n(sn),cn=n(44),ln=function(e){return":/?#[]@!$&'()*+,;=".indexOf(e)>-1},pn=function(e){return/^[a-z0-9\-._~]+$/i.test(e)};function fn(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).escape,n=arguments.length>2?arguments[2]:void 0;return"number"==typeof e&&(e=e.toString()),"string"==typeof e&&e.length&&t?n?JSON.parse(e):Object(cn.stringToCharArray)(e).map(function(e){return pn(e)?e:ln(e)&&"unsafe"===t?e:(un()(e)||[]).map(function(e){return"0".concat(e.toString(16).toUpperCase()).slice(-2)}).map(function(e){return"%".concat(e)}).join("")}).join(""):e}function hn(e){var t=e.value;return M()(t)?function(e){var t=e.key,n=e.value,r=e.style,o=e.explode,i=e.escape,a=function(e){return fn(e,{escape:i})};if("simple"===r)return n.map(function(e){return a(e)}).join(",");if("label"===r)return".".concat(n.map(function(e){return a(e)}).join("."));if("matrix"===r)return n.map(function(e){return a(e)}).reduce(function(e,n){return!e||o?"".concat(e||"",";").concat(t,"=").concat(n):"".concat(e,",").concat(n)},"");if("form"===r){var s=o?"&".concat(t,"="):",";return n.map(function(e){return a(e)}).join(s)}if("spaceDelimited"===r){var u=o?"".concat(t,"="):"";return n.map(function(e){return a(e)}).join(" ".concat(u))}if("pipeDelimited"===r){var c=o?"".concat(t,"="):"";return n.map(function(e){return a(e)}).join("|".concat(c))}}(e):"object"===P()(t)?function(e){var t=e.key,n=e.value,r=e.style,o=e.explode,i=e.escape,a=function(e){return fn(e,{escape:i})},s=m()(n);if("simple"===r)return s.reduce(function(e,t){var r=a(n[t]),i=o?"=":",",s=e?"".concat(e,","):"";return"".concat(s).concat(t).concat(i).concat(r)},"");if("label"===r)return s.reduce(function(e,t){var r=a(n[t]),i=o?"=":".",s=e?"".concat(e,"."):".";return"".concat(s).concat(t).concat(i).concat(r)},"");if("matrix"===r&&o)return s.reduce(function(e,t){var r=a(n[t]),o=e?"".concat(e,";"):";";return"".concat(o).concat(t,"=").concat(r)},"");if("matrix"===r)return s.reduce(function(e,r){var o=a(n[r]),i=e?"".concat(e,","):";".concat(t,"=");return"".concat(i).concat(r,",").concat(o)},"");if("form"===r)return s.reduce(function(e,t){var r=a(n[t]),i=e?"".concat(e).concat(o?"&":","):"",s=o?"=":",";return"".concat(i).concat(t).concat(s).concat(r)},"")}(e):function(e){var t=e.key,n=e.value,r=e.style,o=e.escape,i=function(e){return fn(e,{escape:o})};if("simple"===r)return i(n);if("label"===r)return".".concat(i(n));if("matrix"===r)return";".concat(t,"=").concat(i(n));if("form"===r)return i(n);if("deepObject"===r)return i(n)}(e)}function dn(e,t){return t.includes("application/json")?"string"==typeof e?e:T()(e):e.toString()}function mn(e){var t=e.req,n=e.value,r=e.parameter,o=r.name,i=r.style,a=r.explode,s=r.content;if(s){var u=m()(s)[0];t.url=t.url.split("{".concat(o,"}")).join(fn(dn(n,u),{escape:!0}))}else{var c=hn({key:r.name,value:n,style:i||"simple",explode:a||!1,escape:!0});t.url=t.url.split("{".concat(o,"}")).join(c)}}function vn(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},r.content){var o=m()(r.content)[0];t.query[r.name]=dn(n,o)}else if(!1===n&&(n="false"),0===n&&(n="0"),n){var i=P()(n);if("deepObject"===r.style)m()(n).forEach(function(e){var o=n[e];t.query["".concat(r.name,"[").concat(e,"]")]={value:hn({key:e,value:o,style:"deepObject",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}});else if("object"!==i||M()(n)||"form"!==r.style&&r.style||!r.explode&&void 0!==r.explode){var a=encodeURIComponent(r.name);t.query[a]={value:hn({key:a,value:n,style:r.style||"form",explode:void 0===r.explode||r.explode,escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}}else{m()(n).forEach(function(e){var o=n[e];t.query[e]={value:hn({key:e,value:o,style:r.style||"form",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}})}}else if(r.allowEmptyValue&&void 0!==n){var s=r.name;t.query[s]=t.query[s]||{},t.query[s].allowEmptyValue=!0}}var gn=["accept","authorization","content-type"];function yn(e){var t=e.req,n=e.parameter,r=e.value;if(t.headers=t.headers||{},!(gn.indexOf(n.name.toLowerCase())>-1))if(n.content){var o=m()(n.content)[0];t.headers[n.name]=dn(r,o)}else void 0!==r&&(t.headers[n.name]=hn({key:n.name,value:r,style:n.style||"simple",explode:void 0!==n.explode&&n.explode,escape:!1}))}function bn(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{};var o=P()(r);if(n.content){var i=m()(n.content)[0];t.headers.Cookie="".concat(n.name,"=").concat(dn(r,i))}else if("undefined"!==o){var a="object"===o&&!M()(r)&&n.explode?"":"".concat(n.name,"=");t.headers.Cookie=a+hn({key:n.name,value:r,escape:!1,style:n.style||"form",explode:void 0!==n.explode&&n.explode})}}var _n=n(30),wn=function(e,t){var n=e.operation,r=e.requestBody,o=e.securities,i=e.spec,a=e.attachContentTypeForEmptyPayload,s=e.requestContentType;t=function(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,s=b()({},t),u=r.authorized,c=void 0===u?{}:u,l=i.security||a.security||[],p=c&&!!m()(c).length,f=Ut()(a,["components","securitySchemes"])||{};if(s.headers=s.headers||{},s.query=s.query||{},!m()(r).length||!p||!l||M()(i.security)&&!i.security.length)return t;return l.forEach(function(e,t){for(var n in e){var r=c[n],o=f[n];if(r){var i=r.value||r,a=o.type;if(r)if("apiKey"===a)"query"===o.in&&(s.query[o.name]=i),"header"===o.in&&(s.headers[o.name]=i),"cookie"===o.in&&(s.cookies[o.name]=i);else if("http"===a){if("basic"===o.scheme){var u=i.username,l=i.password,p=nn()("".concat(u,":").concat(l));s.headers.Authorization="Basic ".concat(p)}"bearer"===o.scheme&&(s.headers.Authorization="Bearer ".concat(i))}else if("oauth2"===a){var h=r.token||{},d=h[o["x-tokenName"]||"access_token"],m=h.token_type;m&&"bearer"!==m.toLowerCase()||(m="Bearer"),s.headers.Authorization="".concat(m," ").concat(d)}}}}),s}({request:t,securities:o,operation:n,spec:i});var u=n.requestBody||{},c=m()(u.content||{}),l=s&&c.indexOf(s)>-1;if(r||a){if(s&&l)t.headers["Content-Type"]=s;else if(!s){var p=c[0];p&&(t.headers["Content-Type"]=p,s=p)}}else s&&l&&(t.headers["Content-Type"]=s);return r&&(s?c.indexOf(s)>-1&&("application/x-www-form-urlencoded"===s||0===s.indexOf("multipart/")?"object"===P()(r)?(t.form={},m()(r).forEach(function(e){var n,o,i=r[e];"undefined"!=typeof File&&(o=i instanceof File),"undefined"!=typeof Blob&&(o=o||i instanceof Blob),void 0!==_n.Buffer&&(o=o||_n.Buffer.isBuffer(i)),n="object"!==P()(i)||o?i:M()(i)?i.toString():T()(i),t.form[e]={value:n}})):t.form=r:t.body=r):t.body=r),t};var xn=function(e,t){var n=e.spec,r=e.operation,o=e.securities,i=e.requestContentType,a=e.attachContentTypeForEmptyPayload;if((t=function(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,s=b()({},t),u=r.authorized,c=void 0===u?{}:u,l=r.specSecurity,p=void 0===l?[]:l,f=i.security||p,h=c&&!!m()(c).length,d=a.securityDefinitions;if(s.headers=s.headers||{},s.query=s.query||{},!m()(r).length||!h||!f||M()(i.security)&&!i.security.length)return t;return f.forEach(function(e,t){for(var n in e){var r=c[n];if(r){var o=r.token,i=r.value||r,a=d[n],u=a.type,l=a["x-tokenName"]||"access_token",p=o&&o[l],f=o&&o.token_type;if(r)if("apiKey"===u){var h="query"===a.in?"query":"headers";s[h]=s[h]||{},s[h][a.name]=i}else"basic"===u?i.header?s.headers.authorization=i.header:(i.base64=nn()("".concat(i.username,":").concat(i.password)),s.headers.authorization="Basic ".concat(i.base64)):"oauth2"===u&&p&&(f=f&&"bearer"!==f.toLowerCase()?f:"Bearer",s.headers.authorization="".concat(f," ").concat(p))}}}),s}({request:t,securities:o,operation:r,spec:n})).body||t.form||a)i?t.headers["Content-Type"]=i:M()(r.consumes)?t.headers["Content-Type"]=r.consumes[0]:M()(n.consumes)?t.headers["Content-Type"]=n.consumes[0]:r.parameters&&r.parameters.filter(function(e){return"file"===e.type}).length?t.headers["Content-Type"]="multipart/form-data":r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length&&(t.headers["Content-Type"]="application/x-www-form-urlencoded");else if(i){var s=r.parameters&&r.parameters.filter(function(e){return"body"===e.in}).length>0,u=r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length>0;(s||u)&&(t.headers["Content-Type"]=i)}return t};function En(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Sn(e){for(var t=1;t-1&&(c=o,l=u[p.indexOf(o)])}return!c&&u&&u.length&&(c=u[0].url,l=u[0]),c.indexOf("{")>-1&&function(e){for(var t,n=[],r=/{([^}]+)}/g;t=r.exec(e);)n.push(t[1]);return n}(c).forEach(function(e){if(l.variables&&l.variables[e]){var t=l.variables[e],n=s[e]||t.default,r=new RegExp("{".concat(e,"}"),"g");c=c.replace(r,n)}}),function(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",r=E.a.parse(t),o=E.a.parse(n),i=Pn(r.protocol)||Pn(o.protocol)||"",a=r.host||o.host,s=r.pathname||"";return"/"===(e=i&&a?"".concat(i,"://").concat(a+s):s)[e.length-1]?e.slice(0,-1):e}(c,i)}(b):function(e){var t,n=e.spec,r=e.scheme,o=e.contextUrl,i=void 0===o?"":o,a=E.a.parse(i),s=M()(n.schemes)?n.schemes[0]:null,u=r||s||Pn(a.protocol)||"http",c=n.host||a.host||"",l=n.basePath||"";return"/"===(t=u&&c?"".concat(u,"://").concat(c+l):l)[t.length-1]?t.slice(0,-1):t}(b),!n)return delete g.cookies,g;g.url+=S,g.method="".concat(x).toUpperCase(),h=h||{};var C=t.paths[S]||{};o&&(g.headers.accept=o);var k=An([].concat(Cn(w.parameters)).concat(Cn(C.parameters)));k.forEach(function(e){var n,r=d[e.in];if("body"===e.in&&e.schema&&e.schema.properties&&(n=h),void 0===(n=e&&e.name&&h[e.name])?n=e&&e.name&&h["".concat(e.in,".").concat(e.name)]:On(e.name,k).length>1&&console.warn("Parameter '".concat(e.name,"' is ambiguous because the defined spec has more than one parameter with the name: '").concat(e.name,"' and the passed-in parameter values did not define an 'in' value.")),null!==n){if(void 0!==e.default&&void 0===n&&(n=e.default),void 0===n&&e.required&&!e.allowEmptyValue)throw new Error("Required parameter ".concat(e.name," is not provided"));if(v&&e.schema&&"object"===e.schema.type&&"string"==typeof n)try{n=JSON.parse(n)}catch(e){throw new Error("Could not parse object parameter value string as JSON")}r&&r({req:g,parameter:e,value:n,operation:w,spec:t})}});var O=Sn({},e,{operation:w});if((g=v?wn(O,g):xn(O,g)).cookies&&m()(g.cookies).length){var A=m()(g.cookies).reduce(function(e,t){var n=g.cookies[t];return e+(e?"&":"")+on.a.serialize(t,n)},"");g.headers.Cookie=A}return g.cookies&&delete g.cookies,Z(g),g}var Pn=function(e){return e?e.replace(/\W/g,""):null};function In(e,t){var n=m()(e);if(h.a){var r=h()(e);t&&(r=r.filter(function(t){return p()(e,t).enumerable})),n.push.apply(n,r)}return n}function Mn(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e?n.url=e:n=e,!(this instanceof Mn))return new Mn(n);b()(this,n);var r=this.resolve().then(function(){return t.disableInterfaces||b()(t,Mn.makeApisTagOperation(t)),t});return r.client=this,r}Mn.http=V,Mn.makeHttp=function(e,t,n){return n=n||function(e){return e},t=t||function(e){return e},function(r){return"string"==typeof r&&(r={url:r}),z.mergeInQueryOrForm(r),r=t(r),n(e(r))}}.bind(null,Mn.http),Mn.resolve=Dt,Mn.resolveSubtree=function(e,t){return Bt.apply(this,arguments)},Mn.execute=function(e){var t=e.http,n=e.fetch,r=e.spec,o=e.operationId,i=e.pathName,a=e.method,s=e.parameters,u=e.securities,c=Gt()(e,["http","fetch","spec","operationId","pathName","method","parameters","securities"]),l=t||n||V;i&&a&&!o&&(o=Pt(i,a));var p=Tn.buildRequest(Sn({spec:r,operationId:o,parameters:s,securities:u,http:l},c));return p.body&&(Xt()(p.body)||en()(p.body))&&(p.body=T()(p.body)),l(p)},Mn.serializeRes=J,Mn.serializeHeaders=K,Mn.clearCache=function(){St.refs.clearCache()},Mn.makeApisTagOperation=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=Yt.makeExecute(e);return{apis:Yt.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t})}},Mn.buildRequest=jn,Mn.helpers={opId:jt},Mn.prototype={http:V,execute:function(e){return this.applyDefaults(),Mn.execute(function(e){for(var t=1;t 
    - * @license  MIT
    - */
    -var r=n(569),o=n(570),i=n(355);function a(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function d(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return B(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return B(e).length;t=(""+t).toLowerCase(),r=!0}}function m(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return j(this,t,n);case"utf8":case"utf-8":return k(this,t,n);case"ascii":return A(this,t,n);case"latin1":case"binary":return T(this,t,n);case"base64":return C(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return P(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=u.from(t,r)),u.isBuffer(t))return 0===t.length?-1:y(e,t,n,r,o);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):y(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,n,r,o){var i,a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}function c(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var l=-1;for(i=n;is&&(n=s-u),i=n;i>=0;i--){for(var p=!0,f=0;fo&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function C(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function k(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:c>223?3:c>191?2:1;if(o+p<=n)switch(p){case 1:c<128&&(l=c);break;case 2:128==(192&(i=e[o+1]))&&(u=(31&c)<<6|63&i)>127&&(l=u);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(u=(15&c)<<12|(63&i)<<6|63&a)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:i=e[o+1],a=e[o+2],s=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&s)&&(u=(15&c)<<18|(63&i)<<12|(63&a)<<6|63&s)>65535&&u<1114112&&(l=u)}null===l?(l=65533,p=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=p}return function(e){var t=e.length;if(t<=O)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},u.prototype.compare=function(e,t,n,r,o){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(r>>>=0),a=(n>>>=0)-(t>>>=0),s=Math.min(i,a),c=this.slice(r,o),l=e.slice(t,n),p=0;po)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return _(this,e,t,n);case"ascii":return w(this,e,t,n);case"latin1":case"binary":return x(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var O=4096;function A(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function M(e,t,n,r,o,i){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function N(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function R(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function D(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,i){return i||D(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function U(e,t,n,r,i){return i||D(e,0,n,8),o.write(e,t,n,r,52,8),n+8}u.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},u.prototype.readUInt8=function(e,t){return t||I(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||I(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||I(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||I(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||I(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||I(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},u.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||I(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},u.prototype.readInt8=function(e,t){return t||I(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||I(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt16BE=function(e,t){t||I(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt32LE=function(e,t){return t||I(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||I(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||I(e,4,this.length),o.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||I(e,4,this.length),o.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||I(e,8,this.length),o.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||I(e,8,this.length),o.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||M(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},u.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):R(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);M(this,e,t,n,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+n},u.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);M(this,e,t,n,o-1,-o)}var i=n-1,a=1,s=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+n},u.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):N(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):N(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):R(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||M(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},u.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},u.prototype.writeDoubleLE=function(e,t,n){return U(this,e,t,!0,n)},u.prototype.writeDoubleBE=function(e,t,n){return U(this,e,t,!1,n)},u.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!u.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(q,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function V(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(36))},function(e,t,n){"use strict";e.exports={current:null}},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var u,c=[],l=!1,p=-1;function f(){l&&u&&(l=!1,u.length?c=u.concat(c):p=-1,c.length&&h())}function h(){if(!l){var e=s(f);l=!0;for(var t=c.length;t;){for(u=c,c=[];++p1)for(var n=1;n0&&"/"!==t[0]});function oe(e,t,n){return t=t||[],te.apply(void 0,[e].concat(u()(t))).get("parameters",Object(p.List)()).reduce(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(Object(l.B)(t,{allowHashes:!1}),r)},Object(p.fromJS)({}))}function ie(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(p.List.isList(e))return e.some(function(e){return p.Map.isMap(e)&&e.get("in")===t})}function ae(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(p.List.isList(e))return e.some(function(e){return p.Map.isMap(e)&&e.get("type")===t})}function se(e,t){t=t||[];var n=x(e).getIn(["paths"].concat(u()(t)),Object(p.fromJS)({})),r=e.getIn(["meta","paths"].concat(u()(t)),Object(p.fromJS)({})),o=ue(e,t),i=n.get("parameters")||new p.List,a=r.get("consumes_value")?r.get("consumes_value"):ae(i,"file")?"multipart/form-data":ae(i,"formData")?"application/x-www-form-urlencoded":void 0;return Object(p.fromJS)({requestContentType:a,responseContentType:o})}function ue(e,t){t=t||[];var n=x(e).getIn(["paths"].concat(u()(t)),null);if(null!==n){var r=e.getIn(["meta","paths"].concat(u()(t),["produces_value"]),null),o=n.getIn(["produces",0],null);return r||o||"application/json"}}function ce(e,t){t=t||[];var n=x(e),r=n.getIn(["paths"].concat(u()(t)),null);if(null!==r){var o=t,i=a()(o,1)[0],s=r.get("produces",null),c=n.getIn(["paths",i,"produces"],null),l=n.getIn(["produces"],null);return s||c||l}}function le(e,t){t=t||[];var n=x(e),r=n.getIn(["paths"].concat(u()(t)),null);if(null!==r){var o=t,i=a()(o,1)[0],s=r.get("consumes",null),c=n.getIn(["paths",i,"consumes"],null),l=n.getIn(["consumes"],null);return s||c||l}}var pe=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),i=o()(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||i||""},fe=function(e,t,n){return["http","https"].indexOf(pe(e,t,n))>-1},he=function(e,t){t=t||[];var n=e.getIn(["meta","paths"].concat(u()(t),["parameters"]),Object(p.fromJS)([])),r=!0;return n.forEach(function(e){var t=e.get("errors");t&&t.count()&&(r=!1)}),r};function de(e){return p.Map.isMap(e)?e:new p.Map}},function(e,t,n){"use strict";n.r(t),n.d(t,"SHOW_AUTH_POPUP",function(){return d}),n.d(t,"AUTHORIZE",function(){return m}),n.d(t,"LOGOUT",function(){return v}),n.d(t,"PRE_AUTHORIZE_OAUTH2",function(){return g}),n.d(t,"AUTHORIZE_OAUTH2",function(){return y}),n.d(t,"VALIDATE",function(){return b}),n.d(t,"CONFIGURE_AUTH",function(){return _}),n.d(t,"showDefinitions",function(){return w}),n.d(t,"authorize",function(){return x}),n.d(t,"logout",function(){return E}),n.d(t,"preAuthorizeImplicit",function(){return S}),n.d(t,"authorizeOauth2",function(){return C}),n.d(t,"authorizePassword",function(){return k}),n.d(t,"authorizeApplication",function(){return O}),n.d(t,"authorizeAccessCodeWithFormParams",function(){return A}),n.d(t,"authorizeAccessCodeWithBasicAuthentication",function(){return T}),n.d(t,"authorizeRequest",function(){return j}),n.d(t,"configureAuth",function(){return P});var r=n(26),o=n.n(r),i=n(16),a=n.n(i),s=n(28),u=n.n(s),c=n(95),l=n.n(c),p=n(18),f=n.n(p),h=n(3),d="show_popup",m="authorize",v="logout",g="pre_authorize_oauth2",y="authorize_oauth2",b="validate",_="configure_auth";function w(e){return{type:d,payload:e}}function x(e){return{type:m,payload:e}}function E(e){return{type:v,payload:e}}var S=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,i=e.token,a=e.isValid,s=o.schema,c=o.name,l=s.get("flow");delete f.a.swaggerUIRedirectOauth2,"accessCode"===l||a||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),i.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:u()(i)}):n.authorizeOauth2({auth:o,token:i})}};function C(e){return{type:y,payload:e}}var k=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.name,i=e.username,s=e.password,u=e.passwordType,c=e.clientId,l=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" "),username:i,password:s},f={};switch(u){case"request-body":!function(e,t,n){t&&a()(e,{client_id:t});n&&a()(e,{client_secret:n})}(p,c,l);break;case"basic":f.Authorization="Basic "+Object(h.a)(c+":"+l);break;default:console.warn("Warning: invalid passwordType ".concat(u," was passed, not including client id and secret"))}return n.authorizeRequest({body:Object(h.b)(p),url:r.get("tokenUrl"),name:o,headers:f,query:{},auth:e})}};var O=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,i=e.name,a=e.clientId,s=e.clientSecret,u={Authorization:"Basic "+Object(h.a)(a+":"+s)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:Object(h.b)(c),name:i,url:r.get("tokenUrl"),auth:e,headers:u})}},A=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={grant_type:"authorization_code",code:t.code,client_id:a,client_secret:s,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(h.b)(c),name:i,url:o.get("tokenUrl"),auth:t})}},T=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,s=t.clientSecret,u={Authorization:"Basic "+Object(h.a)(a+":"+s)},c={grant_type:"authorization_code",code:t.code,client_id:a,redirect_uri:n};return r.authorizeRequest({body:Object(h.b)(c),name:i,url:o.get("tokenUrl"),auth:t,headers:u})}},j=function(e){return function(t){var n,r=t.fn,i=t.getConfigs,s=t.authActions,c=t.errActions,p=t.oas3Selectors,f=t.specSelectors,h=t.authSelectors,d=e.body,m=e.query,v=void 0===m?{}:m,g=e.headers,y=void 0===g?{}:g,b=e.name,_=e.url,w=e.auth,x=(h.getConfigs()||{}).additionalQueryStringParams;n=f.isOAS3()?l()(_,p.selectedServer(),!0):l()(_,f.url(),!0),"object"===o()(x)&&(n.query=a()({},n.query,x));var E=n.toString(),S=a()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},y);r.fetch({url:E,method:"post",headers:S,query:v,body:d,requestInterceptor:i().requestInterceptor,responseInterceptor:i().responseInterceptor}).then(function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?c.newAuthErr({authId:b,level:"error",source:"auth",message:u()(t)}):s.authorizeOauth2({auth:w,token:t}):c.newAuthErr({authId:b,level:"error",source:"auth",message:e.statusText})}).catch(function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: ".concat(r.error)),r.error_description&&(t+=", description: ".concat(r.error_description))}catch(e){}}c.newAuthErr({authId:b,level:"error",source:"auth",message:t})})}};function P(e){return{type:_,payload:e}}},function(e,t){var n=e.exports={version:"2.6.5"};"number"==typeof __e&&(__e=n)},function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on  "+e);return e}},function(e,t,n){var r=n(127),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){var r=n(211),o=n(210);e.exports=function(e){return r(o(e))}},function(e,t,n){var r=n(49),o=n(133);e.exports=n(50)?function(e,t,n){return r.f(e,t,o(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return e}},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_LAYOUT",function(){return o}),n.d(t,"UPDATE_FILTER",function(){return i}),n.d(t,"UPDATE_MODE",function(){return a}),n.d(t,"SHOW",function(){return s}),n.d(t,"updateLayout",function(){return u}),n.d(t,"updateFilter",function(){return c}),n.d(t,"show",function(){return l}),n.d(t,"changeMode",function(){return p});var r=n(3),o="layout_update_layout",i="layout_update_filter",a="layout_update_mode",s="layout_show";function u(e){return{type:o,payload:e}}function c(e){return{type:i,payload:e}}function l(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e=Object(r.w)(e),{type:s,payload:{thing:e,shown:t}}}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=Object(r.w)(e),{type:a,payload:{thing:e,mode:t}}}},function(e,t,n){"use strict";(function(t){
    -/*!
    - * @description Recursive object extending
    - * @author Viacheslav Lotsmanov 
    - * @license MIT
    - *
    - * The MIT License (MIT)
    - *
    - * Copyright (c) 2013-2018 Viacheslav Lotsmanov
    - *
    - * Permission is hereby granted, free of charge, to any person obtaining a copy of
    - * this software and associated documentation files (the "Software"), to deal in
    - * the Software without restriction, including without limitation the rights to
    - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
    - * the Software, and to permit persons to whom the Software is furnished to do so,
    - * subject to the following conditions:
    - *
    - * The above copyright notice and this permission notice shall be included in all
    - * copies or substantial portions of the Software.
    - *
    - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    - */
    -function n(e){return e instanceof t||e instanceof Date||e instanceof RegExp}function r(e){if(e instanceof t){var n=t.alloc?t.alloc(e.length):new t(e.length);return e.copy(n),n}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e);throw new Error("Unexpected situation")}function o(e){var t=[];return e.forEach(function(e,i){"object"==typeof e&&null!==e?Array.isArray(e)?t[i]=o(e):n(e)?t[i]=r(e):t[i]=a({},e):t[i]=e}),t}function i(e,t){return"__proto__"===t?void 0:e[t]}var a=e.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var e,t,s=arguments[0],u=Array.prototype.slice.call(arguments,1);return u.forEach(function(u){"object"!=typeof u||null===u||Array.isArray(u)||Object.keys(u).forEach(function(c){return t=i(s,c),(e=i(u,c))===s?void 0:"object"!=typeof e||null===e?void(s[c]=e):Array.isArray(e)?void(s[c]=o(e)):n(e)?void(s[c]=r(e)):"object"!=typeof t||null===t||Array.isArray(t)?void(s[c]=a({},e)):void(s[c]=a(t,e))})}),s}}).call(this,n(64).Buffer)},function(e,t,n){var r=n(151),o=n(336);e.exports=n(126)?function(e,t,n){return r.f(e,t,o(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,n){var r=n(106),o=n(603),i=n(604),a="[object Null]",s="[object Undefined]",u=r?r.toStringTag:void 0;e.exports=function(e){return null==e?void 0===e?s:a:u&&u in Object(e)?o(e):i(e)}},function(e,t,n){var r=n(621),o=n(624);e.exports=function(e,t){var n=o(e,t);return r(n)?n:void 0}},function(e,t,n){var r=n(380),o=n(661),i=n(107);e.exports=function(e){return i(e)?r(e):o(e)}},function(e,t,n){"use strict";var r=n(178),o=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t};e.exports=p;var i=n(137);i.inherits=n(47);var a=n(390),s=n(240);i.inherits(p,a);for(var u=o(s.prototype),c=0;c=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t){e.exports={}},function(e,t,n){n(561);for(var r=n(32),o=n(77),i=n(102),a=n(34)("toStringTag"),s="CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,TextTrackList,TouchList".split(","),u=0;u1){for(var d=Array(h),m=0;m1){for(var g=Array(v),y=0;y=this._finalSize&&(this._update(this._block),this._block.fill(0));var n=8*this._len;if(n<=4294967295)this._block.writeUInt32BE(n,this._blockSize-4);else{var r=(4294967295&n)>>>0,o=(n-r)/4294967296;this._block.writeUInt32BE(o,this._blockSize-8),this._block.writeUInt32BE(r,this._blockSize-4)}this._update(this._block);var i=this._hash();return e?i.toString(e):i},o.prototype._update=function(){throw new Error("_update must be implemented by subclass")},e.exports=o},function(e,t,n){var r=n(63),o=n(406),i=n(407),a=n(46),s=n(158),u=n(225),c={},l={};(t=e.exports=function(e,t,n,p,f){var h,d,m,v,g=f?function(){return e}:u(e),y=r(n,p,t?2:1),b=0;if("function"!=typeof g)throw TypeError(e+" is not iterable!");if(i(g)){for(h=s(e.length);h>b;b++)if((v=t?y(a(d=e[b])[0],d[1]):y(e[b]))===c||v===l)return v}else for(m=g.call(e);!(d=m.next()).done;)if((v=o(m,y,d.value,t))===c||v===l)return v}).BREAK=c,t.RETURN=l},function(e,t,n){"use strict";function r(e){return null==e}e.exports.isNothing=r,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:r(e)?[]:[e]},e.exports.repeat=function(e,t){var n,r="";for(n=0;n1&&void 0!==arguments[1]?arguments[1]:{},r=Object(i.A)(t),a=r.type,s=r.example,u=r.properties,c=r.additionalProperties,l=r.items,p=n.includeReadOnly,f=n.includeWriteOnly;if(void 0!==s)return Object(i.e)(s,"$$ref",function(e){return"string"==typeof e&&e.indexOf("#")>-1});if(!a)if(u)a="object";else{if(!l)return;a="array"}if("object"===a){var d=Object(i.A)(u),m={};for(var v in d)d[v]&&d[v].deprecated||d[v]&&d[v].readOnly&&!p||d[v]&&d[v].writeOnly&&!f||(m[v]=e(d[v],n));if(!0===c)m.additionalProp1={};else if(c)for(var g=Object(i.A)(c),y=e(g,n),b=1;b<4;b++)m["additionalProp"+b]=y;return m}return"array"===a?o()(l.anyOf)?l.anyOf.map(function(t){return e(t,n)}):o()(l.oneOf)?l.oneOf.map(function(t){return e(t,n)}):[e(l,n)]:t.enum?t.default?t.default:Object(i.w)(t.enum)[0]:"file"!==a?h(t):void 0},m=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},v=function e(t){var n,r,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},s=p()({},Object(i.A)(t)),u=s.type,c=s.properties,l=s.additionalProperties,f=s.items,d=s.example,m=a.includeReadOnly,v=a.includeWriteOnly,g=s.default,y={},b={},_=t.xml,w=_.name,x=_.prefix,E=_.namespace,S=s.enum;if(!u)if(c||l)u="object";else{if(!f)return;u="array"}if(n=(x?x+":":"")+(w=w||"notagname"),E){var C=x?"xmlns:"+x:"xmlns";b[C]=E}if("array"===u&&f){if(f.xml=f.xml||_||{},f.xml.name=f.xml.name||_.name,_.wrapped)return y[n]=[],o()(d)?d.forEach(function(t){f.example=t,y[n].push(e(f,a))}):o()(g)?g.forEach(function(t){f.default=t,y[n].push(e(f,a))}):y[n]=[e(f,a)],b&&y[n].push({_attr:b}),y;var k=[];return o()(d)?(d.forEach(function(t){f.example=t,k.push(e(f,a))}),k):o()(g)?(g.forEach(function(t){f.default=t,k.push(e(f,a))}),k):e(f,a)}if("object"===u){var O=Object(i.A)(c);for(var A in y[n]=[],d=d||{},O)if(O.hasOwnProperty(A)&&(!O[A].readOnly||m)&&(!O[A].writeOnly||v))if(O[A].xml=O[A].xml||{},O[A].xml.attribute){var T=o()(O[A].enum)&&O[A].enum[0],j=O[A].example,P=O[A].default;b[O[A].xml.name||A]=void 0!==j&&j||void 0!==d[A]&&d[A]||void 0!==P&&P||T||h(O[A])}else{O[A].xml.name=O[A].xml.name||A,void 0===O[A].example&&void 0!==d[A]&&(O[A].example=d[A]);var I=e(O[A]);o()(I)?y[n]=y[n].concat(I):y[n].push(I)}return!0===l?y[n].push({additionalProp:"Anything can be here"}):l&&y[n].push({additionalProp:h(l)}),b&&y[n].push({_attr:b}),y}return r=void 0!==d?d:void 0!==g?g:o()(S)?S[0]:h(t),y[n]=b?[{_attr:b},r]:r,y};function g(e,t){var n=v(e,t);if(n)return s()(n,{declaration:!0,indent:"\t"})}var y=c()(g),b=c()(d)},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_CONFIGS",function(){return i}),n.d(t,"TOGGLE_CONFIGS",function(){return a}),n.d(t,"update",function(){return s}),n.d(t,"toggle",function(){return u}),n.d(t,"loaded",function(){return c});var r=n(2),o=n.n(r),i="configs_update",a="configs_toggle";function s(e,t){return{type:i,payload:o()({},e,t)}}function u(e){return{type:a,payload:e}}var c=function(){return function(){}}},function(e,t,n){"use strict";n.d(t,"a",function(){return a});var r=n(1),o=n.n(r),i=o.a.Set.of("type","format","items","default","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","maxItems","minItems","uniqueItems","enum","multipleOf");function a(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).isOAS3;if(!o.a.Map.isMap(e))return{schema:o.a.Map(),parameterContentMediaType:null};if(!t)return"body"===e.get("in")?{schema:e.get("schema",o.a.Map()),parameterContentMediaType:null}:{schema:e.filter(function(e,t){return i.includes(t)}),parameterContentMediaType:null};if(e.get("content")){var n=e.get("content",o.a.Map({})).keySeq().first();return{schema:e.getIn(["content",n,"schema"],o.a.Map()),parameterContentMediaType:n}}return{schema:e.get("schema",o.a.Map()),parameterContentMediaType:null}}},function(e,t,n){e.exports=n(781)},function(e,t,n){"use strict";n.r(t);var r=n(469),o="object"==typeof self&&self&&self.Object===Object&&self,i=(r.a||o||Function("return this")()).Symbol,a=Object.prototype,s=a.hasOwnProperty,u=a.toString,c=i?i.toStringTag:void 0;var l=function(e){var t=s.call(e,c),n=e[c];try{e[c]=void 0;var r=!0}catch(e){}var o=u.call(e);return r&&(t?e[c]=n:delete e[c]),o},p=Object.prototype.toString;var f=function(e){return p.call(e)},h="[object Null]",d="[object Undefined]",m=i?i.toStringTag:void 0;var v=function(e){return null==e?void 0===e?d:h:m&&m in Object(e)?l(e):f(e)};var g=function(e,t){return function(n){return e(t(n))}}(Object.getPrototypeOf,Object);var y=function(e){return null!=e&&"object"==typeof e},b="[object Object]",_=Function.prototype,w=Object.prototype,x=_.toString,E=w.hasOwnProperty,S=x.call(Object);var C=function(e){if(!y(e)||v(e)!=b)return!1;var t=g(e);if(null===t)return!0;var n=E.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&x.call(n)==S},k=n(330),O={INIT:"@@redux/INIT"};function A(e,t,n){var r;if("function"==typeof t&&void 0===n&&(n=t,t=void 0),void 0!==n){if("function"!=typeof n)throw new Error("Expected the enhancer to be a function.");return n(A)(e,t)}if("function"!=typeof e)throw new Error("Expected the reducer to be a function.");var o=e,i=t,a=[],s=a,u=!1;function c(){s===a&&(s=a.slice())}function l(){return i}function p(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return c(),s.push(e),function(){if(t){t=!1,c();var n=s.indexOf(e);s.splice(n,1)}}}function f(e){if(!C(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(u)throw new Error("Reducers may not dispatch actions.");try{u=!0,i=o(i,e)}finally{u=!1}for(var t=a=s,n=0;n0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];if(a)throw a;for(var r=!1,o={},s=0;s0?r:n)(e)}},function(e,t){e.exports={}},function(e,t,n){var r=n(348),o=n(215);e.exports=Object.keys||function(e){return r(e,o)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t){e.exports=!0},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){var r=n(49).f,o=n(75),i=n(34)("toStringTag");e.exports=function(e,t,n){e&&!o(e=n?e:e.prototype,i)&&r(e,i,{configurable:!0,value:t})}},function(e,t,n){var r=n(159)("meta"),o=n(43),i=n(75),a=n(49).f,s=0,u=Object.isExtensible||function(){return!0},c=!n(82)(function(){return u(Object.preventExtensions({}))}),l=function(e){a(e,r,{value:{i:"O"+ ++s,w:{}}})},p=e.exports={KEY:r,NEED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,r)){if(!u(e))return"F";if(!t)return"E";l(e)}return e[r].i},getWeak:function(e,t){if(!i(e,r)){if(!u(e))return!0;if(!t)return!1;l(e)}return e[r].w},onFreeze:function(e){return c&&p.NEED&&u(e)&&!i(e,r)&&l(e),e}}},function(e,t,n){"use strict";e.exports=function(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r1&&void 0!==arguments[1]?arguments[1]:[],n={arrayBehaviour:(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).arrayBehaviour||"replace"},r=t.map(function(e){return e||{}}),i=e||{},c=0;c1?t-1:0),r=1;r")}),p=function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();e.exports=function(e,t,n){var f=s(e),h=!i(function(){var t={};return t[f]=function(){return 7},7!=""[e](t)}),d=h?!i(function(){var t=!1,n=/a/;return n.exec=function(){return t=!0,null},"split"===e&&(n.constructor={},n.constructor[c]=function(){return n}),n[f](""),!t}):void 0;if(!h||!d||"replace"===e&&!l||"split"===e&&!p){var m=/./[f],v=n(a,f,""[e],function(e,t,n,r,o){return t.exec===u?h&&!o?{done:!0,value:m.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),g=v[0],y=v[1];r(String.prototype,e,g),o(RegExp.prototype,f,2==t?function(e,t){return y.call(e,this,t)}:function(e){return y.call(e,this)})}}},function(e,t,n){var r=n(212),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(46),o=n(350),i=n(215),a=n(213)("IE_PROTO"),s=function(){},u=function(){var e,t=n(217)("iframe"),r=i.length;for(t.style.display="none",n(351).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("

    Tags

    \ No newline at end of file +Tags |

    Tags

    \ No newline at end of file diff --git a/tags/index.xml b/tags/index.xml index f240332..7a1d646 100644 --- a/tags/index.xml +++ b/tags/index.xml @@ -1 +1 @@ -– Tagshttps://onshape-public.github.io/tags/Recent content in Tags onHugo -- gohugo.ioen-us \ No newline at end of file +Tags onhttps://onshape-public.github.io/tags/Recent content in Tags onHugoen-us \ No newline at end of file diff --git a/webfonts/fa-brands-400.eot b/webfonts/fa-brands-400.eot deleted file mode 100644 index 2cca660..0000000 Binary files a/webfonts/fa-brands-400.eot and /dev/null differ diff --git a/webfonts/fa-brands-400.svg b/webfonts/fa-brands-400.svg deleted file mode 100644 index d9939bc..0000000 --- a/webfonts/fa-brands-400.svg +++ /dev/null @@ -1,3451 +0,0 @@ - - - - - -Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/webfonts/fa-brands-400.ttf b/webfonts/fa-brands-400.ttf index 2cb180b..8c8a402 100644 Binary files a/webfonts/fa-brands-400.ttf and b/webfonts/fa-brands-400.ttf differ diff --git a/webfonts/fa-brands-400.woff b/webfonts/fa-brands-400.woff deleted file mode 100644 index e192c51..0000000 Binary files a/webfonts/fa-brands-400.woff and /dev/null differ diff --git a/webfonts/fa-brands-400.woff2 b/webfonts/fa-brands-400.woff2 index e916d75..64bf1ea 100644 Binary files a/webfonts/fa-brands-400.woff2 and b/webfonts/fa-brands-400.woff2 differ diff --git a/webfonts/fa-regular-400.eot b/webfonts/fa-regular-400.eot deleted file mode 100644 index 54c8991..0000000 Binary files a/webfonts/fa-regular-400.eot and /dev/null differ diff --git a/webfonts/fa-regular-400.svg b/webfonts/fa-regular-400.svg deleted file mode 100644 index e04c2e0..0000000 --- a/webfonts/fa-regular-400.svg +++ /dev/null @@ -1,803 +0,0 @@ - - - - - -Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/webfonts/fa-regular-400.ttf b/webfonts/fa-regular-400.ttf index ef43cfd..3d041f4 100644 Binary files a/webfonts/fa-regular-400.ttf and b/webfonts/fa-regular-400.ttf differ diff --git a/webfonts/fa-regular-400.woff b/webfonts/fa-regular-400.woff deleted file mode 100644 index 13f0191..0000000 Binary files a/webfonts/fa-regular-400.woff and /dev/null differ diff --git a/webfonts/fa-regular-400.woff2 b/webfonts/fa-regular-400.woff2 index 004b29b..ed14925 100644 Binary files a/webfonts/fa-regular-400.woff2 and b/webfonts/fa-regular-400.woff2 differ diff --git a/webfonts/fa-solid-900.eot b/webfonts/fa-solid-900.eot deleted file mode 100644 index 8f11368..0000000 Binary files a/webfonts/fa-solid-900.eot and /dev/null differ diff --git a/webfonts/fa-solid-900.svg b/webfonts/fa-solid-900.svg deleted file mode 100644 index b80d477..0000000 --- a/webfonts/fa-solid-900.svg +++ /dev/null @@ -1,4649 +0,0 @@ - - - - - -Created by FontForge 20190112 at Fri Aug 2 14:41:09 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/webfonts/fa-solid-900.ttf b/webfonts/fa-solid-900.ttf index 5a6d747..19a4d2b 100644 Binary files a/webfonts/fa-solid-900.ttf and b/webfonts/fa-solid-900.ttf differ diff --git a/webfonts/fa-solid-900.woff b/webfonts/fa-solid-900.woff deleted file mode 100644 index d92df45..0000000 Binary files a/webfonts/fa-solid-900.woff and /dev/null differ diff --git a/webfonts/fa-solid-900.woff2 b/webfonts/fa-solid-900.woff2 index df7e704..1acf070 100644 Binary files a/webfonts/fa-solid-900.woff2 and b/webfonts/fa-solid-900.woff2 differ diff --git a/webfonts/fa-v4compatibility.ttf b/webfonts/fa-v4compatibility.ttf new file mode 100644 index 0000000..0b7ac89 Binary files /dev/null and b/webfonts/fa-v4compatibility.ttf differ diff --git a/webfonts/fa-v4compatibility.woff2 b/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 0000000..e7a9381 Binary files /dev/null and b/webfonts/fa-v4compatibility.woff2 differ