Docs/QuickActions SDK

QuickActions SDK

Universal Developer

QuickActions SDK

Overview

QuickActions SDK lets plugins register global actions in the MetaK / Quick Actions panel and reuse Flow Transfer native sharing. meta / plugin.meta remains as a compatibility alias. New code should prefer quickActions / plugin.quickActions.

Quick Start

Plugin index.js can use globalThis.quickActions directly. plugin.quickActions points to the same SDK instance.

EXAMPLE.JAVASCRIPT
quickActions.registerAction({
  id: 'share-current-item',
  render: {
    basic: {
      title: 'Share current item',
      subtitle: 'Use system share, AirDrop, or mail',
      icon: { type: 'class', value: 'i-ri-share-line' }
    },
    shortcut: '⌘⇧S',
    group: 'Share'
  },
  priority: 120
})

quickActions.onActionExecute(async ({ actionId, item }) => {
  if (actionId !== 'share-current-item') return

  const result = await quickActions.shareItem(item, {
    preferredTargets: ['airdrop', 'system-share', 'mail']
  })

  if (!result.success) {
    logger.warn('Native share failed', result.error)
  }
})

API Reference

registerAction(action)

Register a global action shown in the MetaK / Quick Actions panel.

EXAMPLE.TYPESCRIPT
const unregister = quickActions.registerAction({
  id: 'copy-title',
  render: {
    basic: {
      title: 'Copy title',
      subtitle: 'Copy the current item title',
      icon: { type: 'class', value: 'i-ri-file-copy-line' }
    },
    group: 'Text'
  }
})

// Later
unregister()

unregisterAll()

Unregister all Quick Actions created by the current plugin.

onActionExecute(handler)

Listen for actions registered by the current plugin. The callback only receives actionId values owned by this plugin.

EXAMPLE.TYPESCRIPT
const dispose = quickActions.onActionExecute(({ actionId, item }) => {
  logger.info('quick action executed', { actionId, itemId: item.id })
})

dispose()

getNativeShareTargets(payloadType?)

Read native share targets that are actually available on the current platform. The result comes from the Flow Transfer target registry and only includes targets where isNativeShare === true.

PlatformTargets
macOSsystem-share, airdrop, mail, messages
Windowsmail
Linuxmail
EXAMPLE.TYPESCRIPT
const targets = await quickActions.getNativeShareTargets('files')
const canAirDrop = targets.some(target => target.id === 'airdrop')

resolveNativeShareTarget(options?)

Resolve one available native share target from the payload type and plugin preferences, so plugins do not duplicate platform fallback logic.

Default strategy:

Payload typeDefault order
files / imageairdrop -> system-share -> mail
text / html / json / customsystem-share -> mail -> messages
EXAMPLE.TYPESCRIPT
const target = await quickActions.resolveNativeShareTarget({
  payloadType: 'files',
  preferredTargets: ['airdrop', 'mail'],
  allowFallback: false
})

if (!target) {
  logger.info('No preferred native share target available')
}

allowFallback defaults to true. When set to false, unavailable preferred targets return undefined instead of silently selecting another target.

nativeShare(payload, options?)

Share a Flow payload through Flow Transfer's flow:native:share channel. Permission, error, and platform fallback semantics stay aligned with Flow Transfer.

EXAMPLE.TYPESCRIPT
const result = await quickActions.nativeShare(
  {
    type: 'text',
    data: 'Hello from Tuff',
    context: {
      sourcePluginId: plugin.getInfo().name,
      metadata: { title: 'Share text' }
    }
  },
  { target: 'mail' }
)

createSharePayloadFromItem(item, options?)

Convert the current CoreBox item into a shareable Flow payload.

  • File items prefer { type: 'files', data: [path] }
  • Link or generic items use { type: 'text', data: title + subtitle + url }
  • metadata preserves itemId, itemKind, sourceId, and sourceType

shareItem(item, options?)

Wrap the common item -> Flow payload -> target resolution -> native share path. This is the preferred helper for MetaK global share actions.

EXAMPLE.TYPESCRIPT
const result = await quickActions.shareItem(item, {
  preferredTargets: ['airdrop', 'system-share', 'mail']
})

if (!result.success) {
  logger.warn('Share failed', result.error)
}

If your plugin needs full control over payload or target selection, use createSharePayloadFromItem() + resolveNativeShareTarget() + nativeShare().

Type Summary

EXAMPLE.TYPESCRIPT
interface QuickActionsSDK {
  registerAction(action: TuffQuickAction): () => void
  unregisterAll(): void
  onActionExecute(handler: QuickActionExecuteHandler): () => void
  getNativeShareTargets(payloadType?: FlowPayloadType): Promise<FlowTargetInfo[]>
  resolveNativeShareTarget(options?: QuickActionNativeShareTargetOptions): Promise<FlowTargetInfo | undefined>
  nativeShare(payload: FlowPayload, options?: { target?: string }): Promise<NativeShareResult>
  createSharePayloadFromItem(item: TuffItem, options?: QuickActionItemSharePayloadOptions): FlowPayload
  shareItem(item: TuffItem, options?: QuickActionShareItemOptions): Promise<NativeShareResult>
}

Best Practices

  1. Use quickActions for new code, and keep meta only for old plugin compatibility.
  2. Before sharing, call getNativeShareTargets() or resolveNativeShareTarget() instead of guessing availability from process.platform.
  3. Prefer airdrop for files and images; prefer system-share for text-like payloads.
  4. Windows and Linux currently expose only the explicit mail fallback, not a fake system share panel.
  5. Handle result.success === false and provide copy, mail, or plugin-specific fallback behavior.