@miosa/vue v0.2.0 provides four Vue 3 single-file components for embedding MIOSA sandboxes. All components are written with <script setup> and work with Vue 3.3+ and Nuxt 3.
Install
npm install @miosa/vue
# xterm peer deps - required only if you use MiosaTerminal
npm install @xterm/xterm xterm-addon-fit Styles are scoped inside each SFC - no global stylesheet import required.
MiosaPreview
Renders a sandboxed <iframe> showing the HTTP preview URL for a running sandbox.
<script setup lang="ts">
import { MiosaPreview } from '@miosa/vue';
const sandboxId = 'sb_abc123';
const previewToken = await fetchTokenFromYourBackend(sandboxId); // minted server-side
</script>
<template>
<!-- Recommended: short-lived preview token from your backend -->
<MiosaPreview
:sandbox-id="sandboxId"
:preview-token="previewToken"
theme="dark"
@error="(err) => console.error(err)"
/>
</template> Props
| Prop | Type | Default | Description |
|---|---|---|---|
sandboxId | string | - | Required. The sandbox ID to preview. |
previewToken | string | - | Short-lived preview token from your backend. Mutually exclusive with apiKey. |
apiKey | string | - | Your MIOSA API key. Use only in trusted server-rendered contexts. |
theme | "light" \| "dark" | "light" | Visual theme. |
class | string | - | Forwarded to the root <div>. |
Events
| Event | Payload | Description |
|---|---|---|
error | Error | Emitted when the preview URL cannot be resolved. |
Exactly one of previewToken or apiKey must be provided.
MiosaTerminal
Renders a full PTY terminal connected to a sandbox over WebSocket, powered by xterm.js.
<script setup lang="ts">
import { MiosaTerminal } from '@miosa/vue';
</script>
<template>
<MiosaTerminal
sandbox-id="sb_abc123"
:api-key="runtimeConfig.miosaApiKey"
theme="dark"
@resize="(cols, rows) => console.log(cols, rows)"
@error="(err) => console.error(err)"
style="height: 400px"
/>
</template> Props
| Prop | Type | Default | Description |
|---|---|---|---|
sandboxId | string | - | Required. |
apiKey | string | - | Required. |
theme | "light" \| "dark" | "dark" | Sets the xterm.js color scheme. |
Events
| Event | Payload | Description |
|---|---|---|
resize | [cols: number, rows: number] | Emitted when the terminal dimensions change. |
error | Error | Emitted on WebSocket errors or xterm load failure. |
The component auto-fits to its container via ResizeObserver and syncs resize events to the PTY.
MiosaFileTree
Renders a flat-list file browser backed by the sandbox filesystem. Directories expand inline on click; files emit a select event.
<script setup lang="ts">
import { MiosaFileTree } from '@miosa/vue';
function onFileSelect(path: string) {
console.log('selected:', path);
}
</script>
<template>
<MiosaFileTree
sandbox-id="sb_abc123"
:api-key="runtimeConfig.miosaApiKey"
:show-hidden="false"
:default-expanded="true"
@select="onFileSelect"
@change="(path, type) => console.log(path, type)"
/>
</template> Props
| Prop | Type | Default | Description |
|---|---|---|---|
sandboxId | string | - | Required. |
apiKey | string | - | Required. |
showHidden | boolean | false | Include dotfiles and hidden directories. |
defaultExpanded | boolean | false | When true, all directories start expanded. |
Events
| Event | Payload | Description |
|---|---|---|
select | path: string | Emitted when a file is clicked. path is the absolute path within the sandbox (e.g. /workspace/src/index.ts). |
change | [path: string, type: "created" \| "deleted" \| "modified"] | Emitted on filesystem changes (when the watch subscription fires). |
MiosaUsage
Renders a three-column usage summary (compute, storage, egress) for a specific end-user.
<script setup lang="ts">
import { MiosaUsage } from '@miosa/vue';
</script>
<template>
<MiosaUsage
external-user-id="user_xyz"
:api-key="runtimeConfig.miosaApiKey"
period="last_30"
theme="dark"
/>
</template> Props
| Prop | Type | Default | Description |
|---|---|---|---|
externalUserId | string | - | Required. Your platform’s user ID, matching the external_user_id used when creating sandboxes. |
apiKey | string | - | Required. |
period | "current" \| "last_30" \| "last_7" | "current" | Billing period to aggregate over. "current" is the current billing cycle; "last_30" / "last_7" are rolling day windows. |
theme | "light" \| "dark" | "light" | Visual theme. |
Displays compute_seconds, storage_gb_hours, and egress_gb. No events are emitted.
End-to-end example: Nuxt 3
server/api/sandbox-token.post.ts - server route (keeps API key off the client)
import Miosa from '@miosa/sdk';
export default defineEventHandler(async (event) => {
const { sandboxId } = await readBody<{ sandboxId: string }>(event);
const client = new Miosa({ apiKey: process.env.MIOSA_API_KEY! });
const sandbox = await client.sandboxes.get(sandboxId);
// @ts-expect-error
const { token } = await sandbox.previewToken(3600);
return { token };
}); pages/workbench.vue
<script setup lang="ts">
import { MiosaPreview, MiosaTerminal, MiosaFileTree } from '@miosa/vue';
const SANDBOX_ID = 'sb_abc123';
const { data } = await useFetch('/api/sandbox-token', {
method: 'POST',
body: { sandboxId: SANDBOX_ID },
});
const previewToken = computed(() => data.value?.token ?? '');
const selectedFile = ref<string | null>(null);
</script>
<template>
<div class="workbench">
<aside class="workbench__sidebar">
<MiosaFileTree
:sandbox-id="SANDBOX_ID"
:api-key="useRuntimeConfig().miosaApiKey"
@select="(path) => (selectedFile = path)"
/>
</aside>
<main class="workbench__preview">
<div v-if="selectedFile" class="workbench__filepath">{{ selectedFile }}</div>
<MiosaPreview
:sandbox-id="SANDBOX_ID"
:preview-token="previewToken"
theme="dark"
/>
</main>
<section class="workbench__terminal">
<MiosaTerminal
:sandbox-id="SANDBOX_ID"
:api-key="useRuntimeConfig().miosaApiKey"
theme="dark"
@error="(err) => console.error('[terminal]', err)"
/>
</section>
</div>
</template>
<style scoped>
.workbench {
display: grid;
grid-template-columns: 240px 1fr 1fr;
height: 100vh;
overflow: hidden;
}
</style>