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

@shopimind/sdk-shopimind

v1.0.3

Published

Official JavaScript/TypeScript SDK for the Shopimind API. Mirrors the PHP SDK (shopimind/sdk-shopimind) feature-for-feature.

Readme

@shopimind/sdk-shopimind

SDK officiel JavaScript / TypeScript pour l'API Shopimind.

  • Node.js ≥ 14
  • CommonJS (require) et ESM / TypeScript (import)
  • Types .d.ts inclus
  • Dépendance runtime unique : axios
  • Retry automatique, chunking optionnel, format de retour uniforme (envelope)

Sommaire

  1. Installation
  2. Quick start
  3. Format de réponse — envelope uniforme
  4. Lire / récupérer des données (GET)
  5. Écrire des données (create / update / delete / bulk)
  6. Retry automatique
  7. Chunking optionnel
  8. Helpers partagés
  9. Configuration du client
  10. Enregistrer une shop
  11. Valider un webhook entrant
  12. Ressources disponibles
  13. TypeScript
  14. Périmètre couvert

Installation

Via registre

# npm
npm install @shopimind/sdk-shopimind

# yarn
yarn add @shopimind/sdk-shopimind

# pnpm
pnpm add @shopimind/sdk-shopimind

Pour un registre privé (GitHub Packages, Verdaccio, Nexus), router le scope @shopimind dans le .npmrc du projet consommateur :

@shopimind:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Ne jamais committer un token : référencez une variable d'environnement (${GITHUB_TOKEN}) ou placez le token dans le ~/.npmrc utilisateur.

Via Git (sans registre)

Épinglez toujours un tag pour garantir une version reproductible :

yarn add git+https://github.com/shopimind/shopimind-api-js-sdk.git#v1.0.2
# ou
npm install git+https://github.com/shopimind/shopimind-api-js-sdk.git#v1.0.2

Via chemin local (développement)

yarn add file:../shopimind-api-js-sdk
# ou, pour itérer en live :
#   cd shopimind-api-js-sdk && yarn link
#   cd ../mon-projet && yarn link @shopimind/sdk-shopimind

Quick start

const { SpmClient, SpmCustomers } = require('@shopimind/sdk-shopimind');

const client = SpmClient.getClient('v1', process.env.SHOPIMIND_API_KEY);

// Écrire (synchronisation)
const res = await SpmCustomers.bulkSave(client, customers, { chunk: true });
if (!res.ok) {
  console.error('Sync failed', res.error);
  return;
}
console.log(`Synced ${res.data.sent_count}, rejected ${res.data.rejected_count}`);

// Lire
const page = await SpmCustomers.list(client, { limit: 50 });
console.log(page.data);

En TypeScript / ESM :

import { SpmClient, SpmCustomers } from '@shopimind/sdk-shopimind';

Format de réponse — envelope uniforme

Toutes les méthodes retournent le même shape, succès ou échec. Le SDK ne throw jamais pour une erreur HTTP.

{
  ok: true | false,
  statusCode: 200 | 4xx | 5xx | 0,
  data: {/* body de l'API */} | null,
  error: null | {
    message: string,
    code: string,          // 'HTTP_503', 'ETIMEDOUT', etc.
    retryable: boolean,
    attempts: number,      // combien de tentatives effectuées
    details?: any,         // pour les aggregated errors (chunk failures)
  },
}
const res = await SpmCustomers.bulkSave(client, items);

if (res.ok) {
  console.log(res.data.sent_count, res.data.rejected_count);
} else if (res.error.retryable) {
  console.warn('Transient failure, API is unavailable');
} else {
  console.error('Permanent failure', res.error.message);
}

Pour les routes de lecture, le payload de l'API est dans res.data (souvent res.data.data pour un élément unique, selon l'endpoint).


Lire / récupérer des données (GET)

Les ressources de données exposent des méthodes de lecture statiques qui renvoient l'envelope standard.

const { SpmCustomers, SpmOrders, SpmCustomersAddresses } = require('@shopimind/sdk-shopimind');

// Liste paginée — la query est sérialisée en query-string
const page = await SpmCustomers.list(client, { limit: 50, offset: 0 });

// Un élément par identifiant (+ projection de champs optionnelle)
const customer = await SpmCustomers.get(client, 'cust_1', ['email', 'first_name']);
const order    = await SpmOrders.get(client, 'ord_123');
const byRef    = await SpmOrders.getByReference(client, 'CMD-2024-0001');

// Sous-ressources d'un parent
const addresses = await SpmCustomersAddresses.list(client, 'cust_1', { limit: 20 });
const groups    = await SpmCustomers.listGroups(client, 'cust_1');

Méthodes de lecture par ressource :

| Ressource | Lecture | |---|---| | SpmCustomers | get(client, id, fields?) · list(client, query?) · listGroups(client, customerId, query?) | | SpmCustomersAddresses | list(client, customerId, query?) | | SpmCustomersGroups, SpmProducts, SpmProductsCategories, SpmProductsManufacturers, SpmOrdersCarriers, SpmOrdersStatuses, SpmVouchers, SpmCarts | list(client, query?) | | SpmOrders | get(client, orderId, fields?) · getByReference(client, reference, fields?) · list(client, query?) |

SpmProductsImages et SpmProductsVariations n'ont pas de route GET côté API (écriture uniquement).


Écrire des données (create / update / delete / bulk)

Deux styles selon le besoin.

Statique — opérations bulk (recommandé pour la synchro)

await SpmCustomers.bulkSave(client, items, { chunk: true });
await SpmCustomers.bulkUpdate(client, items, { chunk: true });
await SpmCustomers.delete(client, 'cust_1');
await SpmCustomers.bulkDelete(client, ['cust_1', 'cust_2']);

Instance — un item à la fois

const { SpmCustomers } = require('@shopimind/sdk-shopimind');

const customer = new SpmCustomers(client);
customer.customer_id = 'cust_1';
customer.email = '[email protected]';
customer.first_name = 'Foo';
customer.last_name = 'Bar';
customer.is_opt_in = true;
customer.is_newsletter_subscribed = false;
customer.lang = 'fr';
customer.is_active = true;
customer.created_at = '2026-01-01T00:00:00Z';
customer.updated_at = '2026-01-01T00:00:00Z';

const res = await customer.save();   // ou .update()

Ressources imbriquées (addresses, images, variations)

Le constructeur prend le parent ; les méthodes statiques prennent le parent en 2ᵉ argument :

const { SpmCustomersAddresses } = require('@shopimind/sdk-shopimind');

await SpmCustomersAddresses.bulkSave(client, 'cust_1', addresses, { chunk: true });
await SpmCustomersAddresses.bulkDelete(client, 'cust_1', [42, 43]);

Endpoint flat bulkSaveAll

Payload plat avec le parent embarqué dans chaque item (batch multi-parents) :

await SpmCustomersAddresses.bulkSaveAll(client, [
  { customer_id: 'cust_1', address_id: 1, /* ... */ },
  { customer_id: 'cust_2', address_id: 2, /* ... */ },
], { chunk: true });

Associer un data_source

Toutes les ressources de synchronisation acceptent optionnellement un identifiant ou libellé de source de données :

customer.id_data_source = 3;
customer.source_label = 'Magasin Paris';
await customer.save();

Retry automatique

Par défaut, le SDK retry 3 fois sur :

  • HTTP 408, 429, 500, 502, 503, 504
  • Erreurs réseau : ECONNRESET, ETIMEDOUT, ECONNREFUSED, ENETUNREACH, ENOTFOUND, EAI_AGAIN

Avec un backoff exponentiel (1s → 2s → 4s avec jitter ±500ms, cap à 10s).

// Personnaliser
const client = SpmClient.getClient('v1', apiKey, {
  retry: {
    maxRetries: 5,
    backoffBaseMs: 2000,
    backoffCapMs: 30000,
    retryableStatus: [429, 502, 503, 504],
  },
});

// Désactiver
const client = SpmClient.getClient('v1', apiKey, { retry: false });

Chunking optionnel

Passez un gros tableau au SDK : il le découpe en batches alignés sur la limite de l'API et agrège les résultats.

const hugeArray = Array(500).fill().map((_, i) => ({ /* customer data */ }));

const res = await SpmCustomers.bulkSave(client, hugeArray, { chunk: true });

console.log(res.data.sent_count);   // total agrégé
console.log(res.data.chunks);       // détail par chunk (10 × 50)

Par défaut, chunkSize vaut la valeur alignée sur l'API NestJS :

| Ressource | CHUNK_SIZE | |---|---| | SpmCustomDataRecords | 20 | | SpmCustomers, SpmCustomersAddresses, SpmProducts, SpmProductsImages, SpmProductsVariations, SpmOrders, SpmVouchers | 50 | | SpmCustomersGroups, SpmProductsCategories, SpmProductsManufacturers, SpmOrdersCarriers, SpmOrdersStatuses | 100 |

await SpmProducts.bulkSave(client, items, { chunk: true, chunkSize: 25 }); // override
console.log(SpmCustomers.CHUNK_SIZE); // 50

Helpers partagés

const { SpmHelpers } = require('@shopimind/sdk-shopimind');

SpmHelpers.chunk(array, 50);
// → [[...50], [...50], ...]

SpmHelpers.mergeResponses([envelope1, envelope2, ...]);
// → envelope agrégée avec data.sent_count, data.rejected_count, data.chunks[]

SpmHelpers.extractCounts(envelope);
// → { sent: N, rejected: M, failed: K }

SpmHelpers.isRetryable(error);
// → true si l'erreur ou l'envelope est retryable (429 / 5xx / network)

SpmHelpers.formatError(envelope);
// → { message, code, statusCode, retryable, attempts, details }
//   safe à sérialiser pour des logs structurés

Configuration du client — toutes les options

const client = SpmClient.getClient('v1', 'your-api-key', {
  baseUrl: 'https://core-staging.shopimind.com',
  headers: { 'x-trace-id': 'abc-123' },
  timeout: 60000,
  labelSource: 'web',
  retry: { maxRetries: 3 },
});

| Option | Type | Défaut | Rôle | |---|---|---|---| | baseUrl | string | https://core.shopimind.com | URL de base de l'API | | headers | Record<string, string> | {} | Headers additionnels | | timeout | number | 30000 | Timeout de requête (ms) | | labelSource | string \| null | 'web' | Injecté en label_source dans les POST/PUT de synchro. null désactive. | | retry | SpmRetryOptions \| false | Voir Retry automatique | Politique de retry |

L'URL de base peut aussi être surchargée via la variable d'environnement SHOPIMIND_CORE_API_BASE. Priorité : options.baseUrl > SHOPIMIND_CORE_API_BASE > défaut.

Headers nécessaires pour shop/connection

L'endpoint POST /shop/connection attend trois headers spécifiques : client-id, client-version, current-build. Les passer via options.headers :

const client = SpmClient.getClient('v1', apiKey, {
  headers: {
    'client-id': clientId,
    'client-version': '5.0.0',
    'current-build': '1',
  },
});

Enregistrer une shop

const { SpmShopConnection } = require('@shopimind/sdk-shopimind');

const res = await SpmShopConnection.saveConfiguration(client, {
  default_currency: 'EUR',
  default_lang: 'fr',
  langs: ['fr', 'en'],
  timezone: 'Europe/Paris',
  url_client: 'https://myshop.example.com',
  ecommerce_version: '2.7.0',
  module_version: '5.0.0',
});

Valider un webhook Shopimind entrant

const { SpmRequestValidator } = require('@shopimind/sdk-shopimind');

const validation = SpmRequestValidator.validateRequest({
  clientId: req.headers['shopimind-client-identifiant'],
  hmacToken: req.headers['shopimind-token'],
  body: req.body,
  apiIdentification: config.apiIdentification,
  apiPassword: config.apiPassword,
});

if (!validation.valid) {
  return res.status(401).json({ error: validation.error });
}

Ressources disponibles

Le SDK couvre les endpoints publiés dans la documentation Swagger de l'API, avec deux exceptions conservées volontairement bien que masquées de la doc : POST shop/connection (connexion boutique) et data-sources (sources de données).

| Export | Endpoint | Méthodes | |---|---|---| | SpmShopConnection | shop/connection | saveConfiguration | | SpmCustomers | customers | CRUD + bulk + get / list / listGroups | | SpmCustomersAddresses | customers/:id/addresses + customers/addresses/bulk | CRUD + bulk + bulkSaveAll + list | | SpmCustomersGroups | customers-groups | CRUD + bulk + list | | SpmProducts | products | CRUD + bulk + list | | SpmProductsCategories | products-categories | CRUD + bulk + list | | SpmProductsImages | products/:id/images + products/images/bulk | CRUD + bulk + bulkSaveAll | | SpmProductsManufacturers | products-manufacturers | CRUD + bulk + list | | SpmProductsVariations | products/:id/variations + products/variations/bulk | CRUD + bulk + bulkSaveAll | | SpmOrders | orders | CRUD + bulk + get / getByReference / list | | SpmOrdersCarriers | orders-carriers | CRUD + bulk + list | | SpmOrdersStatuses | orders-statuses | CRUD + bulk + list | | SpmVouchers | vouchers | CRUD + bulk + list | | SpmDataSources | data-sources | list / create / update / delete | | SpmIntegrationConfig | integration-config | get / set — config posée par l'intégrateur (par boutique), résolue au rendu en {integration.<key>} | | SpmCustomDataDefinitions | custom-data-definitions | list / get / create / update (= extend) / extend / activate / deactivate / delete / listOverrides / updateOverrides | | SpmCustomDataRecords | custom-data-records/:definitionId | bulkSave (chunk 20) / list / update / delete / bulkDelete (chunk 20) | | SpmContacts | contacts, contact-consent-history, contact-messages-reject | get / list / listLists / listTags / listCustomDataDefinitions / listConsentHistory / listMessagesReject | | SpmEvents | events | create / update / list / listHistories / get / delete / trigger | | SpmCarts | carts | list (lecture seule — voir note) | | SpmLists | lists | list / get / create / update / delete / listContacts | | SpmCustomKpi | custom-stats/kpis | list / get / listSources / listFields / create / update / delete / preview |

SpmDataSources, SpmIntegrationConfig, SpmCustomDataDefinitions, SpmCustomDataRecords, SpmContacts, SpmEvents, SpmLists, SpmCustomKpi (ainsi que toutes les méthodes de lecture) exposent des méthodes statiques (client, …) — pas d'instanciation. Toutes retournent l'envelope standard.

Config intégrateur (SpmIntegrationConfig)

Un champ de config_schema déclaré owner: "integrator" est invisible côté marchand : c'est l'intégrateur qui pose sa valeur par boutique, avec sa clé API, et elle est résolue au rendu en {integration.<key>} (avec le default déclaré comme repli tant qu'elle n'est pas posée).

const { SpmIntegrationConfig } = require('@shopimind/sdk-shopimind');

// Poser des valeurs (clés owner:"integrator" uniquement)
await SpmIntegrationConfig.set(client, { tracking_base: 'https://t.partner.io/p', account_ref: 'acct_42' });

// Relire (valeurs posées + defaults déclarés)
const res = await SpmIntegrationConfig.get(client);
if (res.ok) console.log(res.data.data.values); // { tracking_base: '…', account_ref: '…' }

label_source n'est injecté que sur les endpoints de synchronisation de données (customers / products / orders / vouchers / addresses / images / variations…). Les routes de configuration et d'administration (shop/connection, data-sources, custom-data-*, events, lists, custom-stats, contacts, carts) ne le reçoivent pas — sinon leur validation stricte rejetterait le champ comme inconnu.

Paniers en lecture seule : l'API publique n'expose aucune route d'écriture pour les paniers (ils sont dérivés du tracking front et des cart_id des commandes). Poussez des commandes via SpmOrders.

Consentement : l'historique de consentement (EMAIL / SMS / WHATSAPP / PUSH) est en lecture seule via SpmContacts.listConsentHistory. L'API publique n'expose pas de route SET de consentement.

Hors périmètre clé API : les contrôleurs widgets et integrations utilisent un Bearer JWT (AuthGuard('jwt')), pas la clé spm-api-key de ce SDK — ils ne sont donc pas couverts.


TypeScript

Les types sont dans index.d.ts et importables directement :

import {
  SpmClient,
  SpmCustomers,
  SpmCustomerData,
  SpmEnvelope,
  SpmChunkedEnvelope,
  SpmHelpers,
} from '@shopimind/sdk-shopimind';

const client = SpmClient.getClient('v1', process.env.SHOPIMIND_API_KEY!);

const items: SpmCustomerData[] = [/* ... */];
const res: SpmEnvelope | SpmChunkedEnvelope = await SpmCustomers.bulkSave(client, items, { chunk: true });

if (res.ok) {
  const counts = SpmHelpers.extractCounts(res);
  console.log(`${counts.sent} envoyés, ${counts.rejected} rejetés`);
}

Interfaces data disponibles : SpmCustomerData, SpmCustomerAddressData, SpmBulkCustomerAddressData, SpmCustomerGroupData, SpmProductData, SpmProductCategoryData, SpmProductImageData, SpmBulkProductImageData, SpmProductManufacturerData, SpmProductVariationData, SpmBulkProductVariationData, SpmOrderData, SpmOrderProduct, SpmOrderCustomer, SpmOrderCarrierData, SpmOrderStatusData, SpmVoucherData, SpmShopConnectionData, SpmDataSourceData, SpmCreateDataSourceData, SpmEnvelope, SpmChunkedEnvelope, SpmBulkOptions, SpmRetryOptions.


Périmètre couvert

Le SDK reflète le contrat public de l'API (documentation Swagger), plus deux exceptions conservées volontairement : POST shop/connection (connexion boutique) et data-sources (sources de données).

Couvert

Synchronisation e-commerce (customers, products, orders, vouchers… et leurs sous-ressources), lecture (get / list / getByReference / listGroups), custom data (definitions & records), contacts & historiques (consent / messages-reject), events, lists, custom KPIs, carts (lecture seule), data sources.

Hors périmètre (volontaire)

Les endpoints d'administration masqués de la doc Swagger (@ApiExcludeController) ne sont pas exposés par le SDK : campaigns, templates, stats, domains, webhooks, job/import, export, users/sub-users, list-actions, newsletter-subscribers. Ils relèvent de l'interface d'administration (authentification Bearer JWT, pas la clé spm-api-key) ; pour les consommer, appelez l'API directement avec un Bearer JWT.

Ces endpoints d'administration n'ont jamais fait partie d'une version publiée du SDK (la dernière publiée, 1.0.1, ne les exposait pas) — leur absence n'est donc pas une rupture de compatibilité. Côté consentement : pas de route SET publique ; (dés)abonnement géré côté admin, historique lisible via SpmContacts.listConsentHistory.


License

Propriétaire — Shopimind.