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

@adobe/spacecat-shared-akamai-client

v1.2.0

Published

Shared modules of the Spacecat Services - Akamai Client

Readme

Spacecat Shared - Akamai Client

Overview

@adobe/spacecat-shared-akamai-client is a thin client for Akamai's Property Manager API (PAPI), authenticated with Akamai's EdgeGrid (EG1-HMAC-SHA256) scheme. It exposes operations for finding properties by site domain, reading and updating rule trees, creating property versions, and activating/monitoring activations — for use by Spacecat services that manage Akamai-fronted properties.

The EdgeGrid request signing is implemented directly against Akamai's published algorithm (no akamai-edgegrid dependency), and is cross-validated in tests against the official edgegrid-python reference implementation.

Installation

npm install @adobe/spacecat-shared-akamai-client

Usage

Creating a client

From a Universal context (recommended)

Reads EdgeGrid credentials from context.env:

import AkamaiClient from '@adobe/spacecat-shared-akamai-client';

const client = AkamaiClient.createFrom(context);

Expects AKAMAI_HOST, AKAMAI_CLIENT_TOKEN, AKAMAI_CLIENT_SECRET, AKAMAI_ACCESS_TOKEN, and optionally AKAMAI_ACCOUNT_SWITCH_KEY and AKAMAI_NOTIFY_EMAILS (comma-separated; required only to call activate()).

Direct constructor

import AkamaiClient from '@adobe/spacecat-shared-akamai-client';

const client = new AkamaiClient({
  host: process.env.AKAMAI_HOST, // e.g. "akab-xxxxx.luna.akamaiapis.net"
  clientToken: process.env.AKAMAI_CLIENT_TOKEN,
  clientSecret: process.env.AKAMAI_CLIENT_SECRET,
  accessToken: process.env.AKAMAI_ACCESS_TOKEN,
  accountSwitchKey: process.env.AKAMAI_ACCOUNT_SWITCH_KEY, // optional
  notifyEmails: ['[email protected]'], // required only to call activate()
}, log);

These credentials come from an Akamai API client scoped to Property Manager (PAPI) = READ-WRITE — see Create an API client.

API

findPropertiesByDomain(domain)

Finds candidate properties serving a site domain — matches the exact hostname (plus its apex/www variant) and, as a fallback, a property-name match. Returns matches deduped by propertyId, hostname matches ranked first.

const matches = await client.findPropertiesByDomain('www.example.com');
// [{ propertyId, propertyName, contractId, groupId, matchedOn: ['hostname'], ... }]

searchBy(key, value)

Lower-level primitive behind findPropertiesByDomain — a single PAPI find-by-value lookup.

const results = await client.searchBy('hostname', 'www.example.com');

getLatestVersion(propertyId, contractId, groupId)

const version = await client.getLatestVersion(propertyId, contractId, groupId);

getRuleTree(propertyId, version, contractId, groupId)

const { ruleTree, ruleFormat } = await client.getRuleTree(propertyId, version, contractId, groupId);

createVersion(propertyId, baseVersion, contractId, groupId)

Creates a new property version from baseVersion and returns the new version number.

const newVersion = await client.createVersion(propertyId, latestVersion, contractId, groupId);

updateRuleTree(propertyId, version, contractId, groupId, ruleTree, ruleFormat?)

PUTs a rule tree with PAPI-side validation (validateRules=true). Errors and warnings, if any, come back in the resolved response body rather than as a rejected promise.

const result = await client.updateRuleTree(propertyId, version, contractId, groupId, ruleTree, ruleFormat);
if (result.errors?.length) { /* handle PAPI validation errors */ }

activate(propertyId, version, contractId, groupId, network, note?)

Requires the client to have been constructed with a non-empty notifyEmails (PAPI requires at least one address to notify about activation progress).

const activationLink = await client.activate(propertyId, version, contractId, groupId, 'STAGING');
const activationId = AkamaiClient.activationIdFromLink(activationLink);

getActivation(propertyId, activationId, contractId, groupId)

Returns one activation's details (status, network, propertyVersion, submitDate, updateDate, ...). status progresses through PENDINGZONE_1/ZONE_2/ZONE_3ACTIVE (or ABORTED/FAILED).

const activation = await client.getActivation(propertyId, activationId, contractId, groupId);

listActivations(propertyId, contractId, groupId)

All activations (both networks, all versions) for a property.

latestActivation(propertyId, contractId, groupId, network)

The most recently submitted activation for a network, or undefined if the property has never been activated there — useful for polling deployment status without having to track an activationId across requests/sessions.

const activation = await client.latestActivation(propertyId, contractId, groupId, 'PRODUCTION');
if (activation?.status === 'ACTIVE') { /* deployment complete */ }

normalizeDomain(domain)

Named export. Reduces a URL, host:port, or trailing-dot hostname to a bare lowercase hostname.

import { normalizeDomain } from '@adobe/spacecat-shared-akamai-client';

normalizeDomain('HTTPS://Example.com:8080/path'); // 'example.com'

Error handling

All methods reject with a descriptive Error when:

  • a required argument is missing or the wrong type (e.g. version must be an integer, propertyId/contractId/groupId/network must be non-empty strings),
  • the underlying request fails (network error),
  • PAPI responds with a non-OK HTTP status, or
  • PAPI responds with a 200 but a body that isn't valid JSON.

The error message includes the targeted path and, for non-OK responses, the truncated response body. PAPI-level validation errors/warnings on updateRuleTree (HTTP 200 with an errors array) are returned in the resolved body, not thrown — check result.errors explicitly.

Property/version/activation IDs are URL-encoded before being interpolated into request paths, and searchBy's key argument is restricted to hostname/edgeHostname/propertyName — both defend against a caller accidentally (or maliciously) redirecting a request to an unintended endpoint.

License

Apache-2.0