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

tacel-lucid-workflow-viewer

v0.1.1

Published

Reusable browser workflow viewer for published Lucid workflow graphs

Readme

Lucid Workflow Viewer Module

Reusable browser graph viewer for published Lucid workflow graphs.

This module is intentionally host-agnostic. It contains no database credentials, backend internals, server IPs, auth secrets, or private storage paths. Host apps provide every runtime value and decide how those values are sourced.

Files

  • lucid-workflow-viewer.js - UMD/browser module, exposes window.LucidWorkflowViewer.
  • lucid-workflow-http-data-source.js - optional HTTP adapter for the standard Lucid workflow API.
  • lucid-workflow-viewer.css - optional static stylesheet.
  • index.js - CommonJS entry point for Electron/Node bundlers.
  • scripts/sync-to-host.js - copies browser assets into a host app's packaged renderer/static folder.

Runtime Contract

The host app owns all runtime configuration:

  • apiBaseUrl - base URL for the Lucid workflow API when using the HTTP adapter.
  • documentId - Lucid document id whose published graph should be loaded.
  • workflowId - optional selected workflow id; if omitted, the viewer picks the first workflow.
  • currentUser or userKey - viewer identity used for video progress.
  • theme - dark or light; hosts can also pass className for app-specific styling.
  • showEdgeText, showLineJunctions, showAllWorkflowsOption, enableMultiWorkflowSelection, enableWorkflowRenaming, workflowDisplayNames, showControls, showWorkflowPicker, reactFlowAssetBase, and other display options.
  • enableWorkflowFiltering defaults to true. Set it to false to render the whole graph at once, hide the workflow picker, and use one universal graphColor for nodes and edges.
  • graphColor is optional. Whole-graph mode falls back to white when it is empty or invalid.
  • applyPublishedLockedNodeIds lets a host apply lockedNodeIds returned alongside a published graph response.
  • accessibleNodeIds lets a host pass a certificate allowlist. The module keeps the whole graph visible and derives forced locks for every node outside that list. An empty array locks every node.
  • enableWorkflowRenaming is display-only. It lets viewers override workflow labels in this module without changing the published Lucid graph.
  • workflowDisplayNames can pre-seed display labels as { workflowId: "Display name" }.
  • onWorkflowDisplayNamesChange(event) can be used by the host to persist viewer-only label overrides.
  • cacheVideoUrls defaults to true and caches resolved video URLs per viewer instance.
  • transformVideoUrl(rawUrl, context) lets hosts convert a raw file URL or path before playback. Tauri hosts commonly use this to call convertFileSrc.
  • nodeSelectionMode turns the graph into an authoring node picker: each node renders a membership checkbox instead of the end-user blocked/locked gating. selectedNodeIds is the checked (included) set and onNodeToggle(nodeId, checked) fires on each toggle. Hosts can also push a new checked set without re-initializing via the instance method setSelectedNodeIds(ids) (the viewer reconciles in place, preserving pan/zoom). Off by default — every other host renders unchanged. Used by the WireHub certificate editor so admins pick nodes on the graph itself.
  • openAttachment(args) and downloadAttachment(args) let hosts own the node-attachment View and Download actions. When provided, the viewer calls them instead of falling back to a browser anchor (which cannot save or open files inside native webviews such as Tauri/Electron). args includes { action, file, node, url, fileId, nodeId, workflowId, documentId }. The module still resolves the file first (so "still optimizing" / "failed" statuses are surfaced) and only delegates on success. Web hosts that omit these callbacks keep the default anchor behavior.
  • unassignedProgressWorkflowId lets a host persist progress for unassigned nodes under a synthetic workflow id. If omitted, unassigned progress remains local-only.
  • resumeProgressWorkflowId defaults to __video_resume__. Resume playback uses this single synthetic workflow id so each node/user video position overwrites one row instead of duplicating across workflow progress rows.
  • Resume rows use last_position_seconds for the reopen point and max_position_seconds for the no-skip watched watermark. Legacy position_seconds is still accepted as a fallback.
  • Playback behavior is host-configurable:
    • enableResume turns resume playback on or off.
    • resumeMinPositionSeconds defaults to 5; positions at or below this start from the beginning.
    • resumeEndBufferSeconds defaults to 15; positions within this many seconds of the end start from the beginning. Set 0 to allow resume until the exact end.
    • resumeCompletedVideos defaults to false; completed nodes normally restart from the beginning.
    • savePositionOnClose defaults to true.
    • savePositionOnPause defaults to false.
    • positionSaveIntervalMs defaults to 0, which disables interval saves.
    • preventSkip turns no-skip enforcement on or off.
    • preventSkipToleranceSeconds defaults to 0.5.
    • videoSeekStepSeconds defaults to 5.
    • videoPreload defaults to metadata; valid values are none, metadata, and auto.
  • syncUsers(context) is an optional host callback for copying users from the host's configured source into LUCID.user_access.
  • userSyncIntervalMs defaults to five minutes. syncUsersOnStart defaults to true.
  • userSyncKey lets multiple viewer instances share one scheduler. Use a stable host-specific key when syncing from mounted viewers.

Hosts may either provide callbacks directly or create callbacks from the HTTP adapter. The viewer itself does not know where configuration comes from.

Optional User Sync

The module owns scheduling, overlap protection, and teardown. The host owns database credentials, source-table configuration, and the actual write into LUCID.user_access. Never pass database credentials into browser code.

Start user sync once during host-app startup:

const userSync = LucidWorkflowViewer.startUserSync({
  userSyncKey: 'my-host-users',
  userSyncIntervalMs: 5 * 60 * 1000,
  syncUsersOnStart: true,
  syncUsers: () => hostApi.syncUsersIntoLucid()
});

// On host shutdown:
userSync.stop();

Run one sync manually:

await LucidWorkflowViewer.syncUsers({
  syncUsers: () => hostApi.syncUsersIntoLucid()
});

Simpler hosts may pass the same options into initialize(). The viewer instance starts the scheduler while mounted and stops it during destroy().

HTTP Adapter

The HTTP adapter has no built-in service address. Hosts must pass one of apiBaseUrl, baseUrl, serviceUrl, serviceBaseUrl, or syncBaseUrl. apiBaseUrl is preferred for new hosts.

const dataSource = LucidWorkflowHttpDataSource.create({
  apiBaseUrl: hostConfig.lucidWorkflowApiBaseUrl
});

The adapter provides:

  • loadPublishedGraph(args)
  • loadProgress(args)
  • markNodeComplete(args)
  • getVideoUrl(args)

Basic Browser Usage

<div id="workflow-viewer"></div>
<script src="./lucid-workflow-http-data-source.js"></script>
<script src="./lucid-workflow-viewer.js"></script>
<script>
  const dataSource = LucidWorkflowHttpDataSource.create({
    apiBaseUrl: window.hostLucidConfig.apiBaseUrl
  });

  const viewer = LucidWorkflowViewer.initialize('#workflow-viewer', {
    ...dataSource,
    documentId: window.hostLucidConfig.documentId,
    workflowId: window.hostLucidConfig.workflowId,
    currentUser: window.hostCurrentUser,
    theme: window.hostLucidConfig.theme || 'dark',
    reactFlowAssetBase: window.hostLucidConfig.reactFlowAssetBase,
    showEdgeText: Boolean(window.hostLucidConfig.showEdgeText)
  });
</script>

Direct Callback Usage

LucidWorkflowViewer.initialize(container, {
  documentId,
  workflowId,
  currentUser,
  loadPublishedGraph: async ({ documentId, workflowId }) => {
    return hostApi.loadWorkflowGraph({ documentId, workflowId });
  },
  loadProgress: async ({ documentId, workflowId, userKey }) => {
    return hostApi.loadWorkflowProgress({ documentId, workflowId, userKey });
  },
  markNodeComplete: async ({ documentId, workflowId, nodeId, primaryFileId, userKey }) => {
    return hostApi.markWorkflowNodeComplete({ documentId, workflowId, nodeId, primaryFileId, userKey });
  },
  getVideoUrl: ({ fileId }) => {
    return hostApi.getWorkflowVideoUrl(fileId);
  },
  transformVideoUrl: (rawUrl, context) => {
    return hostApi.toPlayableVideoUrl(rawUrl, context.file);
  }
});

Data Shapes

loadPublishedGraph(args) may return either the standard API response shape or the raw graph:

{
  graph: {
    workflows: [{ id, name, color }],
    nodes: [{ nodeId, title, description, workflowIds, primaryVideoFileId, box, shapeKind, files }],
    edges: [{ workflowId, workflowIds, fromNodeId, toNodeId, text }]
  }
}

Line-to-line publishes can include endpoint metadata:

{
  kind: 'edge-to-edge',
  from: { kind: 'line', lineId, position, x, y },
  to: { kind: 'line', lineId, position, x, y },
  resolvedFromNodeIds: ['source-node-id'],
  resolvedToNodeIds: ['target-node-id']
}

The viewer uses resolvedFromNodeIds and resolvedToNodeIds for video unlocking. Line endpoint refs are visual only.

A node's files array lists its attachments. Each entry is { id, name, mime, size, accessMode, createdAt }, where accessMode is view, download, or both (defaults to both). The node detail panel renders a View and/or Download button per attachment according to accessMode. Hosts handle those clicks via openAttachment / downloadAttachment (see Runtime Contract).

workflowIds is the cumulative membership of the nodes connected by an edge. For compatibility with older hosts, workflowId remains populated when an edge has exactly one workflow membership. Older publishes that only provide workflowId are still supported.

Newer publishes can also include pathPoints on edges. These are sampled Lucid line coordinates and are preferred for visual routing, especially for node-to-edge and edge-to-edge connectors.

loadProgress(args) should return rows containing at least:

[{ node_id: 'lucid-node-id', completed_at: '2026-05-13T12:00:00.000Z' }]

For resume playback, hosts may also return last_position_seconds and max_position_seconds. The viewer writes both offsets through onPositionChange when a video modal is closed, replaced, or destroyed. Older hosts that only return position_seconds still work as a fallback.

Viewer Rules

  • Start nodes are available immediately.
  • A downstream node unlocks when any direct upstream node in the selected workflow has been completed by the current user.
  • Workflow colors are used for graph nodes and single-workflow edges. An edge shown in more than one selected workflow renders as a bold black line.
  • Hosts can set enableWorkflowFiltering: false for certificate-style viewing. The viewer shows all nodes and edges, hides workflow switching, and paints the graph with graphColor or white when no color is configured.
  • Certificate hosts can pass accessibleNodeIds while using whole-graph mode. Nodes outside the allowlist remain visible but render greyed out, show a lock indicator, and ignore clicks.
  • Hosts can set showAllWorkflowsOption: true to add an All workflows + unassigned picker option that displays every published workflow plus unassigned nodes.
  • Hosts can set enableMultiWorkflowSelection: true to let viewers select multiple workflow ids at once from the same picker.
  • Hosts can set enableWorkflowRenaming: true to show an Edit label control for the selected workflow; the rename only changes viewer display text.
  • Hosts can set showUnassignedWorkflowOption: true to add an Unassigned picker option for nodes and edges with no workflow membership.
  • Hosts can set unassignedProgressWorkflowId when they want unassigned node progress to persist through the normal progress callbacks.
  • Hosts can set resumeProgressWorkflowId to control the synthetic workflow id used for per-node resume playback rows.
  • Published shapeKind: "diamond" nodes render as text-only diamonds.
  • Other nodes render as square/card nodes.
  • Line-to-line connections render through junction anchors, but only real workflow nodes participate in video progress.
  • Junction anchors are hidden by default. Hosts can set showLineJunctions: true to show them for debugging or teaching the graph shape.
  • Edge labels render only when the host sets showEdgeText: true and the published edge has text.
  • Lucid box coordinates are used when present; otherwise the module falls back to a simple layout.

Host Asset Sync

Apps that package static browser assets can sync this module into their own source tree:

node ../Modules/lucid-workflow-viewer-module/scripts/sync-to-host.js path/to/host/static/lucid-workflow-viewer
node ../Modules/lucid-workflow-viewer-module/scripts/sync-to-host.js path/to/host/static/lucid-workflow-viewer --check

The sync script copies only the module assets listed in this package. It does not copy host configuration or private runtime settings.