@didww/sdk

中文文档
3.1.1发布于 2026/10/07MITTypeScriptESM + CJS近 30 天下载 2717

DIDWW API v3 TypeScript SDK

原始使用文档
文档目录37 节
  1. About DIDWW API v3
  2. API Version
  3. Installation
  4. Quick Start
  5. Examples
  6. Configuration
  7. Environments
  8. HTTPS Proxy
  9. Resources
  10. Read-Only Resources
  11. DIDs
  12. Voice In Trunks
  13. Voice In Trunk Groups
  14. Voice Out Trunks
  15. Orders
  16. DID Reservations
  17. Shared Capacity Groups
  18. Identities
  19. Addresses
  20. Exports
  21. Address Verifications
  22. Emergency Services (2026-04-16)
  23. DID History (2026-04-16)
  24. Included Resources
  25. Query Parameters
  26. Dirty Tracking (PATCH Optimization)
  27. Trunk Configuration Types
  28. Order Item Types
  29. Date and Datetime Fields
  30. Enums
  31. File Encryption & Upload
  32. Webhook Signature Validation
  33. Error Handling
  34. All Supported Resources
  35. Contributing
  36. Releasing
  37. License

@didww/sdk

TypeScript SDK for the DIDWW API v3.

Tests Coverage Node

About DIDWW API v3

The DIDWW API provides a simple yet powerful interface that allows you to fully integrate your own applications with DIDWW services. An extensive set of actions may be performed using this API, such as ordering and configuring phone numbers, setting capacity, creating SIP trunks and retrieving CDRs and other operational data.

The DIDWW API v3 is a fully compliant implementation of the JSON API specification.

This SDK uses kitsu-core for JSON:API serialization and deserialization.

Read more https://doc.didww.com/api

API Version

This SDK sends the X-DIDWW-API-Version: 2026-04-16 header with every request by default.

NPM VersionBranchDIDWW API Version
3.xmain2026-04-16
2.x2022-05-102022-05-10

Installation

npm install @didww/sdk

Requires Node.js 18+.

Quick Start

import { DidwwClient, Environment } from '@didww/sdk';

const client = new DidwwClient({
  apiKey: 'your-api-key',
  environment: Environment.SANDBOX, // or Environment.PRODUCTION
});

// Check balance
const balance = await client.balance().find();
console.log(balance.data.totalBalance);

// List countries
const countries = await client.countries().list();
for (const country of countries.data) {
  console.log(`${country.iso} - ${country.name}`);
}

For more examples visit examples.

For details on obtaining your API key please visit https://doc.didww.com/api3/configuration.html

Examples

Configuration

const client = new DidwwClient({
  apiKey: 'your-api-key',
  environment: Environment.PRODUCTION,
  timeout: 30_000, // 30 seconds
});

Environments

EnvironmentBase URL
Environment.PRODUCTIONhttps://api.didww.com/v3
Environment.SANDBOXhttps://sandbox-api.didww.com/v3

HTTPS Proxy

You can pass a custom fetch function to route requests through an HTTPS proxy.

Note: undici must be installed separately: npm install undici

import { DidwwClient, Environment } from '@didww/sdk';
import { ProxyAgent } from 'undici';

const proxyAgent = new ProxyAgent('https://proxy.example.com:8080');

const client = new DidwwClient({
  apiKey: 'your-api-key',
  environment: Environment.PRODUCTION,
  fetch: (input, init) => fetch(input, { ...init, dispatcher: proxyAgent } as RequestInit),
});

Resources

Read-Only Resources

// Countries
const countries = await client.countries().list();
const country = await client.countries().find('uuid');

// Regions
const regions = await client.regions().list();

// Cities, Areas, POPs
const cities = await client.cities().list();
const areas = await client.areas().list();
const pops = await client.pops().list();

// DID Groups (with stock keeping units)
const groups = await client.didGroups().list({
  include: 'stock_keeping_units',
});
// Access included SKUs directly on each group
for (const group of groups.data) {
  const skus = group.stockKeepingUnits; // resolved array
  console.log(group.prefix, skus?.length, 'SKUs');
}

// Available DIDs (with DID group and stock keeping units)
const available = await client.availableDids().list({
  include: 'did_group.stock_keeping_units',
});
// Access nested includes
const ad = available.data[0];
const didGroup = ad.didGroup; // resolved DidGroup
const skus = didGroup?.stockKeepingUnits; // resolved StockKeepingUnit[]
console.log(ad.number, didGroup?.prefix, skus?.[0]?.monthlyPrice);

// Other read-only resources
client.didGroupTypes();
client.nanpaPrefixes();
client.proofTypes();
client.publicKeys();
client.addressRequirements();
client.supportingDocumentTemplates();

// Stock keeping units and qty-based pricings are include-only resources:
// - StockKeepingUnit: include on didGroups (see above)
// - QtyBasedPricing: include on capacityPools
const pools = await client.capacityPools().list({ include: 'qty_based_pricings' });

// Balance (singleton)
const balance = await client.balance().find();

DIDs

import { ref } from '@didww/sdk';

// List DIDs
const dids = await client.dids().list();

// Assign a trunk to a DID (automatically nullifies trunk group)
await client.dids().update({
  id: 'did-id',
  voiceInTrunk: ref('voice_in_trunks', 'trunk-id'),
});

// Assign capacity pool and update attributes in one call
await client.dids().update({
  id: 'did-id',
  capacityPool: ref('capacity_pools', 'pool-id'),
  dedicatedChannelsCount: 1,
  capacityLimit: 5,
  description: 'Updated',
});

// Unassign a trunk (set to null)
await client.dids().update({
  id: 'did-id',
  voiceInTrunk: null,
});

Voice In Trunks

import { sipConfiguration, pstnConfiguration, ref, Codec, TransportProtocol } from '@didww/sdk';

// Create SIP trunk
const trunk = await client.voiceInTrunks().create({
  name: 'My SIP Trunk',
  configuration: sipConfiguration({
    host: 'sip.example.com',
    port: 5060,
    codecIds: [Codec.PCMU, Codec.PCMA],
    transportProtocolId: TransportProtocol.UDP,
  }),
  pop: ref('pops', 'pop-id'),
});

// Create PSTN trunk
const pstnTrunk = await client.voiceInTrunks().create({
  name: 'My PSTN Trunk',
  configuration: pstnConfiguration({ dst: '12125551234' }),
});

// Update trunk
await client.voiceInTrunks().update({
  id: trunk.data.id,
  name: 'Updated Name',
});

// Delete trunk
await client.voiceInTrunks().remove(trunk.data.id);

SIP Registration (2026-04-16)

A Voice In Trunk can also authenticate inbound calls via SIP registration credentials generated by DIDWW. The SDK auto-cascades the dependent fields the server requires inside serializeTrunkConfiguration:

  • enabledSipRegistration: true strips host / port from the wire (the server rejects them with 422 otherwise);
  • a non-empty host flips enabledSipRegistration to false and forces useDidInRuri: false on the wire so the server accepts the disable PATCH.

The server generates incomingAuthUsername and incomingAuthPassword and surfaces them in the response when SIP registration is enabled.

const trunk = await client.voiceInTrunks().create({
  name: 'Office (registered)',
  configuration: sipConfiguration({
    enabledSipRegistration: true,
    useDidInRuri: true,
    cnamLookup: true,
  }),
});
const config = trunk.data.configuration as SipConfiguration;
// config.incomingAuthUsername — server-generated
// config.incomingAuthPassword — server-generated

To disable SIP registration on an existing trunk, just set host — the cascade flips enabledSipRegistration and useDidInRuri to false automatically on the wire:

await client.voiceInTrunks().update({
  id: trunk.data.id,
  configuration: sipConfiguration({ host: 'sip.example.com' }),
});

Voice In Trunk Groups

const group = await client.voiceInTrunkGroups().create({
  name: 'Primary Group',
  capacityLimit: 50,
});

Voice Out Trunks

Note: Voice Out Trunks and some OnCliMismatchAction values (REPLACE_CLI, RANDOMIZE_CLI) require additional account configuration. Contact DIDWW support to enable these features.

Voice Out Trunks use a polymorphic authenticationMethod (2026-04-16). Three types are supported:

  • credentials_and_ip -- default method; username and password are server-generated and returned in the response.
  • twilio -- requires a twilioAccountSid.
  • ip_only -- read-only; can only be configured by DIDWW staff upon request. Cannot be set via the API.
import { DefaultDstAction, OnCliMismatchAction, credentialsAndIpAuthenticationMethod } from '@didww/sdk';

// NOTE: 203.0.113.0/24 is RFC 5737 TEST-NET-3 documentation space.
// Replace with the real CIDR of your SIP infrastructure.
const voTrunk = await client.voiceOutTrunks().create({
  name: 'My Outbound Trunk',
  authenticationMethod: credentialsAndIpAuthenticationMethod({
    allowedSipIps: ['203.0.113.0/24'],
    techPrefix: '',
  }),
  defaultDstAction: DefaultDstAction.ALLOW_ALL,
  onCliMismatchAction: OnCliMismatchAction.REJECT_CALL,
});
// voTrunk.data.authenticationMethod.username -- server-generated
// voTrunk.data.authenticationMethod.password -- server-generated

Orders

import { didOrderItem, availableDidOrderItem, reservationDidOrderItem, capacityOrderItem } from '@didww/sdk';

// Order by SKU
const order = await client.orders().create({
  allowBackOrdering: true,
  items: [didOrderItem({ skuId: 'sku-id', qty: 2 })],
});

// Order a specific available DID
const order2 = await client.orders().create({
  items: [availableDidOrderItem({ skuId: 'sku-id', availableDidId: 'available-did-id' })],
});

// Order a reserved DID
const order3 = await client.orders().create({
  items: [reservationDidOrderItem({ skuId: 'sku-id', didReservationId: 'reservation-id' })],
});

// Order capacity
const order4 = await client.orders().create({
  items: [capacityOrderItem({ capacityPoolId: 'pool-id', qty: 1 })],
});

DID Reservations

const reservation = await client.didReservations().create({
  description: 'Reserved for client',
  availableDid: ref('available_dids', 'available-did-id'),
});

await client.didReservations().remove(reservation.data.id);

Shared Capacity Groups

const scg = await client.sharedCapacityGroups().create({
  name: 'Shared Group',
  sharedChannelsCount: 20,
  meteredChannelsCount: 5,
  capacityPool: ref('capacity_pools', 'pool-id'),
});

Identities

import { IdentityType, ref } from '@didww/sdk';

const identity = await client.identities().create({
  identityType: IdentityType.PERSONAL,
  firstName: 'John',
  lastName: 'Doe',
  phoneNumber: '12125551234',
  country: ref('countries', 'country-id'),
});

Addresses

const address = await client.addresses().create({
  cityName: 'New York',
  postalCode: '10001',
  address: '123 Main St',
  identity: ref('identities', 'identity-id'),
  country: ref('countries', 'country-id'),
});

Exports

import { ExportType } from '@didww/sdk';

const exp = await client.exports().create({
  exportType: ExportType.CDR_IN,
  filters: {
    from: '2026-04-15 00:00:00', // inclusive (time_start >= from)
    to: '2026-04-16 00:00:00',   // exclusive (time_start < to)
  },
});

// Download when completed
const data = await client.downloadExport(exp.data.url);

Address Verifications

// List address verifications
const verifications = await client.addressVerifications().list();

// Create address verification
const verification = await client.addressVerifications().create({
  callbackUrl: 'https://example.com/callback',
  callbackMethod: CallbackMethod.POST,
  address: ref('addresses', 'address-id'),
  dids: [ref('dids', 'did-id')],
});

Emergency Services (2026-04-16)

// List emergency requirements
const emergReqs = await client.emergencyRequirements().list();

// Create emergency verification
const emergVerification = await client.emergencyVerifications().create({
  callbackUrl: 'https://example.com/callback',
  callbackMethod: CallbackMethod.POST,
  address: ref('addresses', 'address-id'),
  dids: [ref('dids', 'did-id')],
});

// List emergency calling services
const emergServices = await client.emergencyCallingServices().list();

DID History (2026-04-16)

// List DID history
const history = await client.didHistory().list();
for (const entry of history.data) {
  console.log(entry.action, entry.createdAt);
}

Included Resources

Use the include parameter to sideload related resources. Included relationships are resolved directly on the parent object:

// Regions with their country
const regions = await client.regions().list({
  include: 'country',
});
for (const region of regions.data) {
  console.log(region.name, region.country?.name);
}

// DID groups with nested stock keeping units
const groups = await client.didGroups().list({
  include: 'stock_keeping_units',
});
for (const group of groups.data) {
  for (const sku of group.stockKeepingUnits || []) {
    console.log(group.prefix, sku.monthlyPrice);
  }
}

// Available DIDs with nested includes (did_group → stock_keeping_units)
const available = await client.availableDids().list({
  include: 'did_group.stock_keeping_units',
});
const ad = available.data[0];
const skuId = ad.didGroup?.stockKeepingUnits?.[0]?.id;

// DIDs with voice trunk and capacity pool
const dids = await client.dids().list({
  include: 'voice_in_trunk,capacity_pool',
});
for (const did of dids.data) {
  console.log(did.number, did.voiceInTrunk?.name, did.capacityPool?.name);
}

Query Parameters

const result = await client.regions().list({
  filter: { 'country.id': 'uuid', name: 'Arizona' },
  include: ['country'],
  sort: '-name',
  page: { number: 1, size: 25 },
});

Dirty Tracking (PATCH Optimization)

When you fetch a resource from the API, the SDK snapshots its writable attributes. On update, only changed fields are sent in the PATCH request:

// Load a DID from the API
const response = await client.dids().find('did-id', { include: 'voice_in_trunk' });
const did = response.data;

// Modify only what you need
did.description = 'Updated description';

// PATCH request body (JSON:API format):
// {
//   "data": {
//     "id": "did-id",
//     "type": "dids",
//     "attributes": { "description": "Updated description" }
//   }
// }
await client.dids().update(did);

When you build an object manually (without fetching first), all provided fields are sent:

// All provided fields are sent because there is no clean snapshot
// PATCH request body (JSON:API format):
// {
//   "data": {
//     "id": "did-id",
//     "type": "dids",
//     "attributes": { "description": "Updated", "capacity_limit": 5 }
//   }
// }
await client.dids().update({
  id: 'did-id',
  description: 'Updated',
  capacityLimit: 5,
});

Included resources are also tracked — you can modify and update them directly:

const response = await client.dids().find('did-id', { include: 'voice_in_trunk' });
const trunk = response.data.voiceInTrunk;

// trunk has a clean snapshot — only dirty fields are sent
trunk.name = 'Renamed trunk';

// PATCH request body (JSON:API format):
// {
//   "data": {
//     "id": "<trunk-id>",
//     "type": "voice_in_trunks",
//     "attributes": { "name": "Renamed trunk" }
//   }
// }
await client.voiceInTrunks().update(trunk);

Setting a field to null explicitly clears it:

const response = await client.dids().find('did-id', { include: 'voice_in_trunk' });
const did = response.data;

// Explicitly clear the trunk relationship
did.voiceInTrunk = null;

// PATCH request body (JSON:API format):
// {
//   "data": {
//     "id": "did-id",
//     "type": "dids",
//     "relationships": {
//       "voice_in_trunk": { "data": null }
//     }
//   }
// }
await client.dids().update(did);

Trunk Configuration Types

TypeFactory
SIPsipConfiguration({ host, port, codecIds, ... })
PSTNpstnConfiguration({ dst })

Order Item Types

TypeFactory
DID (by SKU)didOrderItem({ skuId, qty })
Available DIDavailableDidOrderItem({ skuId, availableDidId })
Reservation DIDreservationDidOrderItem({ skuId, didReservationId })
CapacitycapacityOrderItem({ capacityPoolId, qty })
EmergencyemergencyOrderItem({ emergencyCallingServiceId, qty })

Date and Datetime Fields

All date and datetime fields are returned as ISO 8601 strings. JavaScript's Date object has known pitfalls (mutable, timezone handling, 0-indexed months), so the SDK intentionally keeps these as string and lets you parse them with the library of your choice.

  • Datetime fields — ISO 8601 strings e.g. "2024-01-15T10:00:00.000Z":
    • createdAt — present on most resources
    • expiresAt — Did, DidReservation, Proof, EncryptedFile (nullable)
    • activatedAt — EmergencyCallingService (nullable)
    • canceledAt — EmergencyCallingService (nullable)
  • Date-only fields — date strings e.g. "1990-05-20":
    • Identity.birthDate
    • CapacityPool.renewDate, EmergencyCallingService.renewDate (nullable)
    • DidOrderItem.billedFrom, DidOrderItem.billedTo
  • String fields (not numeric):
    • EmergencyRequirement.estimateSetupTime — e.g. "7-14 days", "1"
    • EmergencyRequirement.requirementRestrictionMessage — nullable

Important changes from previous API versions:

  • expireAt renamed to expiresAt on DidReservation and EncryptedFile
  • renewDate is a date-only string, NOT a datetime
  • estimateSetupTime is a string, NOT a number
const did = await client.dids().find('uuid');
console.log(did.createdAt);   // "2024-01-15T10:00:00.000Z"
console.log(did.expiresAt);   // null or "2025-01-15T10:00:00.000Z"

// Parse with your preferred library:
import { parseISO } from 'date-fns';
const date = parseISO(did.createdAt);

Enums

Type-safe enums are provided for all API constant fields:

import {
  // String enums
  CallbackMethod, // POST, GET
  AddressVerificationStatus, // PENDING, APPROVED, REJECTED
  ExportType, // CDR_IN, CDR_OUT
  ExportStatus, // PENDING, PROCESSING, COMPLETED
  IdentityType, // PERSONAL, BUSINESS, ANY
  OrderStatus, // PENDING, CANCELED, COMPLETED
  OnCliMismatchAction, // SEND_ORIGINAL_CLI, REJECT_CALL, REPLACE_CLI*, RANDOMIZE_CLI* (requires account config)
  MediaEncryptionMode, // DISABLED, SRTP_SDES, SRTP_DTLS, ZRTP
  DefaultDstAction, // ALLOW_ALL, REJECT_ALL
  VoiceOutTrunkStatus, // ACTIVE, BLOCKED
  CliFormat, // RAW, E164, LOCAL
  AreaLevel, // WORLDWIDE, COUNTRY, AREA, CITY
  Feature, // VOICE, VOICE_IN, VOICE_OUT, T38, SMS, SMS_IN, SMS_OUT, P2P, A2P, EMERGENCY, CNAM_OUT
  StirShakenMode, // DISABLED, ORIGINAL, PAI, ORIGINAL_PAI, VERSTAT
  EmergencyCallingServiceStatus, // ACTIVE, CANCELED, CHANGES_REQUIRED, IN_PROCESS, NEW, PENDING_UPDATE
  EmergencyVerificationStatus, // PENDING, APPROVED, REJECTED
  DiversionRelayPolicy, // NONE, AS_IS, SIP, TEL
  // Integer enums
  TransportProtocol, // UDP=1, TCP=2, TLS=3
  RxDtmfFormat, // RFC_2833=1, SIP_INFO=2, RFC_2833_OR_SIP_INFO=3
  TxDtmfFormat, // DISABLED=1, RFC_2833=2, SIP_INFO_RELAY=3, SIP_INFO_DTMF=4
  SstRefreshMethod, // INVITE=1, UPDATE=2, UPDATE_FALLBACK_INVITE=3
  Codec, // TELEPHONE_EVENT=6, G723=7, G729=8, PCMU=9, PCMA=10, ...
} from '@didww/sdk';

File Encryption & Upload

import { Encrypt } from '@didww/sdk';

// Instance-based: fetches public keys from the API automatically
const enc = new Encrypt(client);
const fingerprint = await enc.getFingerprint();
const encrypted = await enc.encrypt(fileBuffer);

const ids = await client.uploadEncryptedFiles(fingerprint, [
  { data: encrypted, description: 'My document', filename: 'document.pdf.enc' },
]);

Static functions are also available for manual key management:

import { encryptWithKeys, calculateFingerprint, ref } from '@didww/sdk';
import { readFileSync } from 'node:fs';

const keys = await client.publicKeys().list();
const pems: [string, string] = [keys.data[0].key, keys.data[1].key];

const fingerprint = calculateFingerprint(pems);
const encrypted = encryptWithKeys(readFileSync('document.pdf'), pems);
const ids = await client.uploadEncryptedFiles(fingerprint, [
  { data: encrypted, description: 'My document', filename: 'document.pdf.enc' },
]);

// Create proof with uploaded files
await client.proofs().create({
  proofType: ref('proof_types', 'type-id'),
  entity: ref('identities', 'identity-id'),
  files: ids.map((id) => ref('encrypted_files', id)),
});

Webhook Signature Validation

Validate incoming webhook callbacks from DIDWW using HMAC-SHA1 signature verification.

Initialize the validator with the callback secret that is enabled in the DIDWW User Panel (APIs → DIDWW API 3 → Callback Secrets). DIDWW signs every callback with it and sends callbacks only while a callback secret is enabled.

import { RequestValidator } from '@didww/sdk';

const validator = new RequestValidator('your-callback-secret');

// In your webhook handler:
const valid = validator.validate(
  requestUrl, // full original URL
  payload, // Record<string, string> of payload key-value pairs
  signature, // value of X-DIDWW-Signature header
);

Error Handling

import { DidwwApiError } from '@didww/sdk';

try {
  await client.orders().create({
    /* ... */
  });
} catch (error) {
  if (error instanceof DidwwApiError) {
    console.log('Status:', error.status);
    for (const err of error.errors) {
      console.log(`Error: ${err.detail} (code: ${err.code})`);
    }
  }
}

All Supported Resources

ResourceRepositoryOperations
Countryclient.countries()list, find
Regionclient.regions()list, find
Cityclient.cities()list, find
Areaclient.areas()list, find
NanpaPrefixclient.nanpaPrefixes()list, find
Popclient.pops()list, find
DidGroupTypeclient.didGroupTypes()list, find
DidGroupclient.didGroups()list, find
AvailableDidclient.availableDids()list, find
ProofTypeclient.proofTypes()list, find
PublicKeyclient.publicKeys()list, find
AddressRequirementclient.addressRequirements()list, find
SupportingDocumentTemplateclient.supportingDocumentTemplates()list, find
StockKeepingUnitinclude on didGroups()include only
QtyBasedPricinginclude on capacityPools()include only
Balanceclient.balance()find
Didclient.dids()list, find, update, delete
VoiceInTrunkclient.voiceInTrunks()list, find, create, update, delete
VoiceInTrunkGroupclient.voiceInTrunkGroups()list, find, create, update, delete
VoiceOutTrunkclient.voiceOutTrunks()list, find, create, update, delete
VoiceOutTrunkRegenerateCredentialclient.voiceOutTrunkRegenerateCredentials()create
DidReservationclient.didReservations()list, find, create, update, delete
CapacityPoolclient.capacityPools()list, find, update
SharedCapacityGroupclient.sharedCapacityGroups()list, find, create, update, delete
Orderclient.orders()list, find, create, update, delete
Exportclient.exports()list, find, create, update, delete
Addressclient.addresses()list, find, create, update, delete
AddressVerificationclient.addressVerifications()list, find, create, update, delete
Identityclient.identities()list, find, create, update, delete
EncryptedFileclient.encryptedFiles()list, find, delete
PermanentSupportingDocumentclient.permanentSupportingDocuments()create, delete
Proofclient.proofs()create, delete
AddressRequirementValidationclient.addressRequirementValidations()create
DidHistoryclient.didHistory()list, find
EmergencyRequirementclient.emergencyRequirements()list, find
EmergencyRequirementValidationclient.emergencyRequirementValidations()create
EmergencyCallingServiceclient.emergencyCallingServices()list, find, delete
EmergencyVerificationclient.emergencyVerifications()list, find, create, update

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/didww/didww-api-3-typescript-sdk

Releasing

  1. Ensure you are on the main branch and have committed all changes.
  2. npm ci && npm run typecheck && npm run lint && npm run format:check ensure all checks pass
  3. npm version X.Y.Z (creates git commit and tag)
  4. npm run build build package
  5. npm publish --access public releases npm package
  6. git push --follow-tags origin main pushes git commit and tag to GitHub

Note: if npm publish fails with error like 404 '@didww/[email protected]' is not in this registry. you need to refresh credentials via npm login.

License

MIT

版本与发布记录

@didww/sdk 共发布 7 个版本,首次发布于 2026/02/26;过去 12 个月发布了 7 个版本。

版本发布日期距今
3.1.1latest2026/10/071 个月前
3.1.02026/05/056 个月前
2.0.12022-05-102026/05/056 个月前
3.0.02026/04/246 个月前
2.0.02026/03/207 个月前
1.1.02026/03/028 个月前

关于 @didww/sdk 的常见问题

@didww/sdk 是什么?

DIDWW API v3 TypeScript SDK

如何安装 @didww/sdk?

在项目目录运行 npm install @didww/sdk,或使用 pnpm add / yarn add / bun add。

@didww/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@didww/sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@didww/sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@didww/sdk 可以商用吗?

@didww/sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@didww/sdk 的下载量有多少?

根据 npm 官方下载统计,@didww/sdk 在 2026/10/12 – 2026/11/10 这 30 天内被下载 2,717 次,日均约 91 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@didww/sdk 还在维护吗?

最新版本 3.1.1 发布于 2026/10/07(1 个月前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/02/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。