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

@primocaredentgroup/customer-accounts

v0.4.0

Published

Convex component per la gestione clienti esterni del laboratorio — PrimoLabcore

Downloads

0

Readme

@primocaredentgroup/customer-accounts

Componente Convex riusabile per l'anagrafica clienti del laboratorio: account, contatti, sedi, profili operativi, note, task, attività e richieste dal portale.

Prerequisiti

  • Node.js 20+
  • Convex ^1.43.0
  • accesso npm a @primocaredentgroup/migration-kit@^2.2.4, peer richiesto dal component source
  • un provider di autenticazione configurato nell'app host

Installazione

npm install @primocaredentgroup/customer-accounts

Registra il componente mantenendo l'handle canonico customerAccounts:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import customerAccounts from "@primocaredentgroup/customer-accounts/convex.config.js";

const app = defineApp();
app.use(customerAccounts);
export default app;

Le capability di migrazione dichiarano componentName: "customerAccounts". Un alias di mount differente richiede supporto esplicito del migration kit.

Boundary host autenticato

Il browser non deve chiamare riferimenti components.customerAccounts e non deve fornire userId, authSubject, email o ruoli per autorizzarsi. L'host deriva l'identità da ctx.auth, applica il proprio RBAC e usa exposeApi come unico boundary pubblico per le operazioni CRM dello staff.

// convex/customerAccounts.ts
import {
  CustomerAccountsClient,
  exposeApi,
} from "@primocaredentgroup/customer-accounts";
import { components } from "./_generated/api.js";

export const customerAccountsClientForActor = (tokenIdentifier: string) =>
  new CustomerAccountsClient(components.customerAccounts, {
    callerTokenIdentifier: tokenIdentifier,
  });

export const {
  createAccount,
  updateAccount,
  getAccountByCustomerCode,
  paginateAccounts,
  addAccountContact,
  addAccountLocation,
  getAccountOverview,
  // ...esporta soltanto le funzioni richieste dall'app
} = exposeApi(components.customerAccounts, {
  getActorContext: async (ctx, permission) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Autenticazione richiesta");

    await authorizeCustomerAccountsPermission(identity, permission);
    return { tokenIdentifier: identity.tokenIdentifier };
  },
});

exposeApi espone intenzionalmente solo l'API CRM dello staff. Le operazioni portale restano nel client backend perché l'associazione utente → account è proprietà dell'host. Prima di chiamarle, l'host deve risolvere server-side l'accountId consentito e creare il client con il tokenIdentifier corrente.

const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error("Autenticazione richiesta");

const accountId = await resolvePortalAccountForIdentity(ctx, identity);
const client = customerAccountsClientForActor(identity.tokenIdentifier);

return await client.portal.createOrderRequest(ctx, {
  accountId,
  title: args.title,
});

Le letture di dettaglio portale usate dal client sono sempre scoped per accountId. I vecchi riferimenti raw non scoped restano disponibili soltanto per compatibilità con la 0.3 e sono deprecati.

Liste e paginazione

Le API legacy list* continuano a restituire array, ma sono bounded:

  • default 100 record;
  • massimo 200;
  • se esistono più record del limite richiesto, generano un errore esplicito che indica la corrispondente API paginate*.

Per sincronizzazioni, selettori completi e dataset non banali usa sempre le API paginate con paginationOpts Convex. Il numero di elementi per pagina deve essere compreso tra 1 e 200.

const firstPage = await client.accounts.paginate(ctx, {
  isActive: true,
  paginationOpts: { numItems: 100, cursor: null },
});

Le API paginate* usano cursori compatibili con il boundary dei componenti; trattali sempre come stringhe opache. searchAccountsPaginated usa un cursore dedicato legato ai filtri della ricerca e una finestra bounded di massimo 1.000 risultati. Per questa API gli advanced options endCursor, maximumRowsRead e maximumBytesRead non sono supportati.

Il filtro legacy tag richiede membership in un array e non può produrre una paginazione corretta con lo schema attuale. È supportato solo da listAccounts con scan bounded; non è accettato da paginateAccounts.

Per operazioni idempotenti non enumerare gli account: usa getAccountByCustomerCode. customerCode viene trim-mato in creazione e lookup, conserva il case ed è l'identità stabile e immutabile del master cliente.

Tabelle isolate

| Tabella | Responsabilità | | --- | --- | | lookupValues | Lookup configurabili | | accounts | Anagrafica master cliente | | accountContacts | Contatti dell'account | | accountLocations | Sedi dell'account | | accountOperationalProfiles | Profilo operativo 1:1 | | accountNotes | Note interne | | accountTasks | Task e follow-up | | accountActivities | Timeline audit | | portalClinicExternalLinks | Associazioni clinica esterna → account | | portalOrderRequests | Richieste del portale | | portalOrderAttachments | Allegati delle richieste |

API per dominio

Il client CustomerAccountsClient raggruppa le operazioni nei domini:

  • accounts: create/update/lifecycle/get/list/paginate/search;
  • contacts e locations: lifecycle, primario unico, list/paginate;
  • operationalProfiles: upsert 1:1 e get;
  • notes, tasks, activities: timeline operativa bounded/paginata;
  • lookups: lifecycle, lookup diretto, list/paginate;
  • overview: aggregato bounded dell'account;
  • portal: link cliniche, richieste e allegati con ownership verificata.

Tutti i validator degli argomenti, documenti, pagine e ritorni sono esportati da @primocaredentgroup/customer-accounts/validators e @primocaredentgroup/customer-accounts/returns.

I campi opzionali delle mutation update possono essere:

  • omessi per lasciarli invariati;
  • valorizzati per aggiornarli;
  • impostati a null per cancellarli, dove previsto dal validator.

Il client generico non permette di creare lookup con isSystem: true: quel flag rende il record non disattivabile e richiede una capability privilegiata progettata esplicitamente dall'host. I seed dimostrativi devono creare lookup normali.

Migration kit

La 0.4 espone una sola row verificata:

  • CustomerAccount.Identity, identità customerCode.

Contatti, sedi e transazioni portale sono rinviati finché non esistono chiavi esterne stabili e un contratto esplicito per le relazioni possedute dall'host.

Con migration-kit 2.2.x configura il modulo npm esplicitamente:

// migration-kit.config.ts
export default {
  componentGlobs: ["convex/components/*/migration.ts"],
  modules: ["@primocaredentgroup/customer-accounts/migration"],
};

La capability supporta preview e commit, batch fino a 100 record e un upsert diretto idempotente. preview non scrive. La row dichiara però reconcileStrategy: "skip": nel flusso orchestrato, un externalId già mappato viene conteggiato come skipped e la capability non viene richiamata. Per riconciliare dati sorgente modificati serve rimuovere consapevolmente la mapping o introdurre una futura capability di reconcile. Il customerCode passato come externalId deve coincidere esattamente con input.customerCode, essere non vuoto e non avere spazi esterni.

Upgrade dalla 0.3

Prima di installare la 0.4 su un deployment esistente esegui un preflight in sola lettura e blocca il rollout se trovi:

  • customerCode vuoti, con spazi esterni o duplicati esatti;
  • customerType vuoti o con spazi esterni (la 0.4 normalizza i nuovi valori e i filtri, ma non riscrive automaticamente le righe legacy);
  • duplicati (category, code) nei lookup;
  • più profili operativi per account;
  • più contatti o sedi primarie attive per account;
  • link portale duplicati per account/clinica;
  • richieste portale in bozza create con subject, email o user id invece del tokenIdentifier canonico: il confronto ownership della 0.4 è esatto, quindi completale prima dell'upgrade oppure esegui un backfill con una mapping identità verificata;
  • metadata attività non conformi al record JSON flat supportato: primitive o array di primitive, senza oggetti annidati.

La release aggiunge indici a tabelle esistenti. Sui deployment PrimoCare verificati il dataset è piccolo; per un'installazione con tabelle grandi applica il rollout staged prescritto da Convex: prima indici staged, backfill/verifica, poi indici attivi e codice che li interroga.

Non eseguire migrazioni o deploy di produzione come parte dell'installazione npm. Prima usa preview, conserva un export/backup, applica batch bounded e verifica mapping e conteggi prima/dopo. Un retry orchestrato di identità già mappate deve risultare skipped; il test di upsert con lo stesso ID riguarda la capability diretta, non sostituisce questa verifica dell'orchestratore.

Sviluppo del package

npm install
npm run verify
npm pack --dry-run

verify esegue build, test e typecheck usando i binding ufficiali tracciati nel repository. Dopo una modifica alla superficie Convex, il maintainer esegue separatamente npm run codegen, verifica il diff dei binding e solo dopo lancia verify. Il publish richiede il normale 2FA npm dell'organizzazione.