<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rajesh Kumaravel</title>
    <description>The latest articles on DEV Community by Rajesh Kumaravel (@rajeshkumaravel).</description>
    <link>https://dev.to/rajeshkumaravel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F282100%2Fe7300331-fdc5-42a6-a3dc-2c4a1d331c37.jpeg</url>
      <title>DEV Community: Rajesh Kumaravel</title>
      <link>https://dev.to/rajeshkumaravel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rajeshkumaravel"/>
    <language>en</language>
    <item>
      <title>QueryVault: a documented home for your SQL</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Tue, 28 Jul 2026 07:04:09 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/queryvault-a-documented-home-for-your-sql-38mj</link>
      <guid>https://dev.to/rajeshkumaravel/queryvault-a-documented-home-for-your-sql-38mj</guid>
      <description>&lt;h2&gt;
  
  
  🌐 &lt;a href="https://rajeshk.dev/queryvault?utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_campaign=queryvault"&gt;Visit Query Vault&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The scariest key on any developer's keyboard is Enter, right after a query they didn't fully read...&lt;/p&gt;

&lt;p&gt;Every team that runs a serious database has a second, unmanaged database: the queries people actually use. They live in text files, chat scrollback, and one colleague's memory — and they get re-derived under pressure, against production, with auto-commit on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;QueryVault&lt;/strong&gt; is my answer, now open source under MIT: a desktop app (macOS/Windows) that makes those queries first-class — documented, searchable, shareable — and executes them behind deliberate guard rails.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/rajeshkumaravel/queryvault" rel="noopener noreferrer"&gt;https://github.com/rajeshkumaravel/queryvault&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1oj3nm32bjufoefm6t9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl1oj3nm32bjufoefm6t9.png" alt="the workbench" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The two problems in the trench coat
&lt;/h2&gt;

&lt;p&gt;The tribal-query mess is really two problems occurring at the same moment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge&lt;/strong&gt; — the query isn't documented anywhere structured. Wikis hold text, but nothing connects the doc to execution, so it drifts silently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety&lt;/strong&gt; — the tools people execute with are DBA-grade IDEs whose defaults trust the operator. That's wrong for the support engineer running someone else's &lt;code&gt;UPDATE&lt;/code&gt; at 2 a.m.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You look the query up &lt;em&gt;because&lt;/em&gt; you're about to run it somewhere that matters — so QueryVault handles both in one surface. A saved query carries a title, markdown notes, tags, and named bind parameters (&lt;code&gt;:customer_id&lt;/code&gt;, detected outside strings and comments, prompted at run time, remembered per query). Search is SQLite FTS5 across titles, SQL, notes, and tags. And execution is where the opinions live.&lt;/p&gt;

&lt;h2&gt;
  
  
  The safety model
&lt;/h2&gt;

&lt;p&gt;Four layers, each enforced as low in the stack as it can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Typed intent, scaled to risk.&lt;/strong&gt; Anything that isn't a &lt;code&gt;SELECT&lt;/code&gt; requires typing &lt;code&gt;RUN&lt;/code&gt;. On a profile tagged &lt;code&gt;prod&lt;/code&gt;, the dialog turns red and demands the &lt;em&gt;profile name&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing commits itself.&lt;/strong&gt; Writes run with &lt;code&gt;autoCommit: false&lt;/code&gt; on a long-lived per-profile connection. The status bar turns amber while changes are pending; quitting rolls back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review before commit.&lt;/strong&gt; Every uncommitted statement is inspectable — rows affected, bind values, and for in-grid cell edits the exact &lt;code&gt;old → new&lt;/code&gt;. Commit opens a totals confirmation with &lt;em&gt;Roll back instead&lt;/em&gt; beside it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-only profiles refuse writes in the main process&lt;/strong&gt; — not a disabled button in the UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm1j2z8k289d28rbihhmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm1j2z8k289d28rbihhmy.png" alt="reviewing pending changes" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The statement classifier is deliberately conservative: DML, DDL, and PL/SQL are guarded — and so is anything starting with &lt;code&gt;WITH&lt;/code&gt;, even though CTEs are usually reads. Proving a CTE read-only across dialects is exactly the cleverness that eventually produces a false negative on production. Four extra keystrokes vs. an incident: easy trade.&lt;/p&gt;

&lt;p&gt;One Oracle-specific wrinkle, stated honestly: DDL commits implicitly on Oracle — no client can prevent it — so the pending-transaction model tracks DML only, and DDL is caught at the confirmation step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture: a security decision that organizes the code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqtkne47sua9e5w40kj5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqtkne47sua9e5w40kj5c.png" alt="Architecture" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three boundaries do the work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The renderer is untrusted.&lt;/strong&gt; &lt;code&gt;sandbox: true&lt;/code&gt;, &lt;code&gt;contextIsolation: true&lt;/code&gt;, &lt;code&gt;nodeIntegration: false&lt;/code&gt;. Its entire capability surface is one function — &lt;code&gt;window.api.invoke(channel, …)&lt;/code&gt; — typed end-to-end by a single shared IPC contract (&lt;code&gt;src/shared/ipc.ts&lt;/code&gt;). New capability = new channel in that map + a handler in the main process. There is no second path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All database work lives in the main process&lt;/strong&gt; behind a &lt;code&gt;DatabaseAdapter&lt;/code&gt; interface with two implementations: &lt;code&gt;OracleAdapter&lt;/code&gt; (node-oracledb &lt;strong&gt;Thin mode&lt;/strong&gt; — pure TCP, no Oracle Instant Client to install) and &lt;code&gt;DemoAdapter&lt;/code&gt; (the bundled SQLite demo dataset: 250k orders, 1k customers, 5k tickets, so every screen works with zero setup — and contributors never need Oracle).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety enforcement sits below the UI&lt;/strong&gt;, so no renderer bug can bypass it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56pzwzwov246u3p3ijf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56pzwzwov246u3p3ijf7.png" alt="Arch" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Things deliberately not built
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No cloud/sync.&lt;/strong&gt; Sharing is explicit JSON export/import (titles, SQL, notes, tags — never passwords or bind values). A sync backend means accounts, a server attack surface, and a governance conversation; local-first keeps the threat model auditable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No plugin runtime.&lt;/strong&gt; Extensibility is the compile-time &lt;code&gt;DatabaseAdapter&lt;/code&gt; interface. A plugin system inside an app holding DB credentials is a privilege-escalation surface; a PR implementing an interface is a code review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No ORM.&lt;/strong&gt; The app's own store is hand-written SQL on better-sqlite3 (synchronous, in the main process — which removes a class of async-consistency issues in transaction bookkeeping).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No auto-updater.&lt;/strong&gt; That's a network call and a code-execution path. Updates are new installers on GitHub Releases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The verifiable parts of the security posture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network:&lt;/strong&gt; no outbound requests except to your configured Oracle DBs. Enforced by CSP &lt;code&gt;default-src 'self'&lt;/code&gt; in &lt;code&gt;src/renderer/index.html&lt;/code&gt; (blocks fetch/XHR/WebSocket/remote images — a tracking pixel pasted into a note can't load) and by bundling Monaco locally instead of a CDN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credentials:&lt;/strong&gt; Electron &lt;code&gt;safeStorage&lt;/code&gt; (macOS Keychain / Windows DPAPI). Encrypted blob on disk; plaintext never reaches the renderer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply chain:&lt;/strong&gt; two runtime dependencies — &lt;code&gt;better-sqlite3&lt;/code&gt; and &lt;code&gt;oracledb&lt;/code&gt;. Everything else is build-time and compiled in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disclosure:&lt;/strong&gt; &lt;code&gt;SECURITY.md&lt;/code&gt; routes reports through GitHub private advisories, and explicitly classifies &lt;em&gt;any&lt;/em&gt; third-party network contact as a vulnerability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the disclosed gap: &lt;strong&gt;builds are unsigned&lt;/strong&gt; for now — right-click → Open on macOS, dismiss SmartScreen on Windows, or build from source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance posture (no invented numbers)
&lt;/h2&gt;

&lt;p&gt;No published benchmarks — the story is structural: virtualized grid, rows streamed in 5,000-row batches, a hard 50,000-row display cap so renderer memory is bounded, CSV export that streams &lt;em&gt;all&lt;/em&gt; rows to disk regardless of the cap, FTS5 for search. The ~23-scenario Playwright suite exercises all of it against the 250k-row demo dataset — and the README's screenshots are generated by that suite, so the docs can't drift from the real UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvawvg4yp8h3pkgx2yulr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvawvg4yp8h3pkgx2yulr.gif" alt="walkthrough" width="760" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations &amp;amp; roadmap
&lt;/h2&gt;

&lt;p&gt;Oracle-only today; unsigned builds; macOS is Apple-silicon only; no TCPS/wallet yet; cell editing is intentionally narrow (single-table SELECTs, edit refused unless exactly one row matches); no result filtering or snapshot diffing yet.&lt;/p&gt;

&lt;p&gt;Roadmap: signing/notarization, TCPS/wallet, Postgres and SQL Server adapters, snapshot diffing, grid filtering, Linux packaging.&lt;/p&gt;




&lt;p&gt;If this matches a problem you have: it's free, MIT, and works out of the box on demo data. A star on ⭐ (&lt;a href="https://github.com/rajeshkumaravel/queryvault" rel="noopener noreferrer"&gt;https://github.com/rajeshkumaravel/queryvault&lt;/a&gt;) helps others find it; &lt;a href="https://github.com/rajeshkumaravel/queryvault/issues" rel="noopener noreferrer"&gt;issues&lt;/a&gt; and &lt;a href="https://github.com/rajeshkumaravel/queryvault/discussions" rel="noopener noreferrer"&gt;discussions&lt;/a&gt; are open, and PRs are warmly reviewed — a new &lt;code&gt;DatabaseAdapter&lt;/code&gt; would be a genuinely great first contribution. Tell me where it breaks.&lt;/p&gt;




&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article useful, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>sql</category>
      <category>opensource</category>
      <category>electron</category>
      <category>database</category>
    </item>
    <item>
      <title>Kafka Offset Harbor: a local-first desktop window into Apache Kafka</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Tue, 28 Jul 2026 06:48:14 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/kafka-offset-harbor-a-local-first-desktop-window-into-apache-kafka-2dme</link>
      <guid>https://dev.to/rajeshkumaravel/kafka-offset-harbor-a-local-first-desktop-window-into-apache-kafka-2dme</guid>
      <description>&lt;h2&gt;
  
  
  🌐 &lt;a href="https://rajeshk.dev/kafka-harbor?utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_campaign=kafkaoffsetharbor"&gt;Visit Kafka Offset Harbor&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Kafka is the backbone of event-driven systems, but its data is invisible by design: there's no built-in window onto what's actually flowing through a topic. Answering &lt;em&gt;"did this message arrive?"&lt;/em&gt;, &lt;em&gt;"why is this consumer behind?"&lt;/em&gt;, or &lt;em&gt;"can we replay from Tuesday?"&lt;/em&gt; usually means assembling CLI flags from memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kafka Offset Harbor&lt;/strong&gt; is my answer: a free, MIT-licensed desktop app (macOS, Windows, Linux-from-source) for browsing topics and messages, watching consumer lag, resetting offsets, and administering topics — built &lt;em&gt;local-first&lt;/em&gt;, so your broker credentials never leave your machine.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/rajeshkumaravel/kafka-offset-harbor" rel="noopener noreferrer"&gt;https://github.com/rajeshkumaravel/kafka-offset-harbor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmyx1l7fzyr777oluchy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmyx1l7fzyr777oluchy.png" alt="Browsing messages with the payload inspector" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the existing options?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI tooling&lt;/strong&gt; is complete but hostile to exploration — right for automation, wrong for "show me what's in this topic."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted web UIs&lt;/strong&gt; invert the trust model: you deploy a service, hand it broker credentials, put it behind auth, and patch it forever. Reasonable for a platform team; overkill and a new attack surface for one engineer poking at staging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commercial desktop tools&lt;/strong&gt; proved the form factor, but closed source is a hard sell in the security-reviewed environments where a Kafka GUI matters most.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gap: a desktop tool whose security story is &lt;em&gt;inspectable&lt;/em&gt; — where "credentials never leave your machine" is a property you verify in source, not a promise in a policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explore&lt;/strong&gt; — brokers (controller flagged), topics with partition/replication counts, consumer groups, all in one filterable tree; multiple saved connections with dev/stage/prod colour badges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read&lt;/strong&gt; — fetch from newest/oldest/a specific offset/a timestamp, per partition or all; a virtualized grid smooth at thousands of rows; &lt;code&gt;contains&lt;/code&gt;/&lt;code&gt;regex&lt;/code&gt;/&lt;code&gt;JSONPath&lt;/code&gt; filters across key, value, headers; payloads in the Monaco editor (pretty JSON/XML, raw, hex); tombstones, sizes and headers surfaced; JSON/CSV export.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix consumers&lt;/strong&gt; — colour-coded per-partition lag, group state/members/assignments; offset resets to earliest/latest/offset/timestamp, guarded to idle groups only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Produce &amp;amp; administer&lt;/strong&gt; — keys, tombstones, custom headers, repeat-N test data, JSON-array import; topic create/delete, partition expansion, config editing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo cluster&lt;/strong&gt; — a full in-memory cluster (topics, messages, lagging groups) built in. Every feature works with zero setup and zero network access, because it's the real UI on a fake backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxf2dt84eg6hl3w2grvst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxf2dt84eg6hl3w2grvst.png" alt="Consumer group lag view" width="800" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture: the process boundary is the security boundary
&lt;/h2&gt;

&lt;p&gt;Electron gives you a privileged Node.js &lt;strong&gt;main process&lt;/strong&gt; and a Chromium &lt;strong&gt;renderer&lt;/strong&gt;. Harbor's rule: everything sensitive — Kafka networking, credential decryption, disk persistence — lives only in main. The React renderer is untrusted display logic: it never sees a password and never opens a socket.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7jd1rkdlag90q4tftco1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7jd1rkdlag90q4tftco1.png" alt="Process" width="799" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The renderer and main talk through &lt;strong&gt;one&lt;/strong&gt; typed &lt;code&gt;invoke&lt;/code&gt; bridge, against a contract declared in &lt;code&gt;src/shared/ipc.ts&lt;/code&gt;. Every call returns a structured result envelope — success or typed error — so broker failures surface as values, not cross-process exceptions. Because CI type-checks both processes against the same contract, the app's entire privileged surface is readable in a single file, and extending it without declaring shapes is a compile error.&lt;/p&gt;

&lt;h3&gt;
  
  
  The adapter seam
&lt;/h3&gt;

&lt;p&gt;Main reaches Kafka only through a &lt;code&gt;ClusterAdapter&lt;/code&gt; interface with two implementations: &lt;code&gt;KafkaJsAdapter&lt;/code&gt; (real clusters via kafkajs — PLAINTEXT, SSL/TLS, SASL PLAIN/SCRAM, AWS MSK IAM) and &lt;code&gt;DemoAdapter&lt;/code&gt; (the in-memory demo cluster). The UI can't tell them apart — which is why demo mode is a first-class feature, UI development needs no broker, and a future backend is a third implementation rather than a rewrite.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmrvpxsytuwpd90d41buo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmrvpxsytuwpd90d41buo.png" alt="Process" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fetches are &lt;strong&gt;bounded&lt;/strong&gt; (a window relative to newest/oldest/offset/timestamp — never an unbounded tail), and rendering is &lt;strong&gt;virtualized&lt;/strong&gt; (TanStack Virtual), so cost tracks the viewport, not the topic size. No formal benchmarks yet — that's stated honestly, and the posture is structural.&lt;/p&gt;

&lt;h3&gt;
  
  
  The trade-offs, defended
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Electron&lt;/strong&gt; costs a Chromium runtime's memory. It buys one codebase with native installers on two platforms, the Monaco editor as a payload inspector (half the tool's value), and &lt;code&gt;safeStorage&lt;/code&gt; — direct OS-keychain integration (Keychain/DPAPI/libsecret) with no custom crypto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;kafkajs over librdkafka bindings&lt;/strong&gt;: the C client is faster, but a GUI's bottleneck is the human. Pure JS means the Kafka path needs no compile toolchain anywhere, keeping the parallel macOS/Windows CI build simple and the contribution barrier low. The only native module is better-sqlite3 (the connection store), isolated via the standard unpacked-module config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deliberately absent&lt;/strong&gt;: telemetry, analytics, crash reporting, auto-update pings, cloud sync. "No phoning home" is only credible if it's total. Even the welcome-screen greeting comes from the system clock, because the obvious implementation (a weather API) ships your IP to a third party.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security posture, verifiably
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Credentials&lt;/strong&gt;: encrypted via OS keychain, stored in local SQLite, decrypted only in main at connect time. The IPC contract has no call that returns a secret. MSK IAM stores no secret at all — short-lived tokens minted from your local AWS credential chain via &lt;code&gt;aws-msk-iam-sasl-signer-js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network&lt;/strong&gt;: outbound connections go to your configured brokers, full stop (plus AWS STS iff you use MSK IAM). Three runtime dependencies; none of the app source makes HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply chain&lt;/strong&gt;: better-sqlite3's install-time binary downloader (&lt;code&gt;prebuild-install&lt;/code&gt; + its HTTP/tar chain) is explicitly excluded from the packaged app — commented and auditable in &lt;code&gt;electron-builder.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution&lt;/strong&gt;: public GitHub Actions build (&lt;code&gt;.github/workflows/release.yml&lt;/code&gt;) → tagged Releases. Builds are currently &lt;strong&gt;unsigned&lt;/strong&gt; — disclosed, not hidden; signing is on the roadmap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails&lt;/strong&gt;: offset resets refuse non-idle groups with an explanation; full local reset requires typing &lt;code&gt;CONFIRM&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Grab an installer from &lt;a href="https://github.com/rajeshkumaravel/kafka-offset-harbor/releases" rel="noopener noreferrer"&gt;Releases&lt;/a&gt; and hit &lt;strong&gt;Explore the demo cluster&lt;/strong&gt; — no broker needed. Against a real one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/rajeshkumaravel/kafka-offset-harbor.git
&lt;span class="nb"&gt;cd &lt;/span&gt;kafka-offset-harbor &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev

&lt;span class="c"&gt;# optional local broker with seeded topics + a lagging consumer group&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; koh-kafka:local docker/
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; koh-kafka &lt;span class="nt"&gt;-p&lt;/span&gt; 9092:9092 koh-kafka:local
./docker/seed.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations &amp;amp; roadmap
&lt;/h2&gt;

&lt;p&gt;No Schema Registry/Avro decoding yet (binary payloads show raw/hex); Linux installers pending; builds unsigned pending certificates; MSK IAM uses the default AWS credential chain (no per-connection profile picker yet); explorer, not monitor — nothing pages you.&lt;/p&gt;

&lt;p&gt;Roadmap, roughly in order: Schema Registry/Avro, Linux packaging, code signing, saved queries, measured performance baselines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get involved
&lt;/h2&gt;

&lt;p&gt;It's MIT and contributions are genuinely wanted — ⭐ &lt;a href="https://github.com/rajeshkumaravel/kafka-offset-harbor" rel="noopener noreferrer"&gt;star the repo&lt;/a&gt;, &lt;a href="https://github.com/rajeshkumaravel/kafka-offset-harbor/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;, argue with a trade-off in discussions, or pick up a roadmap item (Schema Registry is the big one). What do you use to look inside Kafka today?&lt;/p&gt;




&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article useful, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>opensource</category>
      <category>electron</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I Built a Browser So My Debugging Tools Could Stop Being Extensions</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Tue, 28 Jul 2026 06:27:21 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/i-built-a-browser-so-my-debugging-tools-could-stop-being-extensions-4pm2</link>
      <guid>https://dev.to/rajeshkumaravel/i-built-a-browser-so-my-debugging-tools-could-stop-being-extensions-4pm2</guid>
      <description>&lt;h2&gt;
  
  
  🌐 &lt;a href="https://rajeshk.dev/sheaf-browser?utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_campaign=sheafbrowser"&gt;Visit Sheaf Browser&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Every web developer's debugging toolchain is four browser extensions in a trench coat: modify headers, format JSON, edit cookies, mock requests. Each install wants access to every site you visit, and Manifest V3 has been quietly narrowing what the interesting ones are allowed to do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rajeshkumaravel/sheaf-browser" rel="noopener noreferrer"&gt;Sheaf Browser&lt;/a&gt; takes a different route: &lt;strong&gt;move the tools below the extension sandbox entirely.&lt;/strong&gt; It's a small open-source browser (Electron, MIT) where the four tools are native plugins in the browser's main process — the layer that actually owns the network.&lt;/p&gt;

&lt;p&gt;Here's the what, why, who, when, where, and how — plus the security model, which is the real story.&lt;/p&gt;

&lt;h2&gt;
  
  
  What
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2qjyl7ruy15m11mby1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd2qjyl7ruy15m11mby1l.png" alt="Letterhead panel with URL-scoped header rules" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Four tools, first-class, written from scratch:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Letterhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Add / replace / remove &lt;strong&gt;request and response&lt;/strong&gt; headers; substring, glob (&lt;code&gt;example.com/*&lt;/code&gt;) or regex scoping; profiles swap rule sets; the icon pulses while a rule is live on the current page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Folio&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Every JSON response becomes a searchable, collapsible tree with copy-path on any key; &lt;code&gt;sheaf://folio&lt;/code&gt; is a paste-anything scratchpad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Imprint&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read and edit cookies &lt;strong&gt;including &lt;code&gt;HttpOnly&lt;/code&gt;&lt;/strong&gt;, plus localStorage / sessionStorage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mailroom&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stub, redirect, block or delay any request; record the session; &lt;strong&gt;export HAR&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Plus the browser around them: tabs, private windows, ranked omnibox, bookmarks, downloads, find-in-page, docked resizable DevTools, and device simulation (viewport + DPR + UA) that works &lt;em&gt;while DevTools is open&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuh5f6ktzzm3ynllbvmqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuh5f6ktzzm3ynllbvmqe.png" alt="Docked DevTools and device simulation" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;Three facts, one conclusion:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MV3's &lt;code&gt;declarativeNetRequest&lt;/code&gt;&lt;/strong&gt; is a static rule table with hard limits — designed so ad blockers can be audited, and consequently so debugging tools can't really exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;HttpOnly&lt;/code&gt; cookies&lt;/strong&gt; are invisible to extension JavaScript by definition — but not to the browser itself. The flag restricts page JS, not the embedder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electron doesn't implement &lt;code&gt;declarativeNetRequest&lt;/code&gt; at all.&lt;/strong&gt; An MV3 header extension in any Electron app installs, renders, and silently does nothing — so bundling existing extensions was never an option.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you already keep a second browser for dev work (you do), the conclusion follows: build the second browser properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who
&lt;/h2&gt;

&lt;p&gt;For: developers, QA, and support engineers debugging web apps daily; security teams that prefer one inspectable MIT codebase over four third-party extensions with total site access.&lt;/p&gt;

&lt;p&gt;Not for: daily driving. No Widevine, no sync, no password manager, no Web Store — deliberate non-goals. Mixing your personal sessions back into the dev browser would recreate the problem it solves.&lt;/p&gt;

&lt;h2&gt;
  
  
  When
&lt;/h2&gt;

&lt;p&gt;Reach for it when you need to: send an &lt;code&gt;Authorization&lt;/code&gt; or feature-flag header to one origin; read an API response as a tree; edit an &lt;code&gt;HttpOnly&lt;/code&gt; session cookie in place; stub a flaky endpoint or delay a request to reproduce a race; export a HAR for a ticket; test a mobile viewport with DevTools open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where — one layer down
&lt;/h2&gt;

&lt;p&gt;Sheaf browser capabilities all come from a single placement decision: the tools run in the browser's &lt;strong&gt;main process&lt;/strong&gt;, below the extension sandbox. &lt;code&gt;session.webRequest&lt;/code&gt; sees every request &lt;em&gt;and response&lt;/em&gt; with no rule ceilings and no permission grants. The same asymmetry repeats everywhere — hard or impossible as an extension, straightforward as the embedder.&lt;/p&gt;

&lt;h2&gt;
  
  
  How
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TB
    subgraph main["Main process"]
        TM["TabManager"]
        PH["PluginHost"]
        SQL["SQLite repos"]
        PROT["sheaf:// &amp;amp; sheaf-stub://"]
    end
    subgraph window["One BrowserWindow"]
        CHROME["Chrome renderer (React)"]
        TAB["Tab = WebContentsView, one per tab"]
        DT["DevTools view"]
        SPL["Splitter view"]
    end
    OVL["Omnibox overlay window"]
    CHROME -- IPC --&amp;gt; TM
    TM --&amp;gt; TAB &amp;amp; DT &amp;amp; SPL
    PH -- "session.webRequest" --&amp;gt; TAB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The compositing constraint.&lt;/strong&gt; Each tab is a &lt;code&gt;WebContentsView&lt;/code&gt; — a native Chromium view composited &lt;em&gt;over&lt;/em&gt; the React-rendered chrome. Native views ignore DOM z-index, so nothing in the DOM can appear above page content — ever. Every overlay is therefore native too: the omnibox dropdown is a separate frameless window, DevTools is its own docked view, and the drag-to-resize splitter is a third thin view. Find your platform's compositing boundary in week one; it designs your component architecture for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The single-listener rule.&lt;/strong&gt; Electron permits one &lt;code&gt;webRequest&lt;/code&gt; listener per event per session — a second registration silently replaces the first. All plugins therefore register typed handlers with one &lt;code&gt;PluginHost&lt;/code&gt;, which owns the real listeners: header handlers fold over the header map in order, the first mock rule to answer a request wins, and the host attaches per session so private windows get the same rules over a throwaway in-memory session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mocking without a proxy.&lt;/strong&gt; Stubs are served from an internal &lt;code&gt;sheaf-stub://&lt;/code&gt; protocol; block/delay/redirect act directly in the pipeline; a completion-time recorder exports HAR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sequenceDiagram
    participant Page
    participant PH as PluginHost
    participant SP as sheaf-stub://
    Page-&amp;gt;&amp;gt;PH: GET /api/flaky-endpoint
    PH-&amp;gt;&amp;gt;PH: mock rule matches (stub)
    PH--&amp;gt;&amp;gt;Page: redirect → sheaf-stub://…
    Page-&amp;gt;&amp;gt;SP: fetch
    SP--&amp;gt;&amp;gt;Page: user-defined status / headers / body
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Shared rule matching.&lt;/strong&gt; Rule types and the URL matcher are one shared module compiled into both the UI and the network layer — the "rule is live here" pulse uses the same matcher that enforces the rule, so the interface can't lie about what the pipeline will do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;The part that justifies the whole project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permission model, deleted.&lt;/strong&gt; No "access to all sites" grants — the tools are the browser. Runtime dependency tree: &lt;strong&gt;two MIT packages&lt;/strong&gt; (&lt;code&gt;better-sqlite3&lt;/code&gt;, &lt;code&gt;adm-zip&lt;/code&gt;); neither touches the network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation.&lt;/strong&gt; One renderer process per tab; context isolation on; no Node in page contexts; typed preload-mediated IPC; &lt;code&gt;javascript:&lt;/code&gt; URLs in the omnibox are never executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero own traffic — verified.&lt;/strong&gt; No telemetry, no update pings, no third-party APIs. Favicons are captured locally at bookmark time; the new-tab greeting is clock-driven; spellcheck is macOS-native only. &lt;code&gt;npm run verify&lt;/code&gt; launches the &lt;strong&gt;built&lt;/strong&gt; app, records every request across a full scripted feature pass, and fails on anything unexpected — after first proving the recorder captures real traffic against a local echo server. Observers must earn trust before their silence means anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance.&lt;/strong&gt; A clean-room rule in CONTRIBUTING keeps GPL/AGPL implementations away from this MIT tree — contributors don't read competing sources while building a feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution honesty.&lt;/strong&gt; Unsigned builds, with the Gatekeeper/SmartScreen friction documented per platform; private vulnerability reporting via SECURITY.md; Electron's Chromium CVE stream treated as a standing upgrade obligation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits, stated plainly
&lt;/h2&gt;

&lt;p&gt;No DRM, no sync, partial Chrome-extension compatibility (DevTools-panel extensions mostly work; MV3 network extensions can't work in any Electron app), and throttling/touch emulation blocked on a CDP-vs-DevTools conflict — all on the record in the README.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Grab a build from Releases, or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/rajeshkumaravel/sheaf-browser
&lt;span class="nb"&gt;cd &lt;/span&gt;sheaf-browser &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm run verify&lt;/code&gt; runs the same verification suite CI runs — including the network-silence check.&lt;/p&gt;




&lt;p&gt;If the architecture interests you, ⭐ &lt;strong&gt;star the repo&lt;/strong&gt; —  &lt;strong&gt;&lt;a href="https://github.com/rajeshkumaravel/sheaf-browser" rel="noopener noreferrer"&gt;https://github.com/rajeshkumaravel/sheaf-browser&lt;/a&gt;&lt;/strong&gt;. &lt;strong&gt;Issues&lt;/strong&gt; for header cases and rule syntax that annoy you, &lt;strong&gt;Discussions&lt;/strong&gt; for arguing with a trade-off, &lt;strong&gt;PRs&lt;/strong&gt; for the open problems — JWT decoder plugin, CDP throttling, shareable team rule sets. &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; (clean-room rule included) has the details.&lt;/p&gt;

&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article useful, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>electron</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Demystifying NPM and NPX: A Dive into Package Management</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Tue, 13 Feb 2024 10:57:26 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/demystifying-npm-and-npx-a-dive-into-package-management-5c92</link>
      <guid>https://dev.to/rajeshkumaravel/demystifying-npm-and-npx-a-dive-into-package-management-5c92</guid>
      <description>&lt;h2&gt;
  
  
  Demystifying NPM and NPX: A Dive into Package Management
&lt;/h2&gt;

&lt;p&gt;In the ever-evolving landscape of web development, efficient package management has become an integral part of the workflow. Among the tools that have significantly shaped this ecosystem, npm (Node Package Manager) stands out as a key player. To complement npm, a tool called npx was introduced, adding a layer of versatility to the package management process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Birth of npx
&lt;/h2&gt;

&lt;p&gt;As projects and their dependencies grew in complexity, developers encountered challenges in managing and executing packages seamlessly. npm addressed these issues by providing a centralized repository for JavaScript libraries and a reliable way to install, manage, and share packages. However, as projects expanded, the need for an improved execution environment became evident.&lt;/p&gt;

&lt;p&gt;Enter npx, a tool bundled with npm (versions 5.2.0 and higher) to tackle the intricacies of package execution. Prior to npx, executing binaries from packages installed via npm required adding those binaries to the system's PATH. This approach had its drawbacks, including potential conflicts and difficulties in version management.&lt;/p&gt;

&lt;p&gt;With npx, the execution of packages is streamlined. It allows developers to run binaries from packages without the need for a global install, making it easier to manage project-specific dependencies. Additionally, npx enables the execution of binaries from packages that are not globally installed, resolving the issue of having to specify the full path to the executable.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Closer Look at npm
&lt;/h2&gt;

&lt;p&gt;npm, the backbone of the Node.js package ecosystem, is used to install, manage, and share packages of code. It facilitates the discovery and distribution of packages, making it an essential tool for developers building applications with JavaScript, whether for the front end or back end.&lt;/p&gt;

&lt;p&gt;The npm registry is a vast collection of open-source packages, providing developers with a rich set of tools, libraries, and frameworks to enhance their projects. Installing a package is as simple as running the command &lt;code&gt;npm install &amp;lt;package-name&amp;gt;&lt;/code&gt;, and npm takes care of fetching and installing the specified package along with its dependencies.&lt;/p&gt;

&lt;p&gt;npm not only excels in package installation but also facilitates version management. Developers can specify the desired version of a package in the project's &lt;code&gt;package.json&lt;/code&gt; file, ensuring consistency across different environments and team members.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unveiling npx's Power
&lt;/h2&gt;

&lt;p&gt;While npm handles package installation, npx focuses on package execution. With npx, developers can run binaries from packages without installing them globally or specifying their full path. This dynamic execution environment enhances the flexibility and portability of JavaScript applications.&lt;/p&gt;

&lt;p&gt;One of the noteworthy features of npx is its ability to run the latest version of a package, even if it's not installed globally. For example, running &lt;code&gt;npx create-react-app my-app&lt;/code&gt; initiates a new React application using the latest version of Create React App without the need to install it globally beforehand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Running Commands from Packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eslint &lt;span class="nt"&gt;--init&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, npx is used to initialize ESLint in a project without the need for a global ESLint installation. The command fetches the latest version of ESLint and executes it with the &lt;code&gt;--init&lt;/code&gt; flag, guiding the user through the setup process.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Executing One-off Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;npx serve&lt;/code&gt; runs a local development server using the 'serve' package without the necessity of installing 'serve' globally. This is particularly useful for ad-hoc tasks and quick development setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Trying Out New Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-new-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a new React application using Create React App is a common scenario. With npx, developers can try out the latest version of Create React App without installing it globally. This keeps the project's dependencies neatly scoped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;npm and npx, working hand in hand, provide a comprehensive solution for managing and executing JavaScript packages in modern development workflows. npm excels in package installation and version management, while npx adds a layer of convenience by facilitating the execution of packages without the need for global installs.&lt;/p&gt;

&lt;p&gt;As the JavaScript ecosystem continues to evolve, these tools remain crucial for developers seeking efficient and scalable package management solutions. Whether you're a seasoned developer or just starting your journey, understanding npm and npx is fundamental to harnessing the full potential of the JavaScript ecosystem.&lt;/p&gt;




&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article a useful primer for getting started with npx, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>npx</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing Github Dashboard: Open Source Project for Analytics and Data Visualisation</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Wed, 28 Jun 2023 06:00:51 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/introducing-github-dashboard-open-source-project-for-analytics-and-data-visualisation-1b1g</link>
      <guid>https://dev.to/rajeshkumaravel/introducing-github-dashboard-open-source-project-for-analytics-and-data-visualisation-1b1g</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Today, I am thrilled to announce the release of GitHub Dashboard, an open source project built using Node JS, Angular, Vercel, and Nx. This project aims to provide a comprehensive and intuitive way to analyse and visualise data from GitHub repositories. With OAuth login for authentication, GitHub Dashboard enables users to fetch repository discussions and pull requests data, empowering them to gain valuable insights through high-level metrics, cards, and graphs&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication and Data Retrieval
&lt;/h2&gt;

&lt;p&gt;GitHub Dashboard leverages OAuth login for secure authentication, ensuring that only authorised users will be allowed to access the platform. By granting necessary permissions, users will be able to fetch discussions and pull requests data from public repositories. This feature allows developers, project managers, and data enthusiasts to explore and analyse repository activities effortlessly&lt;/p&gt;

&lt;h2&gt;
  
  
  Analytics and Data Visualisation
&lt;/h2&gt;

&lt;p&gt;One of the key highlights of GitHub Dashboard is its powerful analytics and data visualisation capabilities. The dashboard presents a user-friendly interface, displaying insightful cards and interactive graphs that provide a bird's-eye view of repository metrics. With just a glance, users can quickly assess crucial statistics such as the count of discussions, pull requests, contributors, and more. These visual representations make it easier to grasp the repository's overall health and engagement&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibility and Customisation
&lt;/h2&gt;

&lt;p&gt;GitHub Dashboard is designed to be highly flexible and customisable. Users can seamlessly navigate through different public repositories and switch between various projects of interest&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;GitHub Dashboard is built using a powerful combination of technologies, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js: A server-side JavaScript runtime environment, providing a scalable and efficient backend&lt;/li&gt;
&lt;li&gt;Angular: A popular frontend framework for building robust and interactive web applications&lt;/li&gt;
&lt;li&gt;Vercel: A cloud platform for static sites and serverless functions, ensuring reliable hosting and deployment&lt;/li&gt;
&lt;li&gt;Nx: A powerful extensible development framework for building monorepo-based applications, improving code sharing and maintainability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Acknowledgments
&lt;/h2&gt;

&lt;p&gt;Completing the GitHub Dashboard project wouldn't have been possible without the support and contributions of my amazing friends. Their dedication, expertise, and guidance have been instrumental in bringing this project to life.&lt;br&gt;
I want to express my heartfelt gratitude to Mathew Jose Pallan, Harshit T Rao, &lt;a href="https://github.com/darshannagesh"&gt;Darshan Nagesh&lt;/a&gt; and &lt;a href="https://github.com/Shreevas-Karanth"&gt;Shreevas Karanth&lt;/a&gt; for their valuable input, feedback, and encouragement throughout this journey&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With GitHub Dashboard, analysing and visualising data from public repositories has been made much easier and simpler. Be it a developer or a project manager or a data enthusiast, this open source project provides a powerful tool to gain actionable insights and understand the health and engagement of GitHub repositories.&lt;/p&gt;

&lt;p&gt;Thank you for your support, and I look forward to your feedback&lt;/p&gt;

&lt;p&gt;Explore &lt;a href="https://openvizhub.vercel.app"&gt;Github Dashboard&lt;/a&gt;...&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;/p&gt;

&lt;p&gt;RK&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>angular</category>
    </item>
    <item>
      <title>Angular Simple Slick without dependencies</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Tue, 28 Feb 2023 05:56:25 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/angular-simple-slick-without-dependencies-2e57</link>
      <guid>https://dev.to/rajeshkumaravel/angular-simple-slick-without-dependencies-2e57</guid>
      <description>&lt;h2&gt;
  
  
  Before we begin…
&lt;/h2&gt;

&lt;p&gt;Let us understand why angular plugins developed using jQuery raises concern about compatibility and integration.&lt;/p&gt;

&lt;p&gt;jQuery and Angular are both JavaScript libraries that provide different approaches to building web applications, and as such, they can be hostile to each other when used together. Some of the reasons why jQuery is hostile with Angular include&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conflicting syntax&lt;/strong&gt;&lt;br&gt;
jQuery and Angular have different syntaxes and ways of doing things, which can lead to conflicts and errors. For example, Angular uses directives and data binding to update the DOM, while jQuery uses selectors and methods&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance overhead&lt;/strong&gt;&lt;br&gt;
Using jQuery along with Angular can result in performance overhead, as both libraries will be loaded and executed. This can impact the speed and efficiency of your application&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Incompatibility issues&lt;/strong&gt;&lt;br&gt;
jQuery was not designed to work with Angular, and using the two together can result in incompatibility issues. This can cause errors and unexpected behaviour, making it difficult to diagnose and fix problems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Maintenance complexity&lt;/strong&gt;&lt;br&gt;
Using both libraries together can lead to code that is more complex and difficult to maintain. This can make it harder to make changes and updates to your codebase&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Duplicate functionality&lt;/strong&gt;&lt;br&gt;
Many of the features and functionality provided by jQuery are already available in Angular. Using both libraries can result in duplicate functionality, which can increase the size and complexity of your codebase&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Different approaches to DOM manipulation&lt;/strong&gt;&lt;br&gt;
jQuery is primarily a DOM manipulation library, while Angular provides a full-featured framework for building web applications. The different approaches to DOM manipulation can result in conflicts and inconsistencies when using both libraries together&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr9ekek8va99wbmienir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdr9ekek8va99wbmienir.gif" alt="code_issue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall, while it is possible to use jQuery with Angular, it is generally not recommended due to the conflicts and challenges that can arise. It's generally best to stick with Angular's built-in capabilities and avoid using jQuery unless absolutely necessary&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Angular Simple Slick&lt;/strong&gt; / &lt;code&gt;ngxslick&lt;/code&gt; is a lightweight and very complete Angular library for rendering simple slideshow of elements without any 3rd party dependencies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports dots and arrow navigation&lt;/li&gt;
&lt;li&gt;Custom styling&lt;/li&gt;
&lt;li&gt;Multi row support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://ngx-carousel-slick-demo.vercel.app" rel="noopener noreferrer"&gt;Demo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/ngx-simple-slick" rel="noopener noreferrer"&gt;NPM Plugin&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Installation&lt;/li&gt;
&lt;li&gt;Import in Angular&lt;/li&gt;
&lt;li&gt;Options&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;$ npm i ngx-simple-slick --save&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Import in Angular&lt;br&gt;
&lt;/h3&gt;
&lt;br&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;span class="gp"&gt;import { BrowserModule } from '@angular/platform-browser';&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;import { NgModule } from '@angular/core';&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;import { NgxSlickModule } from 'ngx-simple-slick';&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="go"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;import { AppComponent } from './app.component';&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="go"&gt;&lt;br&gt;
@NgModule({&lt;br&gt;
  declarations: [&lt;br&gt;
    AppComponent&lt;br&gt;
  ],&lt;br&gt;
  imports: [&lt;br&gt;
    BrowserModule,&lt;br&gt;
    NgxSlickModule&lt;br&gt;
  ],&lt;br&gt;
  providers: [ ],&lt;br&gt;
  bootstrap: [ AppComponent ]&lt;br&gt;
})&lt;br&gt;
export class AppModule { }

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;p&gt;// demo.component.ts&lt;br&gt;
export class DemoComponent implements OnInit {&lt;br&gt;
&lt;/p&gt;&lt;/span&gt;&lt;span class="gp"&gt;  dataObj = new Array(10);&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="go"&gt;  constructor() { }

&lt;p&gt;ngOnInit(): void {&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;

&lt;p&gt;// demo.component.html&lt;br&gt;
&lt;/p&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;lt;ngxslick [dots]=true [loadStatus]="'done'"&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;   &amp;lt;ngxslick [dots]=true [loadStatus]="'done'"&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;      &amp;lt;ng-container *ngFor="let card of dataObj;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;let &lt;/span&gt;i &lt;span class="o"&gt;=&lt;/span&gt; index&lt;span class="s2"&gt;"&amp;gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;        &amp;lt;div class="card"&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;          &amp;lt;figure&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;            &amp;lt;img src="&lt;a href="https://via.placeholder.com/150x150?text=NG%20Slick" rel="noopener noreferrer"&gt;https://via.placeholder.com/150x150?text=NG%20Slick&lt;/a&gt;" /&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;            &amp;lt;figcaption&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;Card {{ i + 1 }}&amp;lt;/figcaption&amp;gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;          &amp;lt;/figure&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;        &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;      &amp;lt;/ng-container&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;    &amp;lt;/ngxslick&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="gp"&gt;&amp;lt;/ngxslick&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="go"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Options&lt;br&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Values&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;loadStatus&lt;/td&gt;
&lt;td&gt;@Input String&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Optional&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;done / fetching&lt;/td&gt;
&lt;td&gt;Status whether data loading is complete or fetching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dots&lt;/td&gt;
&lt;td&gt;@Input Boolean&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Optional&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;true / false&lt;/td&gt;
&lt;td&gt;Dots navigation enabled if true; default arrow navigation is enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;left&lt;/td&gt;
&lt;td&gt;@Input String&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Optional&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Custom class for left navigation arrow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;right&lt;/td&gt;
&lt;td&gt;@Input String&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Optional&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Custom class for right navigation arrow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why jQuery is hostile with Angular ?&lt;/li&gt;
&lt;li&gt;Angular Simple Slick plugin without any dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article a useful primer for getting started with ngxslick, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check this out npm package for more reference &lt;a href="https://www.npmjs.com/package/ngx-simple-slick" rel="noopener noreferrer"&gt;NGX Slick&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>npm</category>
    </item>
    <item>
      <title>How to write and publish your first NPM package</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Mon, 19 Oct 2020 05:56:16 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/how-to-write-and-publish-your-first-npm-package-1p49</link>
      <guid>https://dev.to/rajeshkumaravel/how-to-write-and-publish-your-first-npm-package-1p49</guid>
      <description>&lt;h2&gt;
  
  
  Before we begin…
&lt;/h2&gt;

&lt;p&gt;Before we begin this, you should have the following things set up.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; and npm installed&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com" rel="noopener noreferrer"&gt;npm account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Choosing a package name
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9q3h68fuyk8e3crvn2q9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9q3h68fuyk8e3crvn2q9.jpg" alt="npm package name"&gt;&lt;/a&gt;&lt;br&gt;
You need to check whether the name is available for the npm package. If you are publishing unscoped (public) package; the name of the package should be unique.&lt;/p&gt;

&lt;p&gt;However, if you are publishing a scoped (private) package then name does not have to be unique and name takes the format of &lt;strong&gt;@npm_username/package-name&lt;/strong&gt;&lt;br&gt;
Read more on&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/using-npm/scope.html" rel="noopener noreferrer"&gt;Scoped packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/package-name-guidelines" rel="noopener noreferrer"&gt;Package name guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Initializing the npm package
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a new directory and initialize using &lt;code&gt;npm init&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Initializing package will ask you a few questions for setup.&lt;br&gt;
The default &lt;code&gt;package.json&lt;/code&gt; file will be created in your project directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "number-to-comma-format",
  "version": "1.0.0",
  "description": "Convert a number to comma separated format",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;amp;&amp;amp; exit 1"
  },
  "author": "RAJESH K",
  "license": "MIT"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more on &lt;a href="https://docs.npmjs.com/files/package.json" rel="noopener noreferrer"&gt;package.json&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Node module
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; field in package.json defines the entry point of your package.&lt;/p&gt;

&lt;p&gt;Let's create &lt;code&gt;index.js&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ touch index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code to &lt;code&gt;index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict'

const defaultOptions = {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
};

/**
 * @param  {Number} num - Number to be converted
 * @returns - Formatted number format
 */
function formatNumberToComma(num) {
  return Number(num).toLocaleString('en', defaultOptions);
}

module.exports = formatNumberToComma;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a README
&lt;/h2&gt;

&lt;p&gt;It's a good idea to include documentation for your package so others know how to use it&lt;br&gt;
Generally, a README should cover&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Description of what your package does&lt;/li&gt;
&lt;li&gt;Installation and usage instructions&lt;/li&gt;
&lt;li&gt;Example code&lt;/li&gt;
&lt;li&gt;Contribution guidelines&lt;/li&gt;
&lt;li&gt;License used by the package &lt;em&gt;&lt;a href="https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository" rel="noopener noreferrer"&gt;Choosing the right license&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Test your package locally
&lt;/h2&gt;

&lt;p&gt;It is recommended to test your package locally before publishing to npm&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create and initialize new project outside package directory&lt;/li&gt;
&lt;li&gt;Package can be installed by the following command
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install number-to-comma-format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The problem with this is that your package is still not published yet so it isn't in npm. You need to reference your package locally while developing and testing it.&lt;br&gt;
You could install the package using an absolute path to the package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install /home/rajesh/dev/number-to-comma-format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialize Git
&lt;/h2&gt;

&lt;p&gt;Create a new repository in github for your package and push the source code to git&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/rajeshkumaravel/numbertocommaformat.git
git push origin master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publish the package to npm
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sign in to npm&lt;/li&gt;
&lt;li&gt;You'll be prompted to enter username, password and email address which was used while registering to npm
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now you can publish your package to npm by
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;VOILA...! Your package is now published on npm.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initialize &lt;code&gt;npm init&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add node module/source code&lt;/li&gt;
&lt;li&gt;Test your package locally&lt;/li&gt;
&lt;li&gt;git initialize&lt;/li&gt;
&lt;li&gt;Publish package &lt;code&gt;npm publish&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s it!&lt;/p&gt;

&lt;p&gt;I hope you found this article a useful primer for getting started with publishing on npm, and as always, thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check this out npm package for more reference &lt;a href="https://www.npmjs.com/package/node-express-req-id" rel="noopener noreferrer"&gt;Node express request id&lt;/a&gt;  &lt;a href="https://github.com/rajeshkumaravel/express-req-id" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Happy Coding!&lt;br&gt;
RK&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>Google Firebase Functions : Setting and accessing environment variable</title>
      <dc:creator>Rajesh Kumaravel</dc:creator>
      <pubDate>Fri, 11 Sep 2020 05:18:31 +0000</pubDate>
      <link>https://dev.to/rajeshkumaravel/google-firebase-functions-setting-and-accessing-environment-variable-1gn2</link>
      <guid>https://dev.to/rajeshkumaravel/google-firebase-functions-setting-and-accessing-environment-variable-1gn2</guid>
      <description>&lt;p&gt;It's always a good idea to externalize application keys/secrets from code.&lt;br&gt;
Google Firebase Functions has a feature that allows you to specify environment variables of key/value pairs using &lt;a href="https://firebase.google.com/docs/cli"&gt;Firebase CLI&lt;/a&gt; and can be accessed by your code at runtime.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Set env variable&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:set config.key="SECRET_KEY" config.pass="SECRET_PASS"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;NOTE: You must redeploy functions to make the new configuration available.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Deploy functions&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase deploy --only functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Accessing env variables&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const secretKey  = firebase.config().config.key;
const secretPass = firebase.config().config.pass;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Retrieve all variables&lt;/strong&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "config": {
    "key": "SECRET_KEY",
    "pass": "SECRET_PASS"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Unset a variable&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:unset config.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's consider using a file where we can keep all the environment variables.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;env.json&lt;/code&gt;, a file that will contain all our environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "config": {
    "host": "domain",
    "key": "SECRET_KEY",
    "pass": "SECRET_PASS"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How to deploy the variables with the &lt;code&gt;env.json&lt;/code&gt; file?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;firebase functions:config:set env="$(cat env.json)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Now we can make a bulk update of our variables and keep track of them.&lt;/p&gt;

</description>
      <category>node</category>
      <category>googlecloud</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
