diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..12fb7ad --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,165 @@ +# Forgejo CI mirror — git.ariccamarata.com +# Mirrors .github/workflows/ci.yml for the self-hosted Forgejo Actions runner. +# Keep in sync with the GitHub workflow; only addition is the nSentry failure step. +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + matrix: + node-version: [20, 22, 24] + steps: + - uses: actions/checkout@v4 + - name: Enable corepack + run: corepack enable + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: pnpm + + + - run: pnpm install --frozen-lockfile + + - name: Build TypeScript + run: pnpm run build + + - name: Run tests (ESM) + run: node --test test.mjs + + - name: Run tests (CJS) + run: node --test test-cjs.cjs + + - name: Report failure to nSentry + if: failure() + run: | + # nself sentry ci enable must be run on the CamClaw server first. + # Once registered, the runner's nself-sentry-sync hook delivers this report + # to ~/Sites/acamarata/.claude/inbox via root@sentry-errors.ariccamarata.com. + echo "CI_FAILURE repo=${{ github.repository }} job=${{ github.job }} run=${{ github.run_id }}" >&2 + + typecheck: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - name: Enable corepack + run: corepack enable + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + + - run: pnpm install --frozen-lockfile + - run: pnpm run typecheck + + - name: Report failure to nSentry + if: failure() + run: | + # nself sentry ci enable must be run on the CamClaw server first. + # Once registered, the runner's nself-sentry-sync hook delivers this report + # to ~/Sites/acamarata/.claude/inbox via root@sentry-errors.ariccamarata.com. + echo "CI_FAILURE repo=${{ github.repository }} job=${{ github.job }} run=${{ github.run_id }}" >&2 + + lint: + name: Lint & Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Enable corepack + run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm run lint + - run: pnpm run format:check + - name: Report failure to nSentry + if: failure() + run: | + # nself sentry ci enable must be run on the CamClaw server first. + # Once registered, the runner's nself-sentry-sync hook delivers this report + # to ~/Sites/acamarata/.claude/inbox via root@sentry-errors.ariccamarata.com. + echo "CI_FAILURE repo=${{ github.repository }} job=${{ github.job }} run=${{ github.run_id }}" >&2 + + pack-check: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - name: Enable corepack + run: corepack enable + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + + - run: pnpm install --frozen-lockfile + - run: pnpm run build + + - name: Verify package contents + run: | + npm pack --dry-run 2>&1 | tee pack-output.txt + for f in dist/index.cjs dist/index.mjs dist/index.d.ts dist/index.d.mts lib/spa.js README.md CHANGELOG.md LICENSE; do + grep -qE "(^|[[:space:]])${f}([[:space:]]|$)" pack-output.txt || { echo "MISSING: $f"; exit 1; } + done + echo "All expected files present in package" + + - name: Report failure to nSentry + if: failure() + run: | + # nself sentry ci enable must be run on the CamClaw server first. + # Once registered, the runner's nself-sentry-sync hook delivers this report + # to ~/Sites/acamarata/.claude/inbox via root@sentry-errors.ariccamarata.com. + echo "CI_FAILURE repo=${{ github.repository }} job=${{ github.job }} run=${{ github.run_id }}" >&2 + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Enable corepack + run: corepack enable + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm run build + + - name: Coverage + run: pnpm run coverage + + - name: Upload to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./coverage/lcov.info + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: false + + - name: Report failure to nSentry + if: failure() + run: | + # nself sentry ci enable must be run on the CamClaw server first. + # Once registered, the runner's nself-sentry-sync hook delivers this report + # to ~/Sites/acamarata/.claude/inbox via root@sentry-errors.ariccamarata.com. + echo "CI_FAILURE repo=${{ github.repository }} job=${{ github.job }} run=${{ github.run_id }}" >&2 diff --git a/README.md b/README.md index 7cf110f..4174d7d 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,7 @@ The core algorithm is a JavaScript port of the NREL SPA by Ibrahim Reda and Afsh ## License MIT (TypeScript wrapper and build tooling). The core algorithm in `lib/spa.js` is a port of NREL's SPA C source, subject to its own terms. See [LICENSE](./LICENSE). + +## Telemetry + +This package supports optional, anonymous usage telemetry via [`@acamarata/telemetry`](https://github.com/acamarata/telemetry). It is **off by default**. See [TELEMETRY.md](https://github.com/acamarata/telemetry/blob/main/TELEMETRY.md) for what is collected and how to enable or disable it. diff --git a/TELEMETRY.md b/TELEMETRY.md new file mode 100644 index 0000000..99cfaa4 --- /dev/null +++ b/TELEMETRY.md @@ -0,0 +1,8 @@ +# Telemetry Disclosure + +This package supports opt-in anonymous usage telemetry via [`@acamarata/telemetry`](https://github.com/acamarata/telemetry). + +Telemetry is **off by default**. No data is sent unless you set `ACAMARATA_TELEMETRY=1`. + +Full disclosure (what is sent, where it goes, how to disable): +[github.com/acamarata/telemetry/blob/main/TELEMETRY.md](https://github.com/acamarata/telemetry/blob/main/TELEMETRY.md) diff --git a/package.json b/package.json index d9ab5e9..cb742de 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "devDependencies": { "@acamarata/eslint-config": "^0.1.0", "@acamarata/prettier-config": "^0.1.0", + "@acamarata/telemetry": "^0.1.0", "@acamarata/tsconfig": "^0.1.0", "@eslint/js": "^10.0.1", "@types/node": "^25.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a75d367..e801109 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@acamarata/prettier-config': specifier: ^0.1.0 version: 0.1.0(prettier@3.8.1) + '@acamarata/telemetry': + specifier: ^0.1.0 + version: 0.1.0 '@acamarata/tsconfig': specifier: ^0.1.0 version: 0.1.0 @@ -81,6 +84,10 @@ packages: peerDependencies: prettier: '>=3.0.0' + '@acamarata/telemetry@0.1.0': + resolution: {integrity: sha512-iP09ZD0bHencHLbv6kQZDgwN9crLCWGKxmiMrfJjhBCoWTgv4koSgg0Li/LFKwCCFluua6orj9fVeQ8eqcJXSQ==} + engines: {node: '>=20'} + '@acamarata/tsconfig@0.1.0': resolution: {integrity: sha512-bgzyBak43mE+0HhduZX3cvaPjKcggtGGZZMjr35qtYWolsIWgZ9nx7OOswbVYoU35qoUv6rZ0mTK6GbZ8QTYjw==} engines: {node: '>=20'} @@ -1225,6 +1232,8 @@ snapshots: dependencies: prettier: 3.8.1 + '@acamarata/telemetry@0.1.0': {} + '@acamarata/tsconfig@0.1.0': {} '@bcoe/v8-coverage@1.0.2': {} diff --git a/src/index.ts b/src/index.ts index b487122..44b7b0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -367,3 +367,12 @@ export function calcSpa( sunset: formatTime(raw.sunset), }; } + +// ── Opt-in anonymous telemetry ──────────────────────────────────────────────── +// Off by default. Enable: ACAMARATA_TELEMETRY=1 +// What is sent + how to disable: https://github.com/acamarata/telemetry/blob/main/TELEMETRY.md +import("@acamarata/telemetry") + .then(({ track }) => track("load", { package: "nrel-spa", version: "2.0.2" })) + .catch(() => { + // telemetry not installed or disabled — that's fine + });