npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@evid-ai/capture-sdk

v0.1.6

Published

Headless browser SDK for capturing evidence (photo + GPS + metadata) for the Evid-AI platform.

Readme

@evid-ai/capture-sdk

JavaScript/TypeScript SDK for integrating with the Evid-AI platform — manage task groups, teams, tasks, and submit evidence with tags from your own application.

Install

npm install @evid-ai/capture-sdk
# or
yarn add @evid-ai/capture-sdk

Setup

import { CaptureSDK } from "@evid-ai/capture-sdk";

const sdk = new CaptureSDK({
  apiKey: "pk_live_xxx",
  gatewayUrl: "https://your-gateway.example.com",
});

Authentication

Most resource methods require a user access token. Call sdk.auth.login() once and the SDK stores the token automatically for subsequent calls.

const { user } = await sdk.auth.login({
  identifier: "[email protected]",
  password: "secret",
});

You can also pass an existing token at construction time:

const sdk = new CaptureSDK({
  apiKey: "pk_live_xxx",
  gatewayUrl: "https://your-gateway.example.com",
  accessToken: "existing-token",
});

Two-factor authentication (2FA)

If the account has TOTP 2FA enabled, login() returns twoFactorRequired: true and a short-lived challengeToken instead of a token. Collect the user's 6-digit TOTP code and call verify2FA() to finish.

const result = await sdk.auth.login({
  identifier: "[email protected]",
  password: "secret",
});

if (result.twoFactorRequired) {
  const { user } = await sdk.auth.verify2FA({
    challengeToken: result.challengeToken!,
    code: "123456",
  });
}

challengeToken expires after 5 minutes; on timeout, re-run login().


Resources

sdk.teams

// List teams (paginated)
const page = await sdk.teams.list({ page: 1, pageSize: 20, search: "alpha" });

// Get a single team
const team = await sdk.teams.get("team-id");

// Create a team  — requires API key scope: team:create
const team = await sdk.teams.create({
  name: "Team Alpha",
  members: ["user-id-1", "user-id-2"], // optional, user IDs
});

// Update a team  — requires API key scope: team:update
await sdk.teams.update("team-id", {
  name: "Team Alpha v2",
  members: ["user-id-1", "user-id-3"],
});

CreateTeamInput

| Field | Type | Required | | --------- | ---------- | -------- | | name | string | Yes | | members | string[] | No |

UpdateTeamInput — all fields optional.


sdk.taskGroups

// List task groups, optionally filter by team
const page = await sdk.taskGroups.list({
  teamId: "team-id",
  page: 1,
  pageSize: 20,
});

// Get a single task group
const group = await sdk.taskGroups.get("task-group-id");

// Create a task group  — requires API key scope: task-group:create
const group = await sdk.taskGroups.create({
  name: "Anexo A",
  description: "Main annexe",       // optional
  shortName: "A",                   // optional
  assignedTeams: ["team-id"],       // optional, team IDs
  autoAssignTeamMembers: true,      // optional — auto-populate assignedUsers from team members
});

// Update a task group  — requires API key scope: task-group:update
await sdk.taskGroups.update("task-group-id", {
  name: "Anexo A (updated)",
  assignedTeams: ["team-id-1", "team-id-2"],
  autoAssignTeamMembers: true,      // re-sync assignedUsers from new teams
});

CreateTaskGroupInput

| Field | Type | Required | Description | | ------------------------ | ---------- | -------- | ------------------------------------------------------------------------- | | name | string | Yes | | | description | string | No | | | shortName | string | No | | | assignedTeams | string[] | No | Team IDs to assign | | autoAssignTeamMembers | boolean | No | When true and assignedUsers is empty, auto-populate from team members |

UpdateTaskGroupInput — all fields optional.

| Field | Type | Description | | ------------------------ | ---------- | ------------------------------------------------------------------------- | | name | string | | | description | string | | | shortName | string | | | assignedTeams | string[] | Team IDs to assign | | autoAssignTeamMembers | boolean | When true and assignedUsers is empty, auto-populate from team members |


sdk.tasks

// List tasks, optionally filter by task group or team
const page = await sdk.tasks.list({ taskGroupId: "tg-id", teamId: "team-id" });

// Get a single task
const task = await sdk.tasks.get("task-id");

sdk.evidence

List evidence

const page = await sdk.evidence.list({
  taskId: "task-id",
  page: 1,
  pageSize: 20,
});

Create evidence

sdk.evidence.create() accepts any file type — photo, video, audio, or document.

const result = await sdk.evidence.create({
  taskGroup: "task-group-id",
  team: "team-id",   // optional
  task: "task-id",   // optional
  evidence: {
    file: {
      blob: file,
      mimeType: file.type,
      capturedAt: new Date().toISOString(),
      name: file.name,
    },
    device: {
      userAgent: navigator.userAgent,
      language: navigator.language,
    },
    captureSurface: "headless",
    metadata: {},
  },
});

console.log(result.id);

Multiple files in one call:

await sdk.evidence.create({
  taskGroup: "task-group-id",
  evidence: files.map((file) => ({
    file: { blob: file, mimeType: file.type, capturedAt: new Date().toISOString() },
    device: { userAgent: navigator.userAgent, language: navigator.language },
    captureSurface: "headless",
    metadata: {},
  })),
});

GPS coordinates are captured automatically before uploading. Pass skipLocation: true to submit without location data.

Tags

Attach typed metadata tags to evidence at creation time.

await sdk.evidence.create({
  taskGroup: "task-group-id",
  evidence: capturedEvidence,
  tags: [
    // General tag — text value
    {
      name: "Site name",
      value: "Building A",
      type: "text",
      usagePurpose: "generalTag",
    },
    // General tag — numeric value
    {
      name: "Temperature",
      value: 36.5,
      type: "float",
      usagePurpose: "generalTag",
    },
    // ESG tag
    {
      name: "CO2 emissions",
      value: 120,
      type: "integer",
      usagePurpose: "esgTag",
      esgPillar: "environment",
      esgStandard: "gri",
      unitOfMeasure: "kg",
    },
  ],
});

TagInput

| Field | Type | Required | | ---------------- | --------------------------------- | -------- | | name | string | Yes | | value | string \| number \| boolean | Yes | | type | TagType | Yes | | usagePurpose | "generalTag" \| "esgTag" | Yes | | esgPillar | EsgPillar | No | | esgStandard | EsgStandard | No | | unitOfMeasure | string | No |

TagType

| Value | Description | | ---------- | ------------------- | | text | String value | | integer | Integer number | | float | Decimal number | | boolean | true / false | | datetime | ISO 8601 string | | gps | GPS coordinates |

EsgPillar: "environment" | "social" | "governance"

EsgStandard: "general" | "gri" | "sasb" | "cdp" | "tcfd" | "ir" | "un_sdgs" | "iso_26000" | "aa1000" | "iirc" | "eu_taxonomy"

CreateEvidenceInput

| Field | Type | Required | | -------------- | ------------------------------------ | -------- | | taskGroup | string | Yes | | team | string | No | | task | string | No | | platform | 'web' \| 'mobile' \| 'capture-sdk' | No | | tags | TagInput[] | No | | evidence | EvidenceInput \| EvidenceInput[] | Yes | | skipLocation | boolean | No |


API key scopes

Write operations require the API key to include specific scopes. Scopes are set when creating or rotating the key from the Strapi admin panel.

| Scope | Grants | | ------------------- | ----------------------------- | | evidence:create | Submit evidence | | task-group:create | Create task groups | | task-group:update | Update task groups | | team:create | Create teams | | team:update | Update teams |


Error handling

All SDK errors are CaptureSDKError with a typed code:

import { CaptureSDKError } from "@evid-ai/capture-sdk";

try {
  await sdk.evidence.create({ ... });
} catch (err) {
  if (err instanceof CaptureSDKError) {
    console.error(err.code, err.message);
  }
}

| Code | Description | | ----------------------- | -------------------------------------------- | | UPLOAD_FAILED | Evidence submission to the server failed | | GEO_UNAVAILABLE | Geolocation API not supported by the browser | | GEO_PERMISSION_DENIED | User denied location permission | | GEO_TIMEOUT | Geolocation request timed out | | INVALID_CONFIG | Missing or invalid SDK configuration |


TypeScript

The SDK ships with full TypeScript declarations. All resource types are exported:

import type {
  // Auth
  LoginInput,
  LoginResult,
  Verify2FAInput,
  AuthUser,
  // Teams
  Team,
  ListTeamsParams,
  CreateTeamInput,
  UpdateTeamInput,
  // Task groups
  TaskGroup,
  ListTaskGroupsParams,
  CreateTaskGroupInput,
  UpdateTaskGroupInput,
  // Tasks
  Task,
  ListTasksParams,
  // Evidence
  MediaFile,
  EvidenceInput,
  CreateEvidenceInput,
  EvidenceRecord,
  // Tags
  TagInput,
  TagType,
  TagUsagePurpose,
  EsgPillar,
  EsgStandard,
} from "@evid-ai/capture-sdk";

Requirements

  • Modern browser or Node.js 18+
  • HTTPS (or localhost) required for location access