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

@sqlrooms/artifacts

v0.29.0

Published

`@sqlrooms/artifacts` provides a room-store slice and React/layout helpers for workspace artifacts such as dashboards, notebooks, canvas documents, pivot tables, and apps.

Readme

@sqlrooms/artifacts

@sqlrooms/artifacts provides a room-store slice and React/layout helpers for workspace artifacts such as dashboards, notebooks, canvas documents, pivot tables, and apps.

Artifacts are durable workspace entries. Artifact tabs are the layout/UI adapter for opening, closing, renaming, reordering, searching, and deleting those entries.

Artifacts are workspace-level entries. Embedded document content should be modeled as blocks, usually hosted stateful blocks, rather than as hidden child artifacts in the artifact registry.

See the Artifacts developer guide for the workspace model, lifecycle guidance, and end-to-end setup.

Usage

import {
  ArtifactTabs,
  ArtifactsSliceConfig,
  createArtifactTypeFromStatefulBlock,
  createArtifactPanelDefinition,
  createArtifactsSlice,
  defineArtifactTypes,
  useArtifactWorkspace,
} from '@sqlrooms/artifacts';

const artifactTypes = defineArtifactTypes({
  notebook: {
    label: 'Notebook',
    defaultTitle: 'Notebook',
    icon: FileTextIcon,
    component: NotebookPanel,
    onCreate: ({artifactId, store}) => {
      store.getState().notebook.ensureArtifact(artifactId);
    },
    onEnsure: ({artifactId, store}) => {
      store.getState().notebook.ensureArtifact(artifactId);
    },
    onDelete: ({artifactId, store}) => {
      store.getState().notebook.removeArtifact(artifactId);
    },
  },
});

const store = createRoomStore<RoomState>(
  persistSliceConfigs(
    {
      name: 'my-room',
      sliceConfigSchemas: {
        artifacts: ArtifactsSliceConfig,
      },
    },
    (set, get, store) => ({
      ...createArtifactsSlice({artifactTypes})(set, get, store),
      layout: {
        panels: {
          artifact: createArtifactPanelDefinition(artifactTypes, store),
        },
      },
    }),
  ),
);
<ArtifactTabs types={['notebook']} panelKey="artifact">
  <ArtifactTabs.SearchDropdown />
  <ArtifactTabs.Tabs />
  <ArtifactTabs.NewButton artifactType="notebook" />
</ArtifactTabs>

Use ArtifactTabs.useActions() from custom subcomponents when you need access to the tab adapter actions, and use overlay for dialogs or other elements that need that context without being rendered inside the tab strip.

For non-tab artifact surfaces, use useArtifactWorkspace() directly:

const artifacts = useArtifactWorkspace({
  types: ['notebook', 'dashboard'],
});

return artifacts.selectedArtifact ? (
  <ArtifactPanel artifact={artifacts.selectedArtifact} />
) : (
  <NewArtifactScreen onCreate={() => artifacts.createArtifact('notebook')} />
);

Slice API

Config uses artifact terminology throughout:

  • artifacts.config.artifactsById

  • artifacts.config.artifactOrder

  • artifacts.config.pinnedArtifactIds

  • artifacts.config.currentArtifactId

  • artifacts.createArtifact({type, title?, id?})

  • artifacts.ensureArtifact(id, {type, title?})

  • artifacts.renameArtifact(id, title)

  • artifacts.closeArtifact(id)

  • artifacts.deleteArtifact(id)

  • artifacts.setCurrentArtifact(id?)

  • artifacts.setArtifactOrder(order)

  • artifacts.togglePinArtifact(id)

  • artifacts.isPinnedArtifact(id)

  • artifacts.getArtifact(id)

closeArtifact is non-destructive. It runs close lifecycle cleanup, while the tab adapter hides the layout tab so it can be reopened from search.

deleteArtifact is destructive. It runs close and delete lifecycle hooks, then removes the artifact registry entry.

Artifact Tabs

  • useArtifactWorkspace({types?, selectFallback?}) returns tab-free artifact ids, descriptors, current selection, type definitions, and create/delete/ rename/select actions. It is useful for single-content hosts, sidebars, and search/create surfaces that should not adopt layout-tab behavior.
  • useArtifactTabs({tabsId?, types?, panelKey?}) returns TabStrip-compatible descriptors, open tab ids, selected id, and handlers. It builds on useArtifactWorkspace() and adds the layout-tabs adapter.
  • ArtifactTabs is a compound component over TabStrip and TabsLayout.TabContent.
  • Pass forceMountContent to ArtifactTabs to keep visible artifact tab panels mounted while hiding inactive panels.
  • ArtifactTabs.useActions() exposes the current tab adapter actions to custom subcomponents rendered under ArtifactTabs.
  • createArtifactLayoutNode(artifactId, panelKey?) creates a stable layout panel node for an artifact.
  • createArtifactPanelDefinition(artifactTypes, store) resolves artifact panel titles, icons, and components from the runtime type registry.

Type definitions are runtime configuration and are not persisted. Set canCreate: false on a type definition when an app needs to render an existing artifact as a read-only compatibility surface without showing it in creation menus or allowing createArtifact() calls for that type.

Stateful Block Bridge

Feature packages can expose reusable stateful block definitions from @sqlrooms/blocks. Use createArtifactTypeFromStatefulBlock() when a stateful block should also be available as a top-level artifact shell:

const artifactTypes = defineArtifactTypes({
  dashboard: createArtifactTypeFromStatefulBlock(dashboardBlockDefinition),
});

The artifact shell still owns workspace metadata such as id, title, tabs, current selection, and AI context. The stateful block definition owns the feature-specific rendering and backing-state lifecycle.

Entry Points

| Import | Contains | Pulls React | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------- | | @sqlrooms/artifacts | Slices, components, artifact types — the full package | Yes | | @sqlrooms/artifacts/config | Serializable shapes only: ArtifactMetadata, ArtifactsSliceConfig, ArtifactType, ArtifactSessionLink(Schema) | No | | @sqlrooms/artifacts/ai | Assistant tools for artifact context | No |

Prefer @sqlrooms/artifacts/config when you only need the persisted data model and want to stay out of the React dependency — a test runner, a config migration, or server-side code:

import {
  ArtifactMetadata,
  ArtifactSessionLinkSchema,
} from '@sqlrooms/artifacts/config';

const link = ArtifactSessionLinkSchema.parse(row);

Import these shapes from /config rather than from an internal module path such as @sqlrooms/artifacts/dist/ArtifactsSliceConfig. The subpath is the supported surface and will keep working when the underlying modules are reorganized; internal paths have moved before.

All entries target bundlers and transpilers (moduleResolution: "bundler"), so emitted re-exports are extensionless. Being React-free is what makes /config and /ai usable from Node toolchains, not native node resolution of the published files.

AI Context Tools

@sqlrooms/artifacts/ai provides reusable assistant tools for artifact context:

  • list_context_artifacts
  • read_context_artifact
  • set_primary_context_artifact

Use createArtifactContextAiTools({store, readArtifact}) in apps that combine @sqlrooms/artifacts with @sqlrooms/ai. The factory handles primary artifact selection and run-context updates; the app supplies artifact payload readers for domain-specific types such as documents or dashboards. Apps with capability profiles can pass isArtifactAllowed to apply the same eligibility rule when listing, reading, or selecting a primary context artifact.

Artifact-aware room commands can use resolveArtifactTargetId() to preserve the same per-turn target. Its precedence is an explicit command artifact ID, then an AI invocation's captured artifact target, then the live current artifact for non-AI and compatibility fallback behavior. The helper depends only on room command invocation data; it does not require artifact-owned sessions or a context-selector UI.

Artifact-Owned AI Sessions

@sqlrooms/artifacts/ai also provides createArtifactAiSlice() for apps that want AI chats to belong to the current artifact without changing the generic chat session schema.

Add ArtifactAiConfigSchema to persistence and compose the slice after createArtifactsSlice() and the app's AI slice:

import {
  ArtifactAiConfigSchema,
  createArtifactAiSlice,
} from '@sqlrooms/artifacts/ai';

const store = createRoomStore<RoomState>(
  persistSliceConfigs(
    {
      name: 'my-room',
      sliceConfigSchemas: {
        artifacts: ArtifactsSliceConfig,
        artifactAi: ArtifactAiConfigSchema,
      },
    },
    (set, get, store) => ({
      ...createArtifactsSlice({artifactTypes})(set, get, store),
      ...createAiSlice(aiOptions)(set, get, store),
      ...createArtifactAiSlice()(set, get, store),
    }),
  ),
);

The slice stores a list of links between sessions and artifacts:

sessionArtifactLinks: ArtifactSessionLink[];

sessionArtifactLinks is the only supported persisted and runtime representation. The prerelease-only aiSessionArtifacts and artifactCreators fields were removed without an automatic migration. Update persisted prerelease configs before parsing them with ArtifactAiConfigSchema.

The link type is exported from @sqlrooms/artifacts:

  • ArtifactSessionLink — a single association: {sessionId, artifactId, linkedAt}. linkedAt is a Unix timestamp in milliseconds. A session may be associated with multiple artifacts.
  • ArtifactSessionLinkSchema — the Zod schema used to validate a link (for example when persisting ArtifactAiConfigSchema).

Links intentionally describe association only. If an app needs creation provenance, store it with the artifact's domain metadata instead of overloading the chat association.

All artifact AI session helpers accept sessionArtifactLinks; they do not accept a parallel one-to-one association map.

Use artifactAi.createArtifactScopedSession() when creating chats from an artifact-scoped assistant. It creates a fresh session and associates it with the current artifact. artifactAi.selectLatestSessionForArtifact() and artifactAi.syncCurrentArtifactAiSession() keep the current AI session aligned with artifacts.config.currentArtifactId. Sessions without an explicit artifact association are ignored by artifact-scoped history.

Reusable helpers include:

  • isAiSessionVisibleForArtifact
  • getLatestAiSessionIdForArtifact
  • getEmptyAiSessionIdForArtifact
  • getAiSessionIdsForArtifact
  • getAiSessionGroupsByArtifact
  • getRunningAiSessionCountsByArtifact
  • getOwningArtifactRunContextItems

getEmptyAiSessionIdForArtifact() requires session objects that include prompt and uiMessages; summary-only session rows cannot prove that a chat is empty.

Chat.History should remain generic: pass a filterSession callback built with isAiSessionVisibleForArtifact() and keep artifact-specific labels in the host app. For run context, use getOwningArtifactRunContextItems() to prepend the owning artifact as the implicit primary context item.

Artifact-owned AI sessions attach to artifact shells. If a stateful block is wrapped as a top-level artifact, use that artifact id. Stateful blocks hosted directly inside a block document should use the containing artifact's chat unless the host app intentionally introduces a block-scoped chat model.