moeru-ai/airi · error · Error

gameletKit requires a host binding runtime.

Error message

gameletKit requires a host binding runtime.

What it means

In plugin-sdk-tamagotchi's gamelet kit (src/gamelet/index.ts), mount(definition) delegates the actual mounting of a gamelet iframe/widget to gameletRuntime.bindings.bind(...). bindings is a host-provided capability: only the real tamagotchi host process supplies it when it instantiates kit clients for an extension module. If the kit is used in a runtime whose host did not provide a binding runtime (bare SDK host, unit tests, a slim host), mount() refuses to proceed and throws this error rather than returning a handle that could never mount anything.

Solutions

  1. Run the code inside the real tamagotchi host, which provides gameletRuntime.bindings when creating kit clients.
  2. If you are building/testing against a custom host, register a bindings implementation (bind({ moduleId, kitId, kitModuleType, config }) returning a mounted binding) in the runtime you pass to kit creation.
  3. In tests, stub the kit or inject a fake bindings runtime instead of invoking the real mount path.
  4. Feature-detect before mounting: skip/defer the mount when the host lacks bindings rather than crashing the extension.

Example fix

// before
const gamelets = await module.kits.use(gameletKit)
await gamelets.mount(definition) // throws in tests / slim hosts

// after
const gamelets = await module.kits.use(gameletKit)
if (!gameletRuntimeHasBindings(gamelets)) {
  console.warn('gamelet bindings unavailable; skipping mount')
  return
}
await gamelets.mount(definition)
Defensive patterns

Strategy: validation

Validate before calling

const gamelets = await module.kits.use(gameletKit)
// feature-detect host bindings before mounting
const canMount = 'mount' in gamelets && hostProvidesBindings()
if (canMount) await gamelets.mount(definition)

Type guard

interface HostBindingsRuntime { bindings?: { bind(input: unknown): Promise<unknown> } }
function hasGameletBindings(runtime: HostBindingsRuntime): boolean {
  return typeof runtime.bindings?.bind === 'function'
}

Try / catch

try {
  return await gamelets.mount(definition)
} catch (error) {
  if (errorMessageFrom(error).includes('requires a host binding runtime')) {
    return undefined // host without UI bindings: skip gamelet registration
  }
  throw error
}

Prevention

When it happens

Trigger: Calling module.kits.use(gameletKit) and then gamelets.mount({...}) inside a unit test, a mock host built with createPluginHost but no binding runtime registered, or a host integration that deliberately omits UI binding capabilities. Also when code accidentally runs the SDK kit outside the tamagotchi application.

Common situations: Extension authors writing vitest suites against their gamelet module with a minimal host; a new host embedding the SDK that has not implemented bindings yet; calling mount during host shutdown when capabilities have been torn down.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/64caff85c1ae861a. Report an issue: GitHub.

Appendix: source

Thrown at packages/plugin-sdk-tamagotchi/src/gamelet/index.ts:75

  id: 'kit.gamelet',
  version: '1.0.0',
  allowedExposePolicies: ['local-only', 'remote-observable'],
  defaultExposePolicy: 'local-only',
  createClient(runtime) {
    const gameletRuntime = runtime as GameletKitRuntime
    return {
      iframe(input) {
        return {
          mount: 'iframe',
          iframe: {
            ...input,
            sandbox: input.sandbox ?? 'allow-scripts allow-same-origin allow-forms allow-popups',
          },
        }
      },
      async mount(definition) {
        if (!gameletRuntime.bindings) {
          throw new Error('gameletKit requires a host binding runtime.')
        }

        return await gameletRuntime.bindings.bind({
          moduleId: definition.bindingId ?? createGameletBindingId(runtime),
          kitId: 'kit.gamelet',
          kitModuleType: 'gamelet',
          config: {
            title: definition.title,
            widget: definition.ui,
            config: {
              init: definition.init ?? {},
            },
          },
        })
      },
      orchestration: gameletRuntime.gamelets,
    }
  },

View on GitHub (pinned to 677329427f)