Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cursor/rules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cursor (optional)

**Cursor** users: start at **[AGENTS.md](../../AGENTS.md)**. All conventions live in **`skills/*/SKILL.md`**.

This folder only points contributors to **`AGENTS.md`** so editor-specific config does not duplicate the canonical docs.
50 changes: 50 additions & 0 deletions .cursor/rules/code-review.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
description: PR checklist — API docs, compat, errors, tests, Marketplace vs CDA/CMA terminology
alwaysApply: true
---

# Code review checklist

Use this for any change touching the SDK. Severity labels are optional guidance for reviewers.

## API and documentation

- **Public surface:** New or changed `client()`, `marketplace()`, or chain methods need **JSDoc** consistent with surrounding symbols (params, return `Promise`, examples where helpful).
- **Types:** Update `types/**/*.d.ts` when exports or shapes change.

## Product terminology

- This repo is **Marketplace / Developer Hub** — **not CDA** (Delivery) and not general **stack CMA content** unless the change explicitly introduces that scope. PR text and user-facing strings must not mislabel the product.

## Backward compatibility

- Avoid breaking `client()` options, method signatures, or default behavior without semver intent and migration notes.
- Preserve existing header names and axios defaults unless versioned or documented.

## Errors

- HTTP failures should continue to map through **`contentstackError`** patterns (status, message body fields, header redaction)—no raw axios leaks to callers unless intentional and documented.

## Safety and robustness

- Guard null/undefined for optional nested params consistent with existing modules.
- No sensitive logging of full tokens (follow redaction patterns in `contentstackError`).

## Dependencies and security

- New dependencies need justification; run/license alignment with MIT stack.
- Be mindful of supply-chain risk for install scripts and pinned ranges.

## Tests

- **Unit:** Extend `test/unit/` for logic in `lib/`.
- **Sanity:** Only when live API checks are required—document env vars; do not commit credentials.
- TypeScript samples: update `test/typescript/` when public types warrant it.

## Severity (optional)

| Level | Examples |
|-------|----------|
| **Blocker** | Broken default auth, security regression of tokens, published API removed without major bump |
| **Major** | Missing tests for new behavior, incorrect error mapping, wrong docs that mislead CDA vs Marketplace |
| **Minor** | JSDoc nits, internal naming, non-user-facing refactor |
31 changes: 31 additions & 0 deletions .cursor/rules/contentstack-javascript-marketplace.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
description: Marketplace / Developer Hub SDK — auth, host, HTTP behavior in lib/
globs: lib/**
alwaysApply: false
---

# Contentstack Marketplace SDK (`lib/`)

This package is a **Marketplace (Developer Hub) management** client, not **CDA** and not generic **stack CMA content** APIs. Terminology and docs should say **Marketplace**, Developer Hub, apps, installations, hosting, OAuth as appropriate—avoid implying Delivery or stack entry CRUD unless adding a new surface that truly uses those APIs.

## Client bootstrap

- **`lib/contentstack.js` — `client(params)`:** Builds axios-based HTTP client via `contentstackHTTPClient`, merges `authtoken` / `authorization` into headers, sets `X-User-Agent` / `User-Agent` (includes `contentstack-marketplace-sdk/<version>`). Default hostname comes from `@contentstack/utils` `getContentstackEndpoint(region, 'developerHub', true)`.
- **`Region`:** `lib/core/region.js` — `eu`, `na` (empty string), `azure-na`, `azure-eu`, `gcp-na`. Pass via `params.region` (lowercased internally).

## Auth patterns (actual usage)

- Headers: `authtoken` and/or `authorization` (e.g. OAuth bearer) on the axios instance.
- **`contentstackClient.login`:** POST to `/v3/user-session` (host varies by `region` / `host`); stores returned `authtoken` on `http.defaults.headers.common`.
- **`refreshToken`:** Optional callback in `client()` params (see JSDoc in `contentstack.js`) for token rotation.
- **Marketplace calls:** `client.marketplace(orgUid)` → `lib/marketplace/**` (apps, installation, hosting, webhooks, OAuth helpers, authorization, app requests).

## HTTP layer

- **`lib/core/contentstackHTTPClient.js`:** Axios instance, default `timeout` 30000, `retryOnError` true, default `retryCondition` retries on **HTTP 429**. Uses `Qs` for `paramsSerializer` (including encoded `query` JSON). `versioningStrategy: 'path'`.
- **Concurrency:** `lib/core/concurrency-queue.js` caps parallel requests (`maxRequests`).
- **Errors:** Responses go through `lib/core/contentstackError.js` — enriches thrown `Error` with `status`, `errorMessage`, `errorCode`, `errors`, sanitized headers.

## Official docs alignment

Relate behavior to **Developer Hub / Marketplace** and **user session** documentation on [contentstack.com/docs](https://www.contentstack.com/docs), not to **CDA** delivery references unless the code explicitly integrates delivery tokens for a marketplace feature.
33 changes: 33 additions & 0 deletions .cursor/rules/dev-workflow.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
description: Branches, lint/tests, PR and release expectations for marketplace-sdk
globs: "**/*"
alwaysApply: false
---

# Dev workflow

## Branching

Follow team/GitHub conventions (feature branches, PRs to default branch). Use ticket IDs in branch names when required by the team (e.g. `feat/DX-5383-...`).

## Local quality gate

1. `npm run lint` — ESLint on `lib/` and `test/`.
2. `npm run test:unit` — Mocha + NYC (triggers `pretest`: cleans coverage and runs lint).
3. Optional: `npm run test:typescript` for Jest TS samples.

CI runs `npm ci` and `npm run test:unit:report:json` (see `.github/workflows/unit-test.yml`).

## PR expectations

- Unit tests updated or added for behavioral changes in `lib/`.
- No committed secrets; sanity fixtures stay out of version control if they contain tokens.
- Match existing Standard JS style and JSDoc depth on public APIs.

## Releases

Version lives in `package.json`. `prepare` runs `npm run build` on install/publish—ensure the `dist/` build succeeds before tagging. Coordinate npm release process with maintainers (changelog, semver).

## Known script gap

Root `npm test` references a non-existent `test:api` script; use `npm run test:unit` until `test:api` is defined.
27 changes: 27 additions & 0 deletions .cursor/rules/javascript.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
description: JavaScript source layout, ESLint Standard, logging for marketplace-sdk
globs: "**/*.{js,ts}"
alwaysApply: false
---

# JavaScript (lib / test / types)

## Language and layout

- **Source:** `lib/` — ES modules (`import`/`export`). Built outputs in `dist/` (Webpack + Babel); do not hand-edit `dist/`.
- **Tests:** Mocha + Chai in `test/unit/` and `test/sanity-check/`; Jest + TypeScript samples in `test/typescript/`.
- **Types:** Hand-maintained declarations under `types/` (e.g. `types/contentstackClient.d.ts`, `types/marketplace/**`).

## Style

- **ESLint:** `extends: 'standard'` (`.eslintrc.js`), `ecmaVersion: 2020`, `sourceType: 'module'`.
- Prefer explicit, readable names; avoid drive-by reformatting unrelated code.

## Logging

- HTTP logging hooks: `lib/core/messageHandler.js` (`httpLogHandler` referenced from `contentstackHTTPClient`).
- When adding diagnostics, follow existing patterns—do not replace with ad-hoc `console` in core paths unless consistent with `logHandler` usage.

## Dependencies (declared)

Runtime: `axios`, `@contentstack/utils`. Keep `package.json` accurate when adding imports.
35 changes: 35 additions & 0 deletions .cursor/rules/testing.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
description: Mocha, Jest, sanity tests, env vars for marketplace-sdk
globs: test/**
alwaysApply: false
---

# Testing

## Unit tests (Mocha + NYC)

- **Entry:** `test/unit/index.js` requires individual `*-test.js` files.
- **Command:** `npm run test:unit` (30s timeout, `BABEL_ENV=test`, `@babel/register`, `babel-polyfill`).
- **Coverage:** NYC HTML + text; clover for `test:unit:report:json` (CI).
- **Mocks:** `test/unit/mock/**`, `axios-mock-adapter`, `nock`, `sinon` as used in existing tests.

## TypeScript / Jest

- **Config:** `jest.config.js` — `ts-jest`, coverage to `coverage/`, tests under `test/typescript/` (`*.test.ts`, etc.).
- **Command:** `npm run test:typescript`.

## Sanity / integration-style (live API)

- **Entry:** `test/sanity-check/sanity.js` requires API suites under `test/sanity-check/api/`.
- **Command:** `npm run test:sanity-test` (or `test:sanity` which swallows failures—avoid for strict gates).
- **Env:** `dotenv` loads `.env`. Examples from existing specs: `ORG_UID`, `HOST`, `DEFAULTHOST`, `ADMIN_EMAIL`, `USER_EMAIL`, `EMAIL`, `PASSWORD`. Utility client: `test/sanity-check/utility/ContentstackClient.js` (`host`, `defaultHostName` from env).
- **Fixtures:** JSON read/write in `test/sanity-check/utility/fileOperations/readwrite.js` (e.g. `loggedinAdmin.json`) — treat as local secrets; never commit populated files.

## Naming

- Unit: `*-test.js` beside concepts (`marketplace-test.js`, `ContentstackHTTPClient-test.js`).
- Sanity: `*-test.js` or descriptive names under `test/sanity-check/api/`.

## Pretest

`npm run test:unit` runs `pretest` (`rimraf coverage` + `npm run lint`) unless invoked with `--ignore-scripts`—account for lint when debugging failing tests.
58 changes: 58 additions & 0 deletions .github/workflows/back-merge-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Back-merge main to development

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read
pull-requests: write

jobs:
open-back-merge-pr:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Open back-merge PR if needed
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
BASE_BRANCH="development"
SOURCE_BRANCH="main"

git fetch origin "$BASE_BRANCH" "$SOURCE_BRANCH"

SOURCE_SHA=$(git rev-parse "origin/$SOURCE_BRANCH")
BASE_SHA=$(git rev-parse "origin/$BASE_BRANCH")

if [ "$SOURCE_SHA" = "$BASE_SHA" ]; then
echo "$SOURCE_BRANCH and $BASE_BRANCH are at the same commit; nothing to back-merge."
exit 0
fi

EXISTING=$(gh pr list --repo "${{ github.repository }}" \
--base "$BASE_BRANCH" \
--head "$SOURCE_BRANCH" \
--state open \
--json number \
--jq 'length')

if [ "$EXISTING" -gt 0 ]; then
echo "An open PR from $SOURCE_BRANCH to $BASE_BRANCH already exists; skipping."
exit 0
fi

gh pr create --repo "${{ github.repository }}" \
--base "$BASE_BRANCH" \
--head "$SOURCE_BRANCH" \
--title "chore: back-merge main into development" \
--body "Automated back-merge after changes landed on \`main\`. Review and merge to keep \`development\` in sync."

echo "Created back-merge PR $SOURCE_BRANCH -> $BASE_BRANCH."
86 changes: 86 additions & 0 deletions .github/workflows/check-version-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Check Version Bump

on:
pull_request:

jobs:
version-bump:
name: Version & Changelog bump
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Detect changed files and version bump
id: detect
run: |
if git rev-parse HEAD^2 >/dev/null 2>&1; then
FILES=$(git diff --name-only HEAD^1 HEAD^2)
else
FILES=$(git diff --name-only HEAD~1 HEAD)
fi
VERSION_FILES_CHANGED=false
echo "$FILES" | grep -qx 'package.json' && VERSION_FILES_CHANGED=true
echo "$FILES" | grep -qx 'CHANGELOG.md' && VERSION_FILES_CHANGED=true
echo "version_files_changed=$VERSION_FILES_CHANGED" >> $GITHUB_OUTPUT
# Only lib/, webpack/, dist/, package.json count as release-affecting; .github/ and test/ do not
CODE_CHANGED=false
echo "$FILES" | grep -qE '^lib/|^webpack/|^dist/' && CODE_CHANGED=true
echo "$FILES" | grep -qx 'package.json' && CODE_CHANGED=true
echo "code_changed=$CODE_CHANGED" >> $GITHUB_OUTPUT

- name: Skip when only test/docs/.github changed
if: steps.detect.outputs.code_changed != 'true'
run: |
echo "No release-affecting files changed (e.g. only test/docs/.github). Skipping version-bump check."
exit 0

- name: Fail when version bump was missed
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed != 'true'
run: |
echo "::error::This PR has code changes but no version bump. Please bump the version in package.json and add an entry in CHANGELOG.md."
exit 1

- name: Setup Node
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
uses: actions/setup-node@v4
with:
node-version: '22.x'

- name: Check version bump
if: steps.detect.outputs.code_changed == 'true' && steps.detect.outputs.version_files_changed == 'true'
run: |
set -e
PKG_VERSION=$(node -p "require('./package.json').version.replace(/^v/, '')")
if [ -z "$PKG_VERSION" ]; then
echo "::error::Could not read version from package.json"
exit 1
fi
git fetch --tags --force 2>/dev/null || true
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true)
if [ -z "$LATEST_TAG" ]; then
echo "No existing tags found. Skipping version-bump check (first release)."
exit 0
fi
LATEST_VERSION="${LATEST_TAG#v}"
LATEST_VERSION="${LATEST_VERSION%%-*}"
if [ "$(printf '%s\n' "$LATEST_VERSION" "$PKG_VERSION" | sort -V | tail -1)" != "$PKG_VERSION" ]; then
echo "::error::Version bump required: package.json version ($PKG_VERSION) is not greater than latest tag ($LATEST_TAG). Please bump the version in package.json."
exit 1
fi
if [ "$PKG_VERSION" = "$LATEST_VERSION" ]; then
echo "::error::Version bump required: package.json version ($PKG_VERSION) equals latest tag ($LATEST_TAG). Please bump the version in package.json."
exit 1
fi
CHANGELOG_VERSION=$(sed -nE 's/^## \[v?([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' CHANGELOG.md | head -1)
if [ -z "$CHANGELOG_VERSION" ]; then
echo "::error::Could not find a version entry in CHANGELOG.md (expected line like '## [v1.0.0](...)')."
exit 1
fi
if [ "$CHANGELOG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::CHANGELOG version mismatch: CHANGELOG.md top version ($CHANGELOG_VERSION) does not match package.json version ($PKG_VERSION). Please add or update the CHANGELOG entry for $PKG_VERSION."
exit 1
fi
echo "Version bump check passed: package.json and CHANGELOG.md are at $PKG_VERSION (latest tag: $LATEST_TAG)."
20 changes: 0 additions & 20 deletions .github/workflows/check_branch.yml

This file was deleted.

43 changes: 43 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Contentstack Marketplace SDK – Agent guide

**Universal entry point** for contributors and AI agents. Detailed conventions live in **`skills/*/SKILL.md`**.

## What this repo is

| Field | Detail |
|--------|--------|
| **Name:** | [contentstack-marketplace-sdk](https://github.com/contentstack/contentstack-marketplace-sdk) (`@contentstack/marketplace-sdk`) |
| **Purpose:** | Node/browser SDK for managing Contentstack **Marketplace** app content and related APIs. |
| **Out of scope:** | Not the core Delivery/Management content APIs for arbitrary stacks—scope changes belong to product requirements. |

## Tech stack (at a glance)

| Area | Details |
|------|---------|
| Language | JavaScript (Babel transpilation); TypeScript tests via Jest (`test/typescript`) |
| Build | Webpack configs under **`webpack/`**; outputs under **`dist/`** (`npm run build`) |
| Tests | Mocha + NYC for unit/API tests; `npm run test:typescript` for Jest subset |
| Lint / coverage | ESLint on `lib` and `test` (`npm run lint`); NYC coverage |
| CI | `.github/workflows/unit-test.yml`, `check_branch.yml`, `sca-scan.yml`, `policy-scan.yml`, `npm-publish.yml` |

## Commands (quick reference)

| Command type | Command |
|--------------|---------|
| Build | `npm run build` |
| Test | `npm test` (runs API + unit per `package.json`) |
| Lint | `npm run lint` |

## Where the documentation lives: skills

| Skill | Path | What it covers |
|-------|------|----------------|
| **Development workflow** | [`skills/dev-workflow/SKILL.md`](skills/dev-workflow/SKILL.md) | npm scripts, Husky, CI |
| **Marketplace SDK** | [`skills/marketplace-sdk/SKILL.md`](skills/marketplace-sdk/SKILL.md) | Public API in `lib/`, axios usage |
| **JavaScript tooling** | [`skills/javascript/SKILL.md`](skills/javascript/SKILL.md) | Babel, Webpack targets, dual builds |
| **Testing** | [`skills/testing/SKILL.md`](skills/testing/SKILL.md) | Mocha, NYC, Jest, fixtures |
| **Code review** | [`skills/code-review/SKILL.md`](skills/code-review/SKILL.md) | PR checklist |

## Using Cursor (optional)

If you use **Cursor**, [`.cursor/rules/README.md`](.cursor/rules/README.md) only points to **`AGENTS.md`**—same docs as everyone else.
Loading
Loading