@startinblox/glcdi
v1.0.4
Published
Startin'blox GLCDI Components
Keywords
Readme
@startinblox/glcdi
GLCDI-specific Lit / Startin'blox web components, built on the upstream
solid-boilerplate
component scaffold (Lit + Startin'blox Core / Store / Router / Orbit, Vite,
Storybook, Cypress, BiomeJS).
The package powers the catalogue UI shipped with each GLCDI participant
deployment (participant-ui in glcdi).
It is consumed via Hubl's npm[] config — see Use in participant-ui
below.
What's in this package
| Component | Purpose |
|---|---|
| <sib-auth-apikey> + <sib-auth-provider-apikey> | API-key-only auth element. Drop-in compatible with <sib-auth-oidc> consumers — fires sib-auth:activated with { fetch, session }, exposes getFetch() / getUserWebId() / getSession() / isAuthenticated() / login() / logout(). Replaces OIDC redirect with an operator-pastes-an-X-Api-Key UX (GLCDI Tier 1). See management/IMPLEM_PLAN.md § Identity Tiering Strategy. |
| <solid-glcdi> | Sample OrbitComponent showing how to wire a data-driven Lit element into the Orbit lifecycle. Boilerplate carry-over — useful as a copy-base for new GLCDI views. |
| <sample-object> / <sample-objects> | Demo ComponentObjectHandler / ComponentObjectsHandler pattern for rendering individual objects and collections. |
Install
The package is published to latest on npm; the catalogue UI loads it via
JSDelivr at runtime through Hubl's npm[] config.
<script
type="module"
src="https://cdn.jsdelivr.net/npm/@startinblox/glcdi@latest/+esm"
defer
></script>For an end-to-end demo without Hubl:
<script type="module" src="https://cdn.jsdelivr.net/npm/@startinblox/core@latest/dist/store.js" defer></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@startinblox/glcdi@latest/+esm" defer></script>
<sib-auth-apikey
data-participant-id="urn:glcdi:participant:caney-fork"
data-participant-name="Caney Fork"
auto-login
></sib-auth-apikey>Use in participant-ui
Hubl's autoLogin partial supports an apikey branch (added for GLCDI Tier 1).
Wire <sib-auth-apikey> from config.json like this:
"npm": [
// ... existing entries ...
{
"package": "@startinblox/glcdi",
"version": "latest",
"path": "https://cdn.jsdelivr.net/npm/@startinblox/glcdi@latest/+esm"
}
],
"components": [
{
"type": "autoLogin",
"parameters": {
"apikey": true,
"participant-id": "${PARTICIPANT_ID}",
"participant-name": "${APP_TITLE}",
"storage-key-prefix": "glcdi_operator_api_key",
"provider-label": "${APP_TITLE} connector",
"management-url": "/management"
},
"route": false
}
]Hubl renders that as <sib-auth-apikey data-participant-id="…" auto-login="true">…</sib-auth-apikey>.
The element auto-creates a <sib-auth-provider-apikey> child if none is supplied,
so a single config entry is enough.
When IMPLEM_PLAN.md § 7.2
(Identity Tier 2 — user OIDC) lands, both apikey: true and oidc: true
branches can coexist; downstream components consume whichever
sib-auth:activated event they need.
Local development
npm install
npm run storybook # primary dev environment, http://localhost:6006
npm run cy:open # Cypress UI for component tests
npm run cy:run # headless Cypress run
npm run build # build the package
npm run locale:extract # update localisation files
npm run locale:build # build localisation bundles before publishingThe package itself ships without an index.html — Storybook is the
primary in-package surface for visual iteration. To exercise the components
inside a real Hubl-driven UI, point a local participant-ui build at the
local component bundle (npm link) or at a published preview tag.
Tests
| Layer | Where |
|---|---|
| Component tests | cypress/component/*.cy.ts — cy.mount(html…) per component |
| Storybook variants | stories/*.stories.ts |
Tests for the auth elements live at cypress/component/sib-auth-apikey.cy.ts
and stories at stories/sib-auth-apikey.stories.ts.
Forking notes (upstream sync)
scripts/init.js is the boilerplate's project-rename helper, kept here
intentionally so a future GLCDI-derived component package can fork from
solid-glcdi the same way solid-glcdi itself was forked from
solid-boilerplate. Run it after cloning the package under a new name:
git clone https://git.startinblox.com/components/solid-glcdi.git your-new-component-name
cd your-new-component-name
npm install
npm run init # walks you through the renameTo pull in upstream improvements from the boilerplate:
git remote add upstream https://git.startinblox.com/components/solid-boilerplate.git
git fetch upstream
git merge upstream/masterResolve conflicts in package.json, README.md, and any renamed files
(src/components/solid-glcdi.ts, cypress/component/solid-glcdi.cy.ts).
Core concepts (inherited from solid-boilerplate)
The technical surface — OrbitComponent, ObjectsHandler, ObjectHandler,
store reactivity helpers (setupCacheInvalidation, setupOnResourceReady,
setupOnSaveReset), cherryPickedProperties shape, available helpers under
src/helpers/ — is unchanged from the upstream boilerplate. See
the upstream README
for that documentation; everything below carries over identically.
OrbitComponent quick reference
Attributes: defaultDataSrc (track original src), dataSrc (resource to
display), nestedField (manual handling within Lit Task), uniq (duplicate
in same DOM), route (router-aware gating), cherryPickedProperties
(declared RDF / named props).
Methods: render, _afterAttach, _navigate(e), _getProxyValue(dataSrc),
_responseAdaptator(res), gatekeeper.
Events: component-ready (after attach + init).
OrbitComponent inherits methods from ObjectsHandler.
cherryPickedProperties
cherryPickedProperties: PropertiesPicker[] = [
{ key: "name", value: "name" },
{ key: "project", value: "projectId", cast: (r) => r["@id"] },
{ key: "project", value: "project", expand: true },
{ key: "description", value: "description" },
];Each entry: key (RDF / named source), value (component-side rename),
cast (transform callback, e.g. formatDate), expand (recursive expansion
with same cherryPickedProperties; watch out for circular deps —
_responseAdaptator is usually a better fit for those).
Helpers
src/helpers/:
datas/—dataBuilder(mock data),filterGenerator(filterObjectByX),sortui/—formatDate(Intl-based),lipsum(mock copy)utils/—requestNavigation(Router wrapper),uniq(id generator)
Localisation
Configured via @lit/localize.
Edit lit-localize.json (targetLocales), then:
npm run locale:extract # regenerate XLIFF files in locales/ from `str` / `msg` calls
npm run locale:build # build localisation bundle (run before deploy)Runtime locale switch:
window.setLocale.map((setLocale) => setLocale("fr")); // with Orbit
window.setLocale("fr"); // without OrbitOrbit integration
Components are designed to work with Orbit out of the box.
import @src/initializer;at the top of any component file that runs in Orbit prevents race conditions on Orbit boot. Skip the import if the component will be used standalone.gatekeeperinOrbitComponent.render()skips work when the current route doesn't match — significant performance lever in route-heavy apps.- Without Orbit some integrations degrade (route management, component deduplication, global localisation, conditional display).
Best practices
Standard MDN / webcomponents.org guidance applies. The boilerplate's gatekeeper + localisation are not optional polish — they're load-bearing when the component renders inside a real Hubl/Orbit app.
