{"_id":"56159af421e9110d0078025d","parentDoc":null,"category":{"_id":"57f55187440418170086325a","__v":0,"version":"5588b8a2f6c18d0d005bba06","project":"5588b8a2f6c18d0d005bba03","sync":{"url":"","isSync":false},"reference":true,"createdAt":"2016-10-05T19:16:23.805Z","from_sync":false,"order":1,"slug":"integrations","title":"Message Integrations"},"project":"5588b8a2f6c18d0d005bba03","user":"5588b847f6c18d0d005bba01","__v":25,"version":{"_id":"5588b8a2f6c18d0d005bba06","project":"5588b8a2f6c18d0d005bba03","__v":15,"createdAt":"2015-06-23T01:38:42.696Z","releaseDate":"2015-06-23T01:38:42.696Z","categories":["5588b8a3f6c18d0d005bba07","5588e9689cfea70d00371df3","5588f5921163180d00b64704","561598b121e9110d0078025a","5616f1c9d170d00d00189306","5616f5c3a410c90d00c6121e","561803dcf8c9632100ac7592","563667280441020d0000e9eb","5642570d9417b40d00c0fcd3","57bf5f02efe0050e00d50bd5","57f53fb368a53b2000e03f0f","57f55187440418170086325a","582e3afa72fd270f0006926d","5841faa973967b0f004b4a2b","58db348aa32c8419002433bb"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":["592e7eb017c2b0000f9ce308"],"next":{"pages":[],"description":""},"createdAt":"2015-10-07T22:21:40.615Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":true,"order":1,"body":"Enhancements are accessed by clicking an icon in the Mixmax Enhance menu. Examples include Availability, SMS, and Poll. Each enhancement has an interactive \"editor\" UI that the user can use to configure it, before placing it in the email.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/7zkKJdmWSJ6MOWwba1Qt_image00.png\",\n        \"image00.png\",\n        \"454\",\n        \"418\",\n        \"#3a75d7\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nFor example, when clicking the Poll Enhancement, the enhancement's \"editor\" is shown in a new window:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/OenaLQyRH6cLZ0OZSmAB_image06.png\",\n        \"image06.png\",\n        \"792\",\n        \"764\",\n        \"#386fc8\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOnce the user is done with their input and clicks OK, HTML content generated by the enhancement will be placed in the compose window at the cursor location:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/VqKumDuRTKSiAefubsxV_image08.png\",\n        \"image08.png\",\n        \"602\",\n        \"603\",\n        \"#bd4f46\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nIf the user wishes, they may bring up the enhancement's editor by clicking the pencil icon in the upper right:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/23HlTOTTLapiKiBZFQ1O_image10.png\",\n        \"image10.png\",\n        \"178\",\n        \"134\",\n        \"#91a9de\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen the email is sent, the enhancement may be optionally notified via the “activate” api that is passed information about the particular email it was dropped into.\n\nLet's dive in a bit on what each parameter means, and what is expected of you as the developer to build.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Parameters\"\n}\n[/block]\n## Name\n\nThe name of the enhancement that shows up in the Enhance menu.\n\n## Icon Tooltip\n\nText to display as a tooltip over the icon in the UI.\n\n## Editor URL\n\nURL to show in a new browser window when the enhancement is clicked. The query string parameters “?user=<email>” will be appended to the URL. The ‘user’ parameter is not to be fully trusted since it can be easily modified in the browser address bar. If you need to rely on it (e.g. if you’re creating a database record for this enhancement instance), consider instead using the *activation url*, as that passes the user parameter securely along with other message attributes that you might want to store. The messageId is useful if you want to use the `/messages` REST API to fetch the content of the message (by its `_id`), but it will not be present if the user is inserting your enhancement from a template (where there is no *message* at that time). The editor is required to use the Mixmax [SDK.js](#sdkjs) and call the appropriate function (either `Mixmax.editor.done()` or `Mixmax.editor.cancel()`) to dismiss itself.\n\n## Resolver URL\n\nRESTful API that is called with the enhancement instance parameters that returns the string HTML representation of the app card. See more [information](/docs/integration-api-appendix#client-side-ajax-api-requests) about client-side requests in Mixmax. The following is POSTed to the URL via regular form data:\n  * **params**: JSON object of the enhancement parameters (most likely returned by the editor url via the *sdk.js*).\n  * **messageId**: If the enhancement is being inserted into a message (as opposed to a template), this will have the `_id` of the message. You can use the `/messages/:id` REST API to fetch information about the message.\n\nThis URL is expected to return a JSON object with the following properties:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Parameter\",\n    \"h-1\": \"Type\",\n    \"h-2\": \"Description\",\n    \"0-0\": \"body\",\n    \"0-1\": \"*String*\",\n    \"0-2\": \"The HTML representation that is inserted into the message as a \\\"card\\\" (an immutable island of content in the editor). This can optionally have [variables](/docs/integration-api-appendix#variables-in-emails).\",\n    \"1-0\": \"subject\",\n    \"1-1\": \"*String*\",\n    \"1-2\": \"Optional (defaults to empty string). If this happens to be used inside an email message (as opposed to a Mixmax template or a Mixmax signature) that doesn’t already have a subject set, this will set the subject. For example, if the user is typing “/weather SF, CA” and presses enter, the command could automatically set the subject to “Live weather for SF, CA”\",\n    \"2-0\": \"raw\",\n    \"2-1\": \"*Boolean* \",\n    \"2-2\": \"Optional (defaults to `false`). True if the content should be inserted into the editor as raw HTML (i.e. not an immutable \\\"card\\\"). The user will be able to edit the content. If this is used, the Activate URL does not work.\"\n  },\n  \"cols\": 3,\n  \"rows\": 3\n}\n[/block]\nIf the resolver URL is unable to return content because of invalid user input, it should return an HTTP status code of `400` with the json payload of `{message: \"<failure reason>\"}`. This will show a custom error message in the compose window. If this is not provided, then Could not complete command will be displayed as the default error message.\n\n## Activate URL (optional)\n\nURL that is posted to when the enhancement is being activated (i.e. when it is being sent in a message). It is passed:\n\n  * **user**: Email address of the Mixmax user. This can be trusted since this call originates from the Mixmax backend.\n\n  * **toRecipients**: Array of objects, each with ‘email’ and optional ‘name’ keys, of the recipients in the 'to' field of the email.\n\n  * **ccRecipients**: Array of objects, each with ‘email’ and optional ‘name’ keys, of the recipients in the 'cc' field of the email.\n\n  * **subject**: String subject of the message.\n\n  * **params**: JSON object of the enhancement instance parameters that were originally sent from the Editor.\n\n  * **messageId**: The `_id` of the message, in case you want to use the `/messages/:id` API to fetch more information about the message than what's provided here.\n\n  This API should return an empty 2xx response.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Tutorial: Building Giphy Enhancement\"\n}\n[/block]\n(note: also see our [blog post](https://mixmax.com/blog/giphy-enhancement-sdk))\n\nWe'll walk you through adding an example open source Giphy Picker enhancement.\n\n1. Git clone [https://github.com/mixmaxhq/giphy-mixmax-app](https://github.com/mixmaxhq/giphy-mixmax-app) \n2. Run `npm install` and `npm start`\n3. Restart Chrome in a special temporary mode so the self-signed HTTPS urls can be loaded. See [here](http://developer.mixmax.com/docs/integration-api-appendix#local-development-error-neterr_insecure_response).\n4. Verify it works by visiting https://localhost:8910/editor in your browser. It should load a Giphy image picker UI.\n5. Open up the [Mixmax Dashboard](https://app.mixmax.com/dashboard/settings/developer), click Settings -> Developer -> Add Enhancement.\n6. Enter the following for the inputs:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Input name\",\n    \"h-1\": \"Value\",\n    \"0-0\": \"Name\",\n    \"0-1\": \"My Giphy\",\n    \"1-0\": \"Icon Tooltip\",\n    \"1-1\": \"My Giphy Picker\",\n    \"2-0\": \"Editor URL\",\n    \"2-1\": \"https://localhost:8910/editor\",\n    \"3-0\": \"Resolver API URL\",\n    \"3-1\": \"https://localhost:8910/api/resolver\",\n    \"4-0\": \"Activate API URL\",\n    \"4-1\": \"*leave blank*\"\n  },\n  \"cols\": 2,\n  \"rows\": 5\n}\n[/block]\n7. Refresh Gmail with Mixmax installed. Click Compose and hover over the Enhance menu. You should see the My Giphy enhancement at the top.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Example lifecycle\"\n}\n[/block]\nThis example demonstrates the lifecycle of an example weather enhancement. The enhancement asks the user for their city and inserts a graphic in the email with up-to-date weather for that city.\n\n1. The user chooses to insert your “Weather” enhancement in their Mixmax message. Mixmax launches the *Editor URL* in a new window, which just has a text input that they can enter their city name into. Javascript running in the editor calls `Mixmax.editor.done({city: “San Francisco, CA”})`\n\n2. Mixmax calls the *Resolver URL* and posts the enhancement parameters `{city: “San Francisco, CA”}`. Your resolver returns HTML that is placed inside the editor. In this case, your HTML might just be a dynamically generated image to show the weather, e.g. `<img src=”https://weatherapi.com/img?city=San%20Francisco%2C%20CA”>`.\n\n3. When the user sends their message, the *Activate URL* is called and is sent the enhancement parameters `{city: “San Francisco, CA”}`. Additionally, the recipients of the message are passed so you can keep a record of who it was sent to.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Example enhancement lifecycle if the user edits\"\n}\n[/block]\n1. Same 1 and 2 steps above.\n\n3. The user decides they want to change the city and click the edit button in the card (inside the message). Mixmax re-launches your editor, but this time with `?data=%7Bcity%3A%22San%20Francisco%2C%20CA%22%7D` on the querystring. You show “San Francisco” pre-populated in the text field and they change it to “San Jose, CA”.\n\n4. When they are done editing, the enhancement calls `Mixmax.editor.done({city: “San Jose, CA”})`.\n\n5. Mixmax calls the *Resolver URL* and sends the new enhancement parameters, `{city: “San Jose, CA”}`. The enhancement resolver returns new HTML.\n\n6. When the user sends their message, the *Activate URL* is called.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Example enhancement lifecycle involving templates\"\n}\n[/block]\n1. Same 1 and 2 steps as first example.\n\n3. The user shares the template with Person B.\n\n4. Person B adds the template to their Mixmax message and clicks Send.\n\n5. Mixmax calls the *Activate URL* and is sent the enhancement parameters `{city: “San Francisco, CA”}`, the recipients of the message, and Person B’s email as the ‘user’ since they are the one sending.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"SDK.js\"\n}\n[/block]\nInclude the following line of Javascript in your enhancement's editor (the document hosted at editorUrl):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script defer src=\\\"https://sdk.mixmax.com/v1.1.4/editor.umd.min.js\\\"></script>\",\n      \"language\": \"html\"\n    }\n  ]\n}\n[/block]\nMixmax SDK has two functions that can be called:\n\n`Mixmax.editor.done({ /* params */})` - This is called when your user is finished interacting with the enhancement. For example, this might be called when the user clicks the “OK” button in your editor. Or perhaps if they just need to drag in a file, this is called after the file is uploaded. Be aware that if there is a current value for `window.opener` then this function will close the current tab or window with `window.close()`.\n`Mixmax.editor.cancel()` - This is called if you’d like to cancel the editor. For example, this might be called when the user clicks Cancel in your editor or when they hit the escape key.\n\nIf you're using a JavaScript bundler like [Rollup](https://rollupjs.org/) or [Webpack](https://webpack.github.io/), instead of loading the SDK using a script tag, you can import the SDK from npm like\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"const Mixmax = require(':::at:::mixmaxhq/sdk');\\n// Now access `Mixmax.editor.done` etc. as above.\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nIf your bundler is capable of importing ES6 modules and understands [`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module), you can import the SDK like\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import * as Mixmax from '@mixmaxhq/sdk';\\n\\n// Now access `Mixmax.editor.done` etc. as above.\\n\\n// More concise:\\nimport { editor } from '@mixmaxhq/sdk`;\\n\\n// If your bundler understands [`pkg.browser`](https://github.com/defunctzombie/package-browser-field-spec)\\n// like Rollup does when using rollup-plugin-node-resolve with\\n// [`browser: true`](https://github.com/rollup/rollup-plugin-node-resolve#usage),\\n// you can import _only_ the editor APIs and not the rest of the SDK:\\nimport { done, cancel } from '@mixmaxhq/sdk/editor';\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"overview-enhancement","type":"basic","title":"Enhancements"}
Enhancements are accessed by clicking an icon in the Mixmax Enhance menu. Examples include Availability, SMS, and Poll. Each enhancement has an interactive "editor" UI that the user can use to configure it, before placing it in the email. [block:image] { "images": [ { "image": [ "https://files.readme.io/7zkKJdmWSJ6MOWwba1Qt_image00.png", "image00.png", "454", "418", "#3a75d7", "" ] } ] } [/block] For example, when clicking the Poll Enhancement, the enhancement's "editor" is shown in a new window: [block:image] { "images": [ { "image": [ "https://files.readme.io/OenaLQyRH6cLZ0OZSmAB_image06.png", "image06.png", "792", "764", "#386fc8", "" ] } ] } [/block] Once the user is done with their input and clicks OK, HTML content generated by the enhancement will be placed in the compose window at the cursor location: [block:image] { "images": [ { "image": [ "https://files.readme.io/VqKumDuRTKSiAefubsxV_image08.png", "image08.png", "602", "603", "#bd4f46", "" ] } ] } [/block] If the user wishes, they may bring up the enhancement's editor by clicking the pencil icon in the upper right: [block:image] { "images": [ { "image": [ "https://files.readme.io/23HlTOTTLapiKiBZFQ1O_image10.png", "image10.png", "178", "134", "#91a9de", "" ] } ] } [/block] When the email is sent, the enhancement may be optionally notified via the “activate” api that is passed information about the particular email it was dropped into. Let's dive in a bit on what each parameter means, and what is expected of you as the developer to build. [block:api-header] { "type": "basic", "title": "Parameters" } [/block] ## Name The name of the enhancement that shows up in the Enhance menu. ## Icon Tooltip Text to display as a tooltip over the icon in the UI. ## Editor URL URL to show in a new browser window when the enhancement is clicked. The query string parameters “?user=<email>” will be appended to the URL. The ‘user’ parameter is not to be fully trusted since it can be easily modified in the browser address bar. If you need to rely on it (e.g. if you’re creating a database record for this enhancement instance), consider instead using the *activation url*, as that passes the user parameter securely along with other message attributes that you might want to store. The messageId is useful if you want to use the `/messages` REST API to fetch the content of the message (by its `_id`), but it will not be present if the user is inserting your enhancement from a template (where there is no *message* at that time). The editor is required to use the Mixmax [SDK.js](#sdkjs) and call the appropriate function (either `Mixmax.editor.done()` or `Mixmax.editor.cancel()`) to dismiss itself. ## Resolver URL RESTful API that is called with the enhancement instance parameters that returns the string HTML representation of the app card. See more [information](/docs/integration-api-appendix#client-side-ajax-api-requests) about client-side requests in Mixmax. The following is POSTed to the URL via regular form data: * **params**: JSON object of the enhancement parameters (most likely returned by the editor url via the *sdk.js*). * **messageId**: If the enhancement is being inserted into a message (as opposed to a template), this will have the `_id` of the message. You can use the `/messages/:id` REST API to fetch information about the message. This URL is expected to return a JSON object with the following properties: [block:parameters] { "data": { "h-0": "Parameter", "h-1": "Type", "h-2": "Description", "0-0": "body", "0-1": "*String*", "0-2": "The HTML representation that is inserted into the message as a \"card\" (an immutable island of content in the editor). This can optionally have [variables](/docs/integration-api-appendix#variables-in-emails).", "1-0": "subject", "1-1": "*String*", "1-2": "Optional (defaults to empty string). If this happens to be used inside an email message (as opposed to a Mixmax template or a Mixmax signature) that doesn’t already have a subject set, this will set the subject. For example, if the user is typing “/weather SF, CA” and presses enter, the command could automatically set the subject to “Live weather for SF, CA”", "2-0": "raw", "2-1": "*Boolean* ", "2-2": "Optional (defaults to `false`). True if the content should be inserted into the editor as raw HTML (i.e. not an immutable \"card\"). The user will be able to edit the content. If this is used, the Activate URL does not work." }, "cols": 3, "rows": 3 } [/block] If the resolver URL is unable to return content because of invalid user input, it should return an HTTP status code of `400` with the json payload of `{message: "<failure reason>"}`. This will show a custom error message in the compose window. If this is not provided, then Could not complete command will be displayed as the default error message. ## Activate URL (optional) URL that is posted to when the enhancement is being activated (i.e. when it is being sent in a message). It is passed: * **user**: Email address of the Mixmax user. This can be trusted since this call originates from the Mixmax backend. * **toRecipients**: Array of objects, each with ‘email’ and optional ‘name’ keys, of the recipients in the 'to' field of the email. * **ccRecipients**: Array of objects, each with ‘email’ and optional ‘name’ keys, of the recipients in the 'cc' field of the email. * **subject**: String subject of the message. * **params**: JSON object of the enhancement instance parameters that were originally sent from the Editor. * **messageId**: The `_id` of the message, in case you want to use the `/messages/:id` API to fetch more information about the message than what's provided here. This API should return an empty 2xx response. [block:api-header] { "type": "basic", "title": "Tutorial: Building Giphy Enhancement" } [/block] (note: also see our [blog post](https://mixmax.com/blog/giphy-enhancement-sdk)) We'll walk you through adding an example open source Giphy Picker enhancement. 1. Git clone [https://github.com/mixmaxhq/giphy-mixmax-app](https://github.com/mixmaxhq/giphy-mixmax-app) 2. Run `npm install` and `npm start` 3. Restart Chrome in a special temporary mode so the self-signed HTTPS urls can be loaded. See [here](http://developer.mixmax.com/docs/integration-api-appendix#local-development-error-neterr_insecure_response). 4. Verify it works by visiting https://localhost:8910/editor in your browser. It should load a Giphy image picker UI. 5. Open up the [Mixmax Dashboard](https://app.mixmax.com/dashboard/settings/developer), click Settings -> Developer -> Add Enhancement. 6. Enter the following for the inputs: [block:parameters] { "data": { "h-0": "Input name", "h-1": "Value", "0-0": "Name", "0-1": "My Giphy", "1-0": "Icon Tooltip", "1-1": "My Giphy Picker", "2-0": "Editor URL", "2-1": "https://localhost:8910/editor", "3-0": "Resolver API URL", "3-1": "https://localhost:8910/api/resolver", "4-0": "Activate API URL", "4-1": "*leave blank*" }, "cols": 2, "rows": 5 } [/block] 7. Refresh Gmail with Mixmax installed. Click Compose and hover over the Enhance menu. You should see the My Giphy enhancement at the top. [block:api-header] { "type": "basic", "title": "Example lifecycle" } [/block] This example demonstrates the lifecycle of an example weather enhancement. The enhancement asks the user for their city and inserts a graphic in the email with up-to-date weather for that city. 1. The user chooses to insert your “Weather” enhancement in their Mixmax message. Mixmax launches the *Editor URL* in a new window, which just has a text input that they can enter their city name into. Javascript running in the editor calls `Mixmax.editor.done({city: “San Francisco, CA”})` 2. Mixmax calls the *Resolver URL* and posts the enhancement parameters `{city: “San Francisco, CA”}`. Your resolver returns HTML that is placed inside the editor. In this case, your HTML might just be a dynamically generated image to show the weather, e.g. `<img src=”https://weatherapi.com/img?city=San%20Francisco%2C%20CA”>`. 3. When the user sends their message, the *Activate URL* is called and is sent the enhancement parameters `{city: “San Francisco, CA”}`. Additionally, the recipients of the message are passed so you can keep a record of who it was sent to. [block:api-header] { "type": "basic", "title": "Example enhancement lifecycle if the user edits" } [/block] 1. Same 1 and 2 steps above. 3. The user decides they want to change the city and click the edit button in the card (inside the message). Mixmax re-launches your editor, but this time with `?data=%7Bcity%3A%22San%20Francisco%2C%20CA%22%7D` on the querystring. You show “San Francisco” pre-populated in the text field and they change it to “San Jose, CA”. 4. When they are done editing, the enhancement calls `Mixmax.editor.done({city: “San Jose, CA”})`. 5. Mixmax calls the *Resolver URL* and sends the new enhancement parameters, `{city: “San Jose, CA”}`. The enhancement resolver returns new HTML. 6. When the user sends their message, the *Activate URL* is called. [block:api-header] { "type": "basic", "title": "Example enhancement lifecycle involving templates" } [/block] 1. Same 1 and 2 steps as first example. 3. The user shares the template with Person B. 4. Person B adds the template to their Mixmax message and clicks Send. 5. Mixmax calls the *Activate URL* and is sent the enhancement parameters `{city: “San Francisco, CA”}`, the recipients of the message, and Person B’s email as the ‘user’ since they are the one sending. [block:api-header] { "type": "basic", "title": "SDK.js" } [/block] Include the following line of Javascript in your enhancement's editor (the document hosted at editorUrl): [block:code] { "codes": [ { "code": "<script defer src=\"https://sdk.mixmax.com/v1.1.4/editor.umd.min.js\"></script>", "language": "html" } ] } [/block] Mixmax SDK has two functions that can be called: `Mixmax.editor.done({ /* params */})` - This is called when your user is finished interacting with the enhancement. For example, this might be called when the user clicks the “OK” button in your editor. Or perhaps if they just need to drag in a file, this is called after the file is uploaded. Be aware that if there is a current value for `window.opener` then this function will close the current tab or window with `window.close()`. `Mixmax.editor.cancel()` - This is called if you’d like to cancel the editor. For example, this might be called when the user clicks Cancel in your editor or when they hit the escape key. If you're using a JavaScript bundler like [Rollup](https://rollupjs.org/) or [Webpack](https://webpack.github.io/), instead of loading the SDK using a script tag, you can import the SDK from npm like [block:code] { "codes": [ { "code": "const Mixmax = require('@mixmaxhq/sdk');\n// Now access `Mixmax.editor.done` etc. as above.", "language": "javascript" } ] } [/block] If your bundler is capable of importing ES6 modules and understands [`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module), you can import the SDK like [block:code] { "codes": [ { "code": "import * as Mixmax from '@mixmaxhq/sdk';\n\n// Now access `Mixmax.editor.done` etc. as above.\n\n// More concise:\nimport { editor } from '@mixmaxhq/sdk`;\n\n// If your bundler understands [`pkg.browser`](https://github.com/defunctzombie/package-browser-field-spec)\n// like Rollup does when using rollup-plugin-node-resolve with\n// [`browser: true`](https://github.com/rollup/rollup-plugin-node-resolve#usage),\n// you can import _only_ the editor APIs and not the rest of the SDK:\nimport { done, cancel } from '@mixmaxhq/sdk/editor';", "language": "javascript" } ] } [/block]