Addressing pre-release checks - #1
Merged
Merged
Conversation
Surfaces npm registry links and ecosystem trust signals (provenance, "Repository" link on npmjs.com) that the placeholder repo metadata blocked.
Some bundlers, tsx, and require-subpath consumers need explicit access to package.json. Without this entry, modern resolution rejects the lookup.
Aligns with Node 20+ runtime, lib: ES2022, and tsup target node20. The previous ES2020 target downlevelled features (eg. Error.cause, .at()) the SDK already relies on for AbortSignal.timeout-style usage.
Node 24 is the current LTS-track release as of 2025; macOS and Windows exercise platform-specific fetch and crypto.subtle behaviors that have historically diverged from Linux.
@vitest/coverage-v8 was a dev dep but never executed. Adds test:coverage script, vitest config block (v8 provider, lcov/html reporters), and a single-OS CI step that uploads to Codecov on Linux Node 22.
attw catches type-resolution drift but publint catches a separate class of package.json/exports issues (bin paths, dual-package hazards, missing engines fields). Both should run before publish.
Weekly schedule, dev deps grouped to reduce PR noise, separate ecosystem for github-actions to keep workflow runners current.
The only setting (onlyBuiltDependencies) is already declared in package.json under pnpm.onlyBuiltDependencies. The workspace file with no actual workspaces was a confusing leftover.
Changesets will overwrite the body on each release; an initial stub keeps README links and the npm tarball deterministic.
Documents the security@pdfmonkey.io reporting channel, supported version window, and acknowledgement SLAs. Required for an "Official" SDK to give researchers a clear path that does not involve a public GitHub issue.
Documents the local toolchain, scripts, Changesets workflow, and the zero-runtime-dependencies invariant so external contributors do not need to read the source to onboard.
Standard text with conduct@pdfmonkey.io as the reporting channel. GitHub surfaces this file in the community profile and exposes it to contributors during issue/PR creation.
Bug and feature YAML forms with required SDK and Node version fields, plus a contact-links config that disables blank issues and routes security and product questions away from the SDK tracker. PR template codifies the lint/typecheck/test/build/changeset gates already enforced in CI.
Wires changesets/action to either open a release PR or publish a tagged version when the PR merges. id-token: write enables OIDC trusted publishing and NPM_CONFIG_PROVENANCE=true makes npm record build provenance against the GitHub Actions run.
Standalone files for the most-asked patterns: ESM and CJS quickstart, generateSync, async-iterating pages, Express raw-body webhook, and a Next.js App Router route handler. Also excludes examples and the local-tooling directories (.wolf, .omc) from Biome so the lint scope stays at src and config files.
Matches the Stripe/OpenAI/Anthropic pattern: callers can do
`new PDFMonkey()` and pick up the credential from the environment, or
`new PDFMonkey({ timeout: 5_000 })` and inherit the key while
overriding other options. Explicit apiKey still wins.
PDFMonkeyError prints as "Name: message"; APIError adds the HTTP status and request id. Stops console.log/REPL output from dumping the noisy default Error shape with stack and headers.
Stripe-style UA: "pdfmonkey-node/X.Y.Z node/20.11.0 darwin x64". Lets PDFMonkey support diagnose runtime-specific reports without a full repro. Falls back to "pdfmonkey-node/X.Y.Z" alone on edge runtimes where process is unavailable.
Per-request headers merge on top of defaultHeaders but never replace Authorization or User-Agent. idempotencyKey is forwarded to the Idempotency-Key header — the standard way to make POSTs safe to retry across PDFMonkey's create endpoints.
Adds a ResourceRequestOptions type (signal, timeout, maxRetries, headers, idempotencyKey) and a trailing options argument on every public method across documents, document-cards, document-templates, rest-hooks, snippets, template-folders, workspaces, current-user, and pdf-engines. Resources never set body or query through this surface — those remain controlled by each method. waitForGeneration now forwards its signal to the inner get call so an abort interrupts the polling fetch instead of waiting for the next sleep window.
Replaces the inline 120_000 magic number in generateSync and exports the constant from the public surface so callers can reference the same value when wrapping the SDK in their own retry/timeout policies.
Doubles the poll interval up to maxInterval (default 10s) instead of a fixed 2s loop. Existing interval semantics are preserved (used as the starting point); maxInterval === interval disables backoff for callers that want a constant cadence.
getPage(n) jumps to an arbitrary page number with explicit out-of-range checks; pages() yields each Page in order, complementing the existing item-level Symbol.asyncIterator. Useful for bulk imports that want to process or count pages rather than items.
create/update/generateSync now accept a DocumentPayload (string or any JSON value) and JSON-serialise objects/arrays before sending. Strings still pass through verbatim to support callers that already do their own templating. Removes the boilerplate JSON.stringify on every call that the previous string-only signature forced.
The asymmetry between input (object or string accepted, auto-stringified) and output (always a string) forced callers to write JSON.parse on every read. parseMeta normalises to DocumentMeta | null and tolerates malformed or non-object payloads instead of throwing.
WebhookEvent now narrows on `type` to DocumentDoneEvent (data has download_url, filename) or DocumentErrorEvent (data has failure_cause), with an UnknownWebhookEvent fallback for forward compatibility. Removes the cast users previously needed to read event.data fields after a verifyWebhook call.
Captures the design constraint (Web-Crypto-only for edge runtime support) so a later contributor does not "simplify" the function to node:crypto.timingSafeEqual or a plain string compare.
Each extends InternalServerError so existing instanceof InternalServerError checks keep matching. Lets callers distinguish "PDFMonkey edge said upstream timed out" (504) from a generic 5xx and pick a different retry strategy.
Lets callers inject signing headers (mutate ctx.headers in onRequest), ship metrics on every response, or wrap transport errors before they become APIConnectionError. Each hook is awaited so async work composes cleanly with retries; the response handed to onResponse is cloned so the consumer's body stream does not race with the SDK's parser.
download() returns the PDF as Uint8Array; downloadStream() exposes the underlying ReadableStream for piping to disk or HTTP responses. Both accept a Document object or a string id (fetches first), throw a clear error when download_url is null, and accept an options.fetch override for proxying or custom transports.
The default toJSON() preserves the response body for debugging, but the body can contain user-supplied payloads or PII. toJSONRedacted() returns name/message/status/requestId only — safe to ship to observability pipelines without an extra mask step.
Callers can now plug in their own backoff (linear, fixed, jittered, or "never sleep" for tests) without wrapping the SDK. The previous fixed exponential-backoff-with-full-jitter implementation is the default.
Six resource list() implementations were re-implementing the same "if param defined → q[name] = value" loop with subtle drift potential. buildListQuery centralises filter, page, and sort handling so adding a new filter is a one-line entry instead of a copy-paste.
PDFMonkey constructor, Page, Documents.create/generateSync/waitForGeneration, and verifyWebhook now ship inline usage snippets that surface in the IDE hover. Targeted at the calls a new user reaches for first; deeper methods stay TSDoc-light to avoid maintenance churn.
Adds badges, edge-runtime support note, env var fallback, per-request options block, retryDelay/hooks examples, download/downloadStream, parseMeta, and discriminated-union webhook narrowing. Drops the manual JSON.stringify boilerplate from payload examples now that the SDK auto-serialises objects. Calls out the absence of documents.list (use documentCards.list) and the PUT-only update semantics.
Drops @vitest/coverage-v8, the test:coverage script, the vitest coverage block, the CI coverage + Codecov-upload steps, and the .nyc_output gitignore entry. Coverage was not load-bearing — the value did not justify the dependency surface and extra CI minutes.
The examples/ directory duplicated the README: quickstart, generateSync, and pagination snippets were identical, and the CJS variant only differed by a require() call. The two genuine gotchas — Express needing express.raw to preserve the webhook payload, and Next.js App Router needing an explicit runtime — are now folded into a "Framework recipes" subsection under Webhooks. Single source of truth, less drift surface.
Drops 9 tests that either duplicated existing coverage or tested trivial branches with no realistic regression path: - env var fallback: removes "explicit wins" and "throws when env unset" cases, kept the positive path - error inspect: removes the no-requestId variant, kept the with-id case - Idempotency-Key: removes the absence-check, kept the present-check - documents.get signal abort: removed (duplicates client-level test) - parseMeta non-object cases: removed (basic + null + invalid already cover the branch logic) - 5xx subclasses: kept the 502 mapping as the representative test, dropped the 503/504/500-not-BadGateway repeats Net 203 tests, all passing.
simonc
force-pushed
the
pre-release-checks
branch
from
May 11, 2026 21:21
5db77ee to
2f333c6
Compare
PDFMonkey API does not honour the Idempotency-Key header, so exposing the option implied a retry-safety contract that does not exist — strictly worse than nothing. Per-request `headers` overlapped with the onRequest hook (the canonical place to inject dynamic headers like trace IDs), so it was a second way to do the same thing. ResourceRequestOptions now shrinks to signal/timeout/maxRetries — the options that actually map to client behaviour. README updated to point header-injection use cases at the onRequest hook.
PDFMonkey templates bind named keys (e.g. {{ name }}, {{ items }}), so
the top-level payload must be an object. Allowing `unknown[]` advertised
a contract the API rejects.
#resolveDownloadUrl previously fetched the full Document just to read download_url + status + id — fields a DocumentCard already exposes. The card endpoint returns a much smaller payload. Public download() and downloadStream() now also accept a DocumentCard so callers who already have one from a list iteration skip the fetch entirely. No other internal hot paths fall in the "fetch full doc, read few fields" pattern (waitForGeneration returns the full Document to the caller and stays as-is).
simonc
commented
May 12, 2026
- Bump biome.json schema to 2.4.13 to match installed CLI - Apply biome auto-fix on three test files (trailing blank lines, array reflow) - Switch author/security contact to tinymonkey@pdfmonkey.io - Add Node 26 to CI matrix
Windows runners checked out CRLF, biome formatter requires LF.
biome's useIgnoreFile reads only the project .gitignore (not the global one), so .wolf and .omc need to live in the local file. With them there, the redundant !!**/dist, !!**/node_modules, !!**/coverage, !!**/.wolf and !!**/.omc entries can go.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pre-release housekeeping for the
pdfmonkeynpm package. Brings the repo up to publishable state across packaging, CI, public-facing docs, and SDK surface.Packaging
repository,bugs,homepage, andauthor(tinymonkey@pdfmonkey.io) topackage.json./package.jsonsubpath to theexportsmappnpm-workspace.yamlCHANGELOG.mdin the published tarballCI / release tooling
publintandattwtoprepublishOnlyand CI.gitattributesbiome.jsonincludes by relying on.gitignoreRepo hygiene
SECURITY.mdwith disclosure policy (contact:tinymonkey@pdfmonkey.io)CONTRIBUTING.mdwith setup and PR workflowCHANGELOG.mdstubSDK surface
PDFMONKEY_API_KEYenv var whenapiKeyis omittednodejs.util.inspect.customto error classesUser-Agentwith Node version, platform, and archResourceRequestOptionsthrough every resource methodDEFAULT_SYNC_TIMEOUTconstantwaitForGenerationPage.getPage(n)andPage.pages()helpersDocumentPayloadto drop the array formparseMetahelper for the read-side ofDocument.metaWebhookEventconstantTimeEqualuses double-HMACBadGateway,ServiceUnavailable,GatewayTimeouterror subclassesonRequest/onResponse/onErrorclient hooksDocuments.downloadandDocuments.downloadStreamhelpers (resolves URL viadocument_cards.get)APIError.toJSONRedactedfor safe log forwardingretryDelaystrategy as aClientOptionshookbuildListQueryhelper from list endpointsDocs
@exampleblocks to top-level public surfaces