Skip to content

Release Next v3.0.0-next.18

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 29 Oct 14:37
· 257 commits to main since this release
3a88df9

@cloudpdf/contract@3.0.0-next.18

Minor Changes

  • #917 by @bobsingor – Add folders: folders.create, folders.list, folders.get (with the path
    above the folder), folders.update to rename, folders.moveInto to move
    documents and folders together, and folders.delete for empty folders. The
    top level is the place root. Document records carry folderId;
    documents.init and documents.importFrom take one, and documents.list
    filters by it. Folder conflicts answer 409 with details.reason.

  • #917 by @bobsingor – Documents have a name: set it with documents.init or documents.import
    (it defaults to the document id) and change it with the new documents.update
    operation, which needs the new docs.update tenant scope. documents.list
    gains q to search names ignoring case, sort (createdAt, name or
    size) and order, and no longer lists documents that are being deleted
    unless state=deleting asks for them.

  • #917 by @bobsingor – folders.delete takes recursive=true to delete a folder with everything in
    it. Without it, a folder that holds anything is still refused.

  • #917 by @bobsingor – Document operations accept tenant JWTs, which need the operation's document
    capabilities exactly as a document JWT does; no tenant scope reaches inside a
    document. A tenant token's scope now takes document capabilities next to
    tenant scopes, and they hold for every document of the tenant.
    documents.download needs doc.download and documents.thumbnail needs
    doc.render instead of docs.read. docs.update renames and moves, and never
    changes content.

Patch Changes

  • #910 by @bobsingor – The doc.versions.* operations take the layer: their paths are /v1/docs/:docId/layers/:layerName/versions…. doc.versions.list answers LayerVersions ({ baseSha, versions }): the layer's base and its versions, the upload first.

  • #909 by @bobsingor – Share links carry identity (who their visitors are, for a link made for one person) on the link record, shares.create and shares.update. Identity is a named component, shared with tokens.issue, so the SDKs have one type for it.

  • #910 by @bobsingor – The signature notes describe the new rule. A signature is made over the layer's own base, and its new version is that layer's own: the document and every other layer stay as they were. StaleBase is no longer an error code.

@cloudpdf/sdk@3.0.0-next.18

Minor Changes

  • #917 by @bobsingor – Add the folders client (create, list, get, update, moveInto,
    delete), a folderId option on documents.init, documents.importFrom,
    documents.list and uploads.create, and folderId on document records.

  • #917 by @bobsingor – Add documents.update for renaming documents, a name option on
    documents.init, documents.importFrom and uploads.create, and the q,
    sort and order options on documents.list. Document records now carry
    name.

  • #917 by @bobsingor – Add the recursive option to folders.delete.

  • #910 by @bobsingor – doc.versions.* takes the layer: list, signatures, signatureContents, signatureDigest, analysis, download and revision read /v1/docs/{docId}/layers/{layerName}/versions…. list answers the layer's baseSha and its versions (the upload, then the ones its signatures made), and another layer's version is 404.

  • #909 by @bobsingor – shares.create and shares.update take identity, and a share record returns it: who a link's visitors are, for a link made for one person. Identity is one shared type, used by tokens.issue too.

  • #917 by @bobsingor – A tenant token's scope in tokens.issue takes document capabilities next to
    tenant scopes, and the document operations document tenant tokens as a
    credential.

Patch Changes

  • #910 by @bobsingor – StaleBase is no longer an engine error code, and the signature notes describe the new rule: a signature's new version belongs to its layer, and the document and every other layer stay as they were.

@cloudpdf/server@3.0.0-next.18

Minor Changes

  • #917 by @bobsingor – Organize documents in folders. Folders nest up to 100 levels with names
    unique among siblings, ignoring case. A move takes documents and folders
    together or not at all and never makes a loop, even when two moves race;
    only empty folders delete. Documents are filed at upload and listed per
    folder, and a document being deleted leaves its folder. Migration 046 adds
    the folders table and documents.folder_id. Errors thrown with
    structured context now return it as details.

  • #917 by @bobsingor – Store a name for every document, searchable and sortable without regard to
    case, and rename documents with PATCH /v1/tenants/:tenantId/documents/:id
    under the new docs.update scope. The documents list searches by name, sorts
    by creation time, name or size in either order with stable cursors, and hides
    documents that are being deleted unless asked for by state. Migration 045 names
    existing documents from metadata.name when it is a non-empty string, otherwise
    from their id.

  • #917 by @bobsingor – Delete a folder with everything in it via recursive=true: the folder and
    every folder under it go in one transaction, and every document in them stops
    opening, leaves every list and stops answering its share links at once, while
    their stored files are removed in the background. The sweeper now also
    finishes deletes left behind, such as one interrupted by a crash, after
    deletingGraceMs (default one minute). The filesystem object store no longer
    fails a write when a delete elsewhere in the same tenant prunes the
    directories the write has just made.

  • #917 by @bobsingor – Tenant scopes act on records and document capabilities act on what is inside
    documents, on any token. A tenant JWT is checked inside documents the way a
    document JWT is, against the document capabilities its scope names, which hold
    for every document of the tenant; docs.read lists documents but no longer
    opens, reads or changes them. Downloading the original file needs
    doc.download and the thumbnail needs doc.render. A tenant token whose scope
    names no document capability is refused on the document routes, and
    tokens.issue validates a tenant token's scope entries.

Patch Changes

  • #910 by @bobsingor – A layer's versions are read through the layer. The version routes moved from /v1/docs/:docId/versions… to /v1/docs/:docId/layers/:layerName/versions…, checked like every other layer route.

    • The list gives the layer's versions (the upload, then the ones its signatures made) and its baseSha.
    • A version's signatures, analysis, download and revisions answer only for the upload or the layer's own versions: another layer's version is 404, and a token for one layer can't use another layer's path.
    • Tenant tokens read any layer's versions, through that layer.
  • #909 by @bobsingor – A share link can say who its visitors are, for a link made for one person: identity on shares.create and shares.update, the same shape as tokens.issue's (migration 043). Every session the link gives carries it, whoever opens the link: a field it sets is never asked, and a visitor's answer for it is ignored. Its userId replaces the visitor's own visitor_<id>; each visit still gets its own layer on a per-visitor link. A link that asks a field its identity sets is refused (400), on create and on an update checked against the link as it will be.

  • #907 by @bobsingor – A share link's visitor is remembered on every link except a per-visitor link that doesn't keep visitors' layers: the exchange answers visitor.keep: true for shared links too. A visitor who comes back in the same browser keeps their answers to the link's questions and stays the author of what they added, instead of being asked again on every page load and listed as a new visitor each time.

  • #910 by @bobsingor – A signature moves only the layer it was made in. Completing a signature writes the new version as that layer's own: only its base_sha moves, and the document (documents.base_sha, the upload) and every other layer stay as they were.

    Before, a signature moved the whole document, so on a per-visitor link the next visitor opened the signer's filled-in, signed copy, and layers still on the old version could no longer sign (StaleBase).

    • Every layer can sign, over its own base. A layer that signs again signs over its previous version.
    • Versions belong to their layer: a layer's versions are numbered along its own chain and stored under the layer, and they're deleted with it.
    • /layers/:layerName/head reports the layer's own base.
    • Migration 044 gives each existing signed version its layer, puts a document a signature moved back on its upload, and starts layers that stored nothing on the upload too.
    • No document-wide signal any more: the base-changed bus channel is gone. Other replicas reload the signing layer because its version moved.

@embedpdf/core@3.0.0-next.18

Minor Changes

  • #907 by @bobsingor – A ready document whose share link asks for a passphrase or answers it got after the document opened shows them as shareRequest, as a document waiting to open does, and documents.retry(id, { sharePassword }) or retry(id, { visitor }) lets it go on as the same visitor instead of opening it again.

Patch Changes

  • #909 by @bobsingor – documents.retry(id, { identity }) takes the visitor's answers to what a share link asks (was { visitor }). They join who the page said the user is, the document's identity or else the viewer's, and the document opens again with that identity.

  • #910 by @bobsingor – The StaleBase engine error is gone, and with it its conflict mapping: a signature moves only its own layer, so every layer can sign.

@embedpdf/engine-core@3.0.0-next.18

Minor Changes

  • #911 by @bobsingor – New runPageFormFieldsConformance suite checks that pages.insert and pages.extract bring form fields, keep same-named fields apart, and survive a save in either mode.

  • #907 by @bobsingor – DocumentShare gets openRequest, onOpenRequest() and resume(): a passphrase, or questions asked on open, that a share link gets while a document is open are asked of the visitor, and resume({ sharePassword }) or resume({ visitor }) lets the document go on as the same visitor. ShareOpenRequest and shareOpenRequestOf() move here from @embedpdf/core, which re-exports the type.

Patch Changes

  • #910 by @bobsingor – The version wire paths and resources are the layer's: wirePaths.layerVersions, layerVersionSignatures, layerVersionSignatureContents, layerVersionSignatureDigest, layerVersionAnalysis, layerVersionDownload and layerVersionRevision take the layer name. The resources are now layer-versions and layer-version-*, so a layer's CDN grant covers only its own versions.

    The catalog schema is LayerVersionsSchema ({ baseSha, versions }, was DocumentVersionsSchema with head).

  • #909 by @bobsingor – identity is the one word for who the user is, on both engines. OpenOptions.identity is who your page knows the user is: the local engine's session identity, as before; on the cloud engine a document token decides, and a share link takes it as the visitor's answers to what the link asks. The share input's visitor is gone (pass identity in the options instead), and DocumentShare.resume() takes { sharePassword, identity }. doc.security.identity says who a session acts for.

    The runtime entry exports devWarn, isDev and resetDevWarnings for engines: development-only warnings, once per key.

  • #910 by @bobsingor – EngineErrorCode.StaleBase is gone. A signature no longer moves the document, so no layer is ever behind it and every layer can sign over its own base.

@embedpdf/engine-runtime@3.0.0-next.18

Minor Changes

  • #911 by @bobsingor – New EPDFDoc_ImportPages copies pages with the form fields of their widgets, where FPDF_ImportPagesByIndex left each copied widget's /Parent naming an object of the source and wrote no /AcroForm. Each field above the copied widgets is copied once, its /Kids limited to what was copied, and the copied top-level fields join the destination's /AcroForm /Fields (made when it has none) with the source's /DR resources, /DA and /Q, /NeedAppearances, calculation order and SignaturesExist. A /DR font is shared only when the destination defines one of that name the same way, key for key (widths and descriptor included, no font program); otherwise it is copied under a free name, and the copied /DA strings follow, comments and all. A copied pop-up's /Parent names the copy of its annotation.

    New EPDFDoc_GetImportFieldRoots lists the top-level fields an import of some pages brings, and EPDFForm_GetFieldPartialName reads a field's own /T by object number.

  • #913 by @bobsingor – New EPDFCatalog_GetMetadata reads the document's XMP packet (the catalog's /Metadata stream) decoded, and EPDFCatalog_SetMetadata replaces it, unfiltered, keeping the stream's object number, or removes it.

    Saving an encrypted document encrypts its metadata stream, unless the file says /EncryptMetadata false; it was written in the clear, so readers decrypted the XMP into noise. A metadata stream with a filter is written decoded, where its encoded bytes were written without the filter that decodes them.

@embedpdf/engine-services@3.0.0-next.18

Minor Changes

  • #911 by @bobsingor – pages.insert and pages.extract bring the form fields of the copied pages' widgets, written into the document's /AcroForm, so the fields stay fillable after a save and in other PDF apps. An extract brings only the widgets on the extracted pages. An inserted top-level field whose name the document already uses comes in as name_2 (or the next free number), with its fields under it, so two copies of a filled-in form keep their own values.

  • #913 by @bobsingor – metadata.update keeps a document's XMP packet in step with its /Info fields: a field it sets is written to its XMP property (dc:title, dc:creator, dc:description, pdf:Keywords, xmp:CreatorTool, pdf:Producer, xmp:CreateDate, xmp:ModifyDate, pdf:Trapped), added when the packet doesn't have it, and a field it sets to null is removed from the packet too. A packet's dc:subject keyword list follows the keywords. metadata.custom.update changes or removes the pdfx: property Adobe apps copy a custom key to, and never adds one. Everything else in the packet stays as written; a document without XMP gets none, and XMP that isn't well-formed is left as it is.

@cloudpdf/engine@3.0.0-next.18

Patch Changes

  • #910 by @bobsingor – A document's signed bytes (signatures.getContents, getDigest, downloadRevision and history analyze) are read through its layer's version paths.

  • #909 by @bobsingor – A share link takes the page's identity (the open() option, or the viewer's identity) as the visitor's answers, the same as the visitor typing them: only the fields the link asks, never userId or groupId. The share input's visitor is gone.

    Nothing the page passes is ignored silently: in development the engine warns once when it doesn't use scope (the document's token says what the session may do), or when the session doesn't act for the identity passed, and says why.

  • #907 by @bobsingor – A renewal the share link refuses for a passphrase, or for questions asked on open, no longer retries on every request. The document asks once (doc.share.openRequest, onOpenRequest), reads on with its session until it runs out, then waits for resume(); with nothing listening, a request fails with the refusal. A shared link's visitor is now kept in the visitor store for the next visit, as the server says (visitor.keep).

@cloudpdf/viewer@3.0.0-next.18

Patch Changes

  • #909 by @bobsingor – The viewer takes identity again: who your page knows the user is. A document token decides for itself, and a share link takes it as the visitor's answers to what the link asks, so the questions it covers aren't asked. src.visitor is gone; scope stays out, since the token says what the user may do.

@embedpdf/core-js-sandbox@3.0.0-next.18

Patch Changes

  • #905 by @bobsingor – PDF JavaScript runs in Next.js apps again.

    • Turbopack, the default bundler in Next 16, failed with "Can't resolve '#quickjs-variant'", because it doesn't follow an imports target that names another package. #quickjs-variant now maps to two files of this package, quickjs-variant/browser.js and quickjs-variant/wasmfile.js, which re-export QuickJS's browser and wasm-file builds.
    • Production builds on Next before 16.4.1, webpack or Turbopack, broke QuickJS's browser build, so the sandbox never started. QuickJS 0.32.0 embeds its wasm as raw bytes in a template literal, and Next's minifier turned some of them into octal escapes ("Octal escape sequences are not allowed in template strings"). QuickJS is pinned to 0.31.0, which embeds the wasm as base64.

    Browsers still get the browser build, with no .wasm request, and Node the wasm-file one.

@embedpdf/viewer-chrome@3.0.0-next.18

Patch Changes

  • #908 by @bobsingor – Hide the Measure tab when the session can neither draw measurements nor set a page's scale: the measurement panel, and the Measure bar's scale button that opens it, now follow the same permission checks as the measurement tools. The scale button is drawn like every other bar button, so the Measure bar is as tall as the other mode bars, and it shows pressed while the panel is open; clicking it again closes the panel.

  • #907 by @bobsingor – Where a document allows searching but not copying text, search opens as a find bar over the top corner of the pages instead of a panel of empty result rows. It shows which match you're on and how many there are, Enter and Shift+Enter step through them, and its options sit behind a button. In the search panel, Enter and Shift+Enter step through the matches too, and a match the engine finds no text around reads "Result 3" instead of an empty row.

  • #907 by @bobsingor – When a share link gets a passphrase or questions while its document is open, the viewer shows the same passphrase or questions form over the document, and the document goes on once they're given.

@cloudpdf/viewer-angular@3.0.0-next.18

@cloudpdf/viewer-react@3.0.0-next.18

@cloudpdf/viewer-svelte@3.0.0-next.18

@cloudpdf/viewer-vue@3.0.0-next.18

@embedpdf/core-acrojs@3.0.0-next.18

@embedpdf/core-annotation@3.0.0-next.18

@embedpdf/core-fonts@3.0.0-next.18

@embedpdf/core-form@3.0.0-next.18

@embedpdf/core-geometry@3.0.0-next.18

@embedpdf/core-signature@3.0.0-next.18

@embedpdf/core-stage@3.0.0-next.18

@embedpdf/core-ui@3.0.0-next.18

@embedpdf/engine@3.0.0-next.18

@embedpdf/engine-runtime-darwin-arm64@3.0.0-next.18

@embedpdf/engine-runtime-darwin-x64@3.0.0-next.18

@embedpdf/engine-runtime-linux-arm64@3.0.0-next.18

@embedpdf/engine-runtime-linux-x64@3.0.0-next.18

@embedpdf/engine-runtime-linuxmusl-arm64@3.0.0-next.18

@embedpdf/engine-runtime-linuxmusl-x64@3.0.0-next.18

@embedpdf/engine-runtime-wasm32@3.0.0-next.18

@embedpdf/engine-runtime-win32-arm64@3.0.0-next.18

@embedpdf/engine-runtime-win32-x64@3.0.0-next.18

@embedpdf/angular@3.0.0-next.18

@embedpdf/react@3.0.0-next.18

@embedpdf/svelte@3.0.0-next.18

@embedpdf/vue@3.0.0-next.18

@embedpdf/web@3.0.0-next.18

@embedpdf/plugin-actions@3.0.0-next.18

@embedpdf/plugin-annotation@3.0.0-next.18

@embedpdf/plugin-attachment@3.0.0-next.18

@embedpdf/plugin-commands@3.0.0-next.18

@embedpdf/plugin-form@3.0.0-next.18

@embedpdf/plugin-history@3.0.0-next.18

@embedpdf/plugin-i18n@3.0.0-next.18

@embedpdf/plugin-interaction@3.0.0-next.18

@embedpdf/plugin-link@3.0.0-next.18

@embedpdf/plugin-measurement@3.0.0-next.18

@embedpdf/plugin-metadata@3.0.0-next.18

@embedpdf/plugin-outline@3.0.0-next.18

@embedpdf/plugin-page-edit@3.0.0-next.18

@embedpdf/plugin-redaction@3.0.0-next.18

@embedpdf/plugin-render@3.0.0-next.18

@embedpdf/plugin-search@3.0.0-next.18

@embedpdf/plugin-selection@3.0.0-next.18

@embedpdf/plugin-shell@3.0.0-next.18

@embedpdf/plugin-signature@3.0.0-next.18

@embedpdf/plugin-stage@3.0.0-next.18

@embedpdf/plugin-stamp@3.0.0-next.18

@embedpdf/plugin-view-manager@3.0.0-next.18

@embedpdf/viewer-angular@3.0.0-next.18

@embedpdf/viewer@3.0.0-next.18

@embedpdf/viewer-react@3.0.0-next.18

@embedpdf/viewer-svelte@3.0.0-next.18

@embedpdf/viewer-vue@3.0.0-next.18