On this page

@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

PropTypeDefaultDescription
sandboxIdstring-Required. The sandbox ID to preview.
previewTokenstring-Short-lived preview token from your backend. Mutually exclusive with apiKey.
apiKeystring-Your MIOSA API key. Use only in trusted server-rendered contexts.
theme"light" \| "dark""light"Visual theme.
classstring-Forwarded to the root <div>.

Events

EventPayloadDescription
errorErrorEmitted 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

PropTypeDefaultDescription
sandboxIdstring-Required.
apiKeystring-Required.
theme"light" \| "dark""dark"Sets the xterm.js color scheme.

Events

EventPayloadDescription
resize[cols: number, rows: number]Emitted when the terminal dimensions change.
errorErrorEmitted 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

PropTypeDefaultDescription
sandboxIdstring-Required.
apiKeystring-Required.
showHiddenbooleanfalseInclude dotfiles and hidden directories.
defaultExpandedbooleanfalseWhen true, all directories start expanded.

Events

EventPayloadDescription
selectpath: stringEmitted 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

PropTypeDefaultDescription
externalUserIdstring-Required. Your platform’s user ID, matching the external_user_id used when creating sandboxes.
apiKeystring-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>

See also

Was this helpful?