Implement PENPOT_URL/PENPOT_TOKEN resolution in src/env.ts with unit tests #187
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills#187
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implement
extensions/penpot/src/env.ts: resolve and normalise thePENPOT_URLbase URL and thePENPOT_TOKENpersonal access token from the environment, with actionable failure messages when either is missing or malformed. Pure functions, unit-tested withnode --test.Background
Depends on: #186
Every penpot tool call needs two environment values:
PENPOT_URL— the instance base URL, with no/apisuffix (e.g.https://penpot.example.com). Users routinely paste the UI URL or a URL ending in/api, and a stray suffix makes every RPC call 404, so this module normalises it rather than propagating the mistake.PENPOT_TOKEN— a Penpot personal access token. It is presented asAuthorization: Token <token>(notBearer). Tokens live in the per-machine environment (or.env);.envmust never be committed.Configuration is resolved at call time, not at extension load time, so a machine without Penpot configured still loads the extension cleanly. This mirrors the lazy-resolution pattern in
extensions/victorialogs/src/env.ts.This module is a prerequisite for the RPC client and every later read/write tool. It must stay dependency-free apart from
node:testin the co-located test file.Documentation Required
A separate process downloads these into the listed folder before this issue is implemented. Check the folder for the actual reference material before starting.
docs/reference/penpot-api//apisuffix), and the canonicalcurl -H "Authorization: Token <token>" https://design.penpot.app/api/rpc/command/get-profileexample. This is the authoritative source for what a validPENPOT_URLlooks like and which header scheme is used.<PENPOT_URL>/api/main/doc/openapi.json— the instance's own OpenAPI 3.0 spec (generated from Penpot source). Useful for confirming command paths are rooted at/api/rpc/command/; the full vendored copy is produced in the skill-content milestone.docs/reference/nodejs/process.envaccess and the fact that missing variables areundefined, not empty strings.Implementation Details
Create
extensions/penpot/src/env.tswith (at minimum) these pure, independently-testable pieces:normalizeBaseUrl(raw: string): string/./api(case-insensitive) that would otherwise be duplicated when the client appends/api/rpc/command/..../again after removing/api.https://host/penpot, must survive intact).resolveConfig(env: Record<string, string | undefined> = process.env)returning a discriminated result — for example{ ok: true, value: { baseUrl, token } } | { ok: false, error: string }— rather than throwing, so callers (and tests) can branch. Follow theResult-style shape already used inextensions/forgejo/src/errors.tsif that is convenient, but do not import forgejo code.Actionable error messages. Each failure names the variable and says what to do:
PENPOT_URL→ tell the user to set it to the instance base URL without the/apisuffix, and give a concrete example.PENPOT_TOKEN→ tell the user to create a personal access token in Penpot (account settings → access tokens) and export it asPENPOT_TOKEN.PENPOT_URL(failsnew URL(...)) → quote the offending value and restate the expected shape.Malformed-token guard is intentionally minimal — do not attempt to validate token format (Penpot tokens are opaque). Only reject empty/whitespace-only values.
Keep the module importable with zero third-party dependencies so tests run without
node_modules.Write co-located tests in
extensions/penpot/src/env.test.ts(orextensions/penpot/env.test.ts— pick the location used by the rest of this extension and stay consistent; the rootnpm testglob for this extension is registered in a later milestone).Acceptance Criteria
normalizeBaseUrlstrips a trailing/, a trailing/apiand a trailing/after that, and is idempotent.https://host/penpot) is preserved unchanged.resolveConfigreturns the normalised base URL and the token when both variables are set.PENPOT_URLproduces an actionable error naming the variable and the expected shape (no/apisuffix).PENPOT_TOKENproduces an actionable error naming the variable and how to obtain a token.PENPOT_URLproduces an error quoting the offending value rather than throwing a rawTypeError.node --test extensions/penpot/src/env.test.ts(or the chosen test path) is green.Test Plan
Manual sanity check that the module sees real environment values:
pi-loop opened and merged a pull request for this issue: #220