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

@nextage/nx-frame-be

v1.0.60

Published

## GraphQL: la superficie generata

Readme

NxFrameBe Library

GraphQL: la superficie generata

generateSchema(ctrl, extension, mergeCodedEntity?, readOnly?) genera per ogni modulo quattro query (count, list, get, findOne), nove mutation (create, update, remove, copy, le tre mutation array, bulkUpdate, bulkRemove) e tre subscription. Le operazioni di dominio del modulo si dichiarano a parte, in extension.typeDefs / extension.resolvers, e il generatore non le tocca.

Un modulo dichiara quali mutation generate non fanno parte della sua API con mutations:

schemaRegistry.register(ctrl, {
  fields, typeDefs, resolvers, roles,
  mutations: { create: false, copy: false, bulkUpdate: false, bulkRemove: false }
});
  • un'operazione a false non e' generata: niente campo nello SDL, niente resolver;
  • assente o true: generata come sempre - senza la mappa non cambia nulla;
  • una chiave che non nomina una mutation generata fa fallire la generazione;
  • query, mutation custom e subscription non sono governate dalla mappa;
  • readOnly = true non genera nessuna mutation e nessuna subscription, e prevale sulla mappa.

Rifiutare a runtime una mutation generata, con un resolver che lancia, resta possibile ma non e' il modo di togliere una superficie statica: l'operazione resterebbe pubblicata.

La LIST generata legge solo cio' che la selezione richiede (opt-in)

Un modulo con documenti pesanti puo' chiedere che la query LIST generata legga da Mongo solo i campi che il client ha selezionato:

schemaRegistry.register(ctrl, {
  fields, typeDefs, resolvers, roles,
  projection: { dependencies: { category: ['aclass'], label: ['name'] } }
});
  • i campi selezionati diventano una projection Mongo, con _id sempre letto; conta il NOME del campo, non l'alias; inline fragment e fragment spread sono seguiti; di una selezione annidata si legge il path di primo livello (aclass { code } legge aclass); __typename e' ignorato;
  • dependencies dichiara, per campo GraphQL, i path che il suo field resolver legge oltre al campo stesso: per un campo calcolato, o per un resolver che legge altri campi del documento;
  • un campo selezionato che non e' un path dello schema e non e' dichiarato fa leggere il documento intero: un resolver di cui non si conoscono gli input non resta mai senza dati;
  • vale SOLO per il resolver LIST generato: count, get, findOne, le query custom e i chiamanti interni di ctrl.list leggono documenti interi come prima; senza projection non cambia nulla.

Un ctrl.list sovrascritto riceve la projection nel parametro fields: e' li' che, per esempio, un populate si puo' limitare ai campi selezionati.

Tenancy

Con un provider registrato su APP.tenancy, ogni modello il cui schema dichiara il campo del proprietario e' scopato per default (tenancy: none per escluderlo). Tutte le operazioni generate lo rispettano: letture per id e per filtro, create, update, remove e le loro varianti bulk, copy (sorgente letta con lo scoping, proprietario della copia deciso dal provider) e le tre scritture array (solo su un documento che il contesto puo' scrivere). Le primitive *Native non hanno hook ne' scoping, per contratto.

Rimozione: la pipeline e' del framework, il predicato puo' essere del modello

BaseModel.remove(id, context) esegue beforeRemove, la delete, l'audit CRUD e afterRemove; nei controller che pubblicano eventi la stessa chiamata sta nella transazione dell'outbox. Un modello che deve vincolare la cancellazione a uno stato del documento non riscrive nulla di questo: sovrascrive removeFilter(id, context) e restituisce le condizioni da aggiungere al filtro della delete.

  • Le condizioni le giudica la delete stessa, in modo atomico: un documento che smette di soddisfarle dopo beforeRemove - una scrittura concorrente - resta. Un controllo in beforeRemove su uno stato che altri possono cambiare non lo garantirebbe.
  • Il filtro base si applica dopo le condizioni e non e' sovrascrivibile: _id e, con la tenancy, il proprietario verificato - letto con la sessione del contesto, giudicato da assertWritable e pinnato nella delete, come nelle scritture array. Un documento il cui proprietario cambia fra la verifica e la delete non viene cancellato. Le condizioni possono quindi solo restringere.
  • Una delete che non cancella nulla - documento sparito o condizioni non soddisfatte - e' rifiutata con il ForbiddenError di un documento mancante, senza audit e senza afterRemove. Chi vuole dire al chiamante il motivo rilegge il documento dopo il rifiuto: quella lettura spiega l'esito, non lo cambia.