Skip to main content
ClaudeWave
Skill808 repo starsupdated 3d ago

add-pdf-viewer

Internal implementation skill invoked by /add-native for native PDF control workflows. Handles HTTPS and file URI PDF viewing with @microsoft/power-apps-native-pdf-viewer 0.2.9+.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/microsoft/power-platform-skills /tmp/add-pdf-viewer && cp -r /tmp/add-pdf-viewer/plugins/mobile-apps/skills/add-native/add-pdf-viewer ~/.claude/skills/add-pdf-viewer
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

**📋 Shared instructions: [shared-instructions.md](${PLUGIN_ROOT}/shared/shared-instructions.md)** — read first.

# Add PDF Viewer

**Internal helper.** Users should invoke `/add-native pdf-viewer`, `/add-native pdf-control`, or `/add-native @microsoft/power-apps-native-pdf-viewer`; `/add-native` routes here after resolving the capability.

Generate or verify the native PDF viewer wrapper and show how to call its **native React Native API**. Version 0.2.9 and later support HTTPS PDF URLs and local `file://` URIs. Do not use the HostingSDK / PCF path from the package README; that is for a different use case.

## Steps

### 1. Verify app

```bash
test -f app.config.js && test -f power.config.json && test -f package.json && test -d src
```

If this fails, tell the user to run `/create-mobile-app` first and STOP.

### 2. Verify package is already present

```bash
node -e "const p=require('./package.json'); const m='@microsoft/power-apps-native-pdf-viewer'; if (!p.dependencies?.[m]) { console.error('MISSING: ' + m + ' is not in package.json. The template/app must already ship this native extension. This skill will not install it or edit native config.'); process.exit(1); } let v; try { v=require('./node_modules/' + m + '/package.json').version; } catch { console.error('MISSING_INSTALL: cannot verify the installed ' + m + ' version. Run the project package install first.'); process.exit(1); } const [major,minor,patch]=v.split('.').map(Number); if (!(major > 0 || minor > 2 || (minor === 2 && patch >= 9))) { console.error('UNSUPPORTED_VERSION: ' + m + ' ' + v + ' does not support file:// URIs. Version 0.2.9+ is required.'); process.exit(1); } console.log('OK: native PDF viewer ' + v + ' supports https:// and file://');"
```

If the check fails, STOP. Do not run `npm install`, `npx expo install`, `pod install`, or edit `app.config.js`. Version 0.2.9+ must already be part of the app's native build.

### 3. Write or verify `src/native/pdfViewer.ts`

Create `src/native/pdfViewer.ts` if it does not exist. If it already exists, inspect it and patch only if it violates the supported URI rules or throws instead of returning a result.

The wrapper MUST:

- Accept `https://` URLs and `file://` URIs.
- Reject `content://`, `blob:`, `http://`, empty, and malformed URLs before calling native code.
- Return a discriminated union and never throw.
- Return `NATIVE_MODULE_MISSING` when the extension is installed in JS but unavailable in the native build.
- Surface viewer action results (`shared`, `printed`, `dismissed`) when available.
- Return `VIEWER_FAILED` for native errors not covered by validation/module checks.

```ts
// src/native/pdfViewer.ts
import { NativePdfViewer } from '@microsoft/power-apps-native-pdf-viewer';

export type PdfViewerResult =
  | { ok: true; action?: 'shared' | 'printed' | 'dismissed' }
  | { ok: false; reason: 'INVALID_URL' | 'NATIVE_MODULE_MISSING' | 'VIEWER_FAILED'; message?: string };

export async function openHttpsPdf(
  url: string,
  options?: { title?: string; maxFileSizeMb?: number; cacheEnabled?: boolean },
): Promise<PdfViewerResult> {
  let parsed: URL;
  try {
    parsed = new URL(url);
  } catch {
    return { ok: false, reason: 'INVALID_URL', message: 'PDF location must be a valid https:// URL or file:// URI.' };
  }

  const isHttpsUrl = parsed.protocol === 'https:';
  const isFileUri = parsed.protocol === 'file:' && url.startsWith('file://') && parsed.pathname !== '/';
  if (!isHttpsUrl && !isFileUri) {
    return { ok: false, reason: 'INVALID_URL', message: 'Native PDF viewer supports https:// and file:// inputs only.' };
  }

  if (!NativePdfViewer?.openPdf) {
    return { ok: false, reason: 'NATIVE_MODULE_MISSING', message: 'Native PDF viewer module is not available in this build.' };
  }

  try {
    const response = await NativePdfViewer.openPdf(url, {
      maxFileSizeMb: 50,
      cacheEnabled: true,
      ...options,
    });

    if (response.status === 'ok') {
      return { ok: true, action: response.result?.action };
    }

    return { ok: false, reason: 'VIEWER_FAILED', message: response.message ?? response.error };
  } catch (error: any) {
    return { ok: false, reason: 'VIEWER_FAILED', message: error?.message ?? String(error) };
  }
}
```

### 4. Use the wrapper

Screens import the wrapper, not the native package directly:

```ts
import { openHttpsPdf } from '@/native/pdfViewer';

const response = await openHttpsPdf('https://example.com/report.pdf', {
  title: "Inspection report",
});

if (response.ok) {
  switch (response.action) {
    case "shared":
      // User completed native Share.
      break;
    case "printed":
      // User completed native Print.
      break;
    case "dismissed":
      // User closed the viewer.
      break;
  }
} else {
  console.warn("Failed to open PDF:", response.reason, response.message);
}
```

Notes:
- URLs must use `https://` or a non-empty `file://` URI. `content://`, `blob:`, and `http://` are not supported by this skill.
- Use `@microsoft/power-apps-native-pdf-viewer` only for this native PDF viewing use case.
- Use `expo-document-picker` for picking/importing/uploading a local PDF or document.
- Use `/add-native pdf-report` for generated local PDFs. That helper requires `expo-print` and adds sharing behavior only when `expo-sharing` is already present.
- Generated local PDFs from `expo-print` may be opened by native PDF viewer 0.2.9+ as `file://` URIs.
- Share and Print are built into the native viewer; there are no separate JS share/print calls.
- The wrapper returns `{ ok: true } | { ok: false }`; handle every non-ok reason in UI.

### 5. Type-check

```bash
npx tsc --noEmit
```

Fix any TypeScript errors before rebuilding.

### 6. Native rebuild note

This skill does not install native code. If the package was just added outside the skill, the app needs a native rebuild outside this workflow. If the package was already in the build, Metro hot reload is enough for wrapper edits.

### 7. Do not use Hosting
add-data-sourceSkill

Guide the user to add a data source, connection, or API connector to a Canvas App via Power Apps Studio, then verify and continue. USE WHEN the user asks to add a data source, add a connection, add an API, add a connector, connect to SharePoint / Dataverse / SQL / Excel / OneDrive / Teams / Office 365, or any similar request to make new data available to the app. DO NOT USE WHEN the user is asking to list or describe existing data sources — call list_data_sources or list_apis directly instead.

canvas-appSkill

Creates or edits a Power Apps Canvas App through the Canvas Authoring MCP coauthoring session. Handles new app generation, direct targeted edits, complex multi-screen changes, responsive layout, per-screen self-QA, and compile-error convergence. Trigger on requests to create, build, generate, modify, update, change, fix, or edit a Canvas App or .pa.yaml files.

configure-canvas-mcpSkill

Configure the Canvas Authoring MCP server for the current coauthoring session. USE WHEN "configure MCP", "set up MCP server", "MCP not working", "connect Canvas Apps MCP", "canvas-authoring not available", "MCP not configured", "set up canvas apps".

generate-canvas-appSkill

[DEPRECATED — use canvas-app instead] Generate a complete Power Apps canvas app.

report-issueSkill

>

add-azuredevopsSkill

Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.

add-connectorSkill

Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.

add-datasourceSkill

Use when adding an unspecified data source to an Expo/React Native Power Apps mobile app; routes to Dataverse, SharePoint, or another connector.