npm.io
0.1.1 • Published yesterday

@edvizion/pdfs

Licence
UNLICENSED
Version
0.1.1
Deps
1
Size
53 kB
Vulns
0
Weekly
0

@edvizion/pdfs

TypeScript SDK and shared contract for edvizion-pdfs, Edvizion's PDF template rendering service.

This package is internal. It is published to the public npm registry for convenience of installation, not for general use. It is a client for a private Cloudflare Worker that is not publicly reachable — without access to Edvizion's infrastructure, this package cannot do anything useful.

There is no public API, no hosted demo, and no support for outside use.

What it is

The service stores per-organization PDF templates and renders them into PDFs. This package is the client for it, over either transport:

  • Service binding — Worker-to-Worker RPC. Trusted caller, no JWT.
  • HTTP — Bearer JWT, for callers outside the Cloudflare account.

Both expose the same methods, the same arguments, and the same error classes. Moving a caller between transports is an import change.

It also carries the contract: the zod schemas, TypeScript types, and error codes that the service itself validates against. Those are defined once and shared, so the client and the service cannot disagree about a payload shape without a compile error.

Access requirements

Transport Requires
@edvizion/pdfs/binding a Worker in the same Cloudflare account as edvizion-pdfs
@edvizion/pdfs (HTTP) an AuthKit access token carrying an org_id claim and the right scope

Service bindings are account-scoped, so the binding transport is unavailable outside Edvizion's account. The HTTP endpoint is deployed but every route except /health and /openapi.json requires a verified token.

Install

npm i @edvizion/pdfs

Quick start

Service binding — add to the calling Worker's wrangler.jsonc:

"services": [
  { "binding": "PDFS", "service": "edvizion-pdfs", "entrypoint": "PDFService" }
]
import { pdfs } from "@edvizion/pdfs/binding";

const client = pdfs(env.PDFS, { tenantID: org.id, userID: user.id });

const bytes = await client.generate({
  templateID: "tpl_standard_record_request",
  type: "record-request",
  payload,
});

HTTP:

import { PDFClient } from "@edvizion/pdfs";

const client = new PDFClient({
  baseURL: "https://api.edvizion.com/pdf",
  token: () => getAccessToken(),
});

const bytes = await client.generate({ templateID, type: "record-request", payload });

entrypoint: "PDFService" is required on the binding — omitting it binds the JWT-protected HTTP handler instead, and every call fails on auth.

Exports

Import Contents Runs in
@edvizion/pdfs PDFClient — HTTP transport Workers, Node, browser
@edvizion/pdfs/binding pdfs(), PDFBindingClient, PDFServiceBinding Workers only
@edvizion/pdfs/contract types, zod schemas, error classes, PDFServiceContract anywhere

The contract is re-exported from both transport entry points, so importing it separately is only necessary when you want types without a client.

Documentation

SKILL.md ships with this package and is the complete integration guide: setup, every method, payload contracts, the error table, Liquid template authoring, and testing guidance. It is written to be handed directly to a coding agent — drop it at .claude/skills/edvizion-pdfs/SKILL.md in the consuming repo.

Errors

Both transports throw the same typed errors, rebuilt from a shared error code:

import { TemplateNotFoundError, InvalidTemplatePayloadError } from "@edvizion/pdfs/contract";

try {
  await client.generate({ templateID, payload });
} catch (error) {
  if (error instanceof InvalidTemplatePayloadError) return badRequest(error.issues);
  if (error instanceof TemplateNotFoundError) return notFound();
  throw error;
}

Cross-tenant access returns template_not_found, never a permission error — a response must never reveal that another organization's template exists.

Testing against it

The service is fully unit tested on its own. Consuming apps should test their own logic, not re-verify the service's rules. The binding is a plain structural interface with no Cloudflare types, so stubbing it needs nothing but an object literal:

const stub = { generate: vi.fn(), /* … */ } satisfies PDFServiceBinding;
const client = pdfs(stub, { tenantID: "org_a", userID: "user_a" });

A stub will accept calls the real service rejects. That is expected — a unit test against a double is not an integration test. See SKILL.md.

Versioning

This package and the deployed Worker share the contract, so they are released together. Adding a template type is additive and safe to roll out in either order. Changing an existing payload schema is breaking — tightening a field rejects payloads that previously worked — and requires publishing the SDK and deploying the Worker in lockstep.

License

UNLICENSED — proprietary to Edvizion. Published publicly for installation convenience; no rights are granted for outside use.