# Install SuperScheduler Pro

> Install Pro from its private, versioned HTTPS tarball with npm, keep lockfile integrity, upgrade deliberately, run it in CI and treat the download key as a secret.

Source: https://superscheduler.org/en/docs/install-pro/
Reviewed: 2026-10-07

Add "super-scheduler": "https://npm.superscheduler.org/pro/YOUR_DOWNLOAD_KEY/0.1.0.tgz" to your dependencies and run npm install once: npm downloads the archive and records its SHA-512 integrity in package-lock.json. From then on npm ci installs exactly that archive, locally and in CI. Imports stay super-scheduler and super-scheduler/styles.css, React 18.2+ or 19 is a peer dependency, and the key in the URL is a download secret.

SuperScheduler Pro is not on the public npm registry. Each release is a versioned archive (`.tgz`) served over HTTPS, and your personal download key is part of its URL. npm supports this natively as a [URL dependency](https://docs.npmjs.com/cli/v11/configuring-npm/package-json/#urls-as-dependencies): no registry configuration, no `.npmrc` changes and no interactive login. Once installed, the package is named `super-scheduler` and behaves like any other dependency.

This guide uses npm. Replace `YOUR_DOWNLOAD_KEY` with the key you received; the examples pin version `0.1.0`.

## Before you start
- **A download key.** It authorizes downloads only. See [Keep the download key secret](#download-key).
- **React 18.2 or later, or React 19**, with the matching `react-dom`. Both are peer dependencies; the library has no runtime dependencies of its own.
- **HTTPS access** from every machine that installs dependencies (developer laptops, CI runners, build containers) to `npm.superscheduler.org`.

## Add the dependency
Add the tarball URL to `dependencies` in `package.json`:

```json
{
  "dependencies": {
    "super-scheduler": "https://npm.superscheduler.org/pro/YOUR_DOWNLOAD_KEY/0.1.0.tgz",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}
```

Then install:

```sh
npm install
```

Running `npm install` with the URL as an argument does the same and writes the entry for you:

```sh
npm install https://npm.superscheduler.org/pro/YOUR_DOWNLOAD_KEY/0.1.0.tgz
```

Check the result:

```sh
npm ls super-scheduler react react-dom
```

You should see `super-scheduler@0.1.0` and a single version of `react` and `react-dom`.

## What the lockfile records
The first install downloads the archive, computes its SHA-512 hash and stores both the URL and the hash in `package-lock.json`:

```json
{
  "packages": {
    "node_modules/super-scheduler": {
      "version": "0.1.0",
      "resolved": "https://npm.superscheduler.org/pro/YOUR_DOWNLOAD_KEY/0.1.0.tgz",
      "integrity": "sha512-…",
      "peerDependencies": {
        "react": "^18.2.0 || ^19.0.0",
        "react-dom": "^18.2.0 || ^19.0.0"
      }
    }
  }
}
```

The `integrity` value is what makes the install reproducible. The archive behind a released version never changes, so every later install of `0.1.0`, on any machine, must produce the same hash; if the downloaded bytes ever differed, npm would stop with an `EINTEGRITY` error instead of installing them. Commit `package-lock.json` together with `package.json`, and never edit the `integrity` field by hand. The npm documentation describes the [`resolved` and `integrity` fields](https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/#packages).

## npm install or npm ci
| Command | Use it when | What it does with Pro |
|---|---|---|
| `npm install` | You add, upgrade or change the URL of a dependency | Resolves the URL, downloads the archive and rewrites `resolved` and `integrity` in the lockfile when they change |
| `npm ci` | Everywhere else: fresh clones, CI, Docker builds, deploys | Deletes `node_modules` and installs exactly what the lockfile says, verifying the integrity; fails if `package.json` and the lockfile disagree |

Prefer `npm ci` in automation. It never rewrites the lockfile, so a build cannot silently pick up a different archive.

## Upgrade to a new version
A tarball URL is a fixed address, not a semver range: `npm update` and `npm outdated` do not see new Pro releases, and nothing upgrades by itself. To move to a new version:

1. Read the [changelog](https://superscheduler.org/en/changelog/) for the target version.
2. Change the version at the end of the URL, for example `…/YOUR_DOWNLOAD_KEY/0.1.0.tgz` to the new version number.
3. Run `npm install` to download the new archive and regenerate its lockfile entry.
4. Run your type check and tests, then commit `package.json` and `package-lock.json` together.

To roll back, point the URL at the previous version and run `npm install` again. Released archives are immutable, so the previous version installs with the same integrity it had before.

## Continuous integration
CI needs nothing beyond what it already does for public packages: the URL and the integrity are in the lockfile, and the download requires no login.

```sh
npm ci
npm run typecheck
npm test
npm run build
```

Keep in mind where the download key travels in CI:

- **Dependency caches.** If you cache npm's cache directory or `node_modules` between runs, the cached archive and the lockfile are as sensitive as the key itself. Keep caches private to the project.
- **Logs.** npm error messages can include the URL it tried, key included. Do not publish CI logs of private projects.
- **Forks and public mirrors.** A repository that contains the key must stay private. Do not push it to a public mirror.

## Keep the download key secret
The key is a bearer secret for downloads. Anyone who has the URL can download that release, so it deserves the same care as an API token:

- It appears in `package.json`, `package-lock.json`, npm's local cache and possibly in logs. Keep the repository and those files private.
- Do not paste the URL into public issues, chats, gists, screenshots or bug reports. When you share a dependency list, replace the key with `YOUR_DOWNLOAD_KEY`.
- If the key is exposed, ask for a new one, replace it in `package.json`, run `npm install` and commit both files. The archive is the same, so only the `resolved` URL changes; the integrity stays identical.

> **Limitation:**
> The key controls downloads, nothing else. Revoking it blocks new downloads from the server, but it does not remove archives already downloaded, npm caches, or code already bundled into an application. It is not a runtime licence check or DRM: the installed package does not contact any server.

## Peer dependencies and a single React
Pro declares `react` and `react-dom` `^18.2.0 || ^19.0.0` as peer dependencies and uses your application's copy. npm reports a peer dependency conflict if your project is on an older React.

There must be exactly one React in the bundle. Two copies break hooks and context, which `useSchedulerControl`, the `super-scheduler/hooks` subpath and the render slots of `super-scheduler/react-render` rely on. `npm ls react react-dom` must show a single version. In a monorepo or when you link packages locally, tell the bundler to resolve one copy, for example with Vite's [`resolve.dedupe`](https://vite.dev/config/shared-options.html#resolve-dedupe) set to `['react', 'react-dom']`.

## Imports and styles
The package name is `super-scheduler`, whatever URL it was installed from. Import the stylesheet once, in your entry file, before your own CSS:

```tsx
// src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { version } from 'super-scheduler'
// Once per application, before your own stylesheets. The library rules live in
// `@layer super-scheduler`, so any unlayered rule of yours wins without !important.
import 'super-scheduler/styles.css'
import './app.css'
import { Planning } from './Planning'

// '0.1.0': the version your bundler resolved from the tarball.
console.info(`SuperScheduler ${version}`)

const container = document.getElementById('root')
if (container === null) throw new Error('#root is missing')

createRoot(container).render(
  <StrictMode>
    <Planning />
  </StrictMode>,
)
```
```tsx
// src/Planning.tsx
import { useMemo, useState } from 'react'
import { SuperSchedulerComponent } from 'super-scheduler'
import type { SchedulerEventsChangeArgs, SuperScheduler } from 'super-scheduler'

const ROOMS: SuperScheduler.ResourceData[] = [
  { id: 'r101', name: 'Room 101' },
  { id: 'r102', name: 'Room 102' },
]

const TIME_HEADERS: SuperScheduler.TimeHeaderData[] = [
  { groupBy: 'Month' },
  { groupBy: 'Day', format: 'd' },
]

export function Planning() {
  const [events, setEvents] = useState<SuperScheduler.EventData[]>([
    {
      id: 1,
      resource: 'r101',
      start: '2026-10-02T14:00:00',
      end: '2026-10-05T11:00:00',
      text: 'Booking 1042',
    },
  ])
  // The control edits the array it receives in place: hand it a copy of the state.
  const owned = useMemo(() => events.slice(), [events])
  const onEventsChange = (args: SchedulerEventsChangeArgs) => setEvents([...args.events])

  return (
    <SuperSchedulerComponent
      startDate="2026-10-01"
      days={31}
      scale="Day"
      cellWidth={44}
      timeHeaders={TIME_HEADERS}
      resources={ROOMS}
      events={owned}
      onEventsChange={onEventsChange}
    />
  )
}
```
You should see a month of day columns, two rooms and one booking. Drag the booking to the other room: `onEventsChange` writes its new position into React state, which is the pattern described in [Controlled events and callbacks](https://superscheduler.org/en/docs/controlled-state/).

Optional features live in their own subpaths, so you only load what you import:

| Import | Contents |
|---|---|
| `super-scheduler` | `SuperSchedulerComponent`, the `SuperScheduler` namespace, `useSchedulerControl`, all public types, `version` |
| `super-scheduler/styles.css` | The stylesheet and its `--super-scheduler-*` tokens |
| `super-scheduler/react-render` | A component variant with React render slots and hover cards |
| `super-scheduler/history` | Undo and redo |
| `super-scheduler/minimap` | Timeline overview with a viewport brush |
| `super-scheduler/panes` | Several coordinated scheduler panes with splitters |
| `super-scheduler/zoom-ui` | Zoom slider, zoom readout and level-of-detail badge |
| `super-scheduler/views` | Save and restore zoom, scroll position, density, collapsed rows and columns |
| `super-scheduler/ranges` | Cancellable loading of events by date range |
| `super-scheduler/hooks` | React subscriptions to scheduler state |
| `super-scheduler/core` | DOM-free date, duration and timeline utilities |
| `super-scheduler/datasets` | Deterministic sample data for demos and tests |
| `super-scheduler/tailwind` | Tailwind CSS v3 preset |

Every entry ships ES modules and CommonJS with TypeScript declarations for both. `moduleResolution: "bundler"`, `"node16"` and `"nodenext"` read the package's `exports`; older `"node"` resolution finds the subpath types too. Some features and language packs are loaded on demand with dynamic `import()`, so keep your bundler's code splitting enabled (it is on by default in Vite, Next.js and webpack).

## Troubleshooting the installation
| Symptom | Cause and fix |
|---|---|
| npm fails with HTTP 403 for the tarball URL | The key is wrong, expired or revoked. Check for copy errors; ask for a new key if needed |
| npm fails with HTTP 404 | The key is valid but that version does not exist. Check the version in the URL against the [changelog](https://superscheduler.org/en/changelog/) |
| `EINTEGRITY` | The downloaded bytes do not match the lockfile's hash. Released archives never change, so look for a damaged cache (`npm cache verify`) or a lockfile edited or merged by hand (restore it from version control). Never replace the hash to make the error go away |
| `npm ci` says the lockfile is out of sync | `package.json` changed without `npm install`. Run `npm install` and commit both files |
| `ERESOLVE` mentioning React | Your React is older than 18.2. Upgrade React first |
| "Invalid hook call" from SuperScheduler hooks | Two copies of React. See [a single React](#react) |
| The grid has no borders or colors | `super-scheduler/styles.css` is not imported |

For runtime problems after installation, see [Troubleshooting](https://superscheduler.org/en/docs/troubleshooting/).

## Next steps
- Learn how the component fits a React app: [React integration](https://superscheduler.org/en/docs/react-integration/).
- Wire your data and backend: [Controlled events and callbacks](https://superscheduler.org/en/docs/controlled-state/).
- Add business rules to dragging: [Drag, resize and business rules](https://superscheduler.org/en/docs/drag-resize-rules/).
