@naturalcycles/internal-web-lib
v1.0.2
Published
Internal web libraries for Natural Cycles, served via CDN and published from the NCBackend3 monorepo
Readme
@naturalcycles/internal-web-lib
Internal web libraries for Natural Cycles, served via CDN
Source lives in this monorepo at packages/internal-web-lib. Published publicly to npm so jsDelivr
can serve it, but it is not open-source: it encodes our own configuration, so consumers don't have
to define their own.
One self-contained bundle per feature in bundle/, loaded as <script type="module" async>.
Consumers with their own bundler use the package exports instead.
Analytics client on a page
The stub is inline and synchronous, so nothing is lost while the bundle downloads. init() drains
it, replaying each call under the timestamp it was made at. The stub carries every method of the
real client, so a page never has to check whether it has loaded. Only track and identify can be
replayed, the rest have nothing to act on yet and warn.
<script>
{
const tooEarly = name => () => console.warn(`[analytics] ${name}() before the client loaded`)
const queue = method =>
function (...args) {
this.q.push({ method, args, ts: Date.now() })
}
globalThis.analyticsClient = {
q: [],
track: queue('track'),
identify: queue('identify'),
init: tooEarly('init'),
reset: tooEarly('reset'),
flushNow: tooEarly('flushNow'),
destroy: tooEarly('destroy'),
onEvent: () => {
tooEarly('onEvent')()
return () => {} // the unsubscribe the real onEvent returns
},
}
}
</script>
<script type="module" async>
import { AnalyticsClient } from 'https://cdn.jsdelivr.net/npm/@naturalcycles/internal-web-lib@1/bundle/analyticsClient.js'
const analyticsClient = new AnalyticsClient({
url: 'https://api.example.com/web/e',
clientId: 10, // ClientId.LovableBR, allow-listed by the destination
identity: { persistence: 'cookie', persistenceKey: 'analyticsId' },
})
analyticsClient.init()
Object.assign(globalThis, { analyticsClient }) // calls from here on go straight to the client
</script>clientId is ClientId from @naturalcycles/shared, one id per repo the client is built from, so
every embedding site needs its own. Add a member there before pointing a new site at the bundle, the
ingestion endpoint rejects ids it doesn't know. A CDN page passes the plain number, TypeScript
consumers import the enum.
Pin the jsDelivr url to a major, as above. An unpinned url follows latest, shipping a new bundle
to every embedding page the moment a release lands. A major keeps fixes and features flowing while
holding back the releases that would need the page changed.
Releases
Cut from master by ci-release-packages.yml on every commit under packages/**, driven by
dev-lib release (Conventional Commits), same as
@naturalcycles/shared. See its readme for the commit-type mapping and beta-* prereleases. The
workflow runs each package's build script, so bundle/ is rebuilt from the released commit.
Credits
The analytics client is a clean-room reimplementation whose design, persisted-identity format and default property names originate from mixpanel-browser, Copyright Mixpanel, Inc., licensed under the Apache License 2.0.
