diff --git a/.changeset/set-field-value-animate.md b/.changeset/set-field-value-animate.md new file mode 100644 index 00000000..fca23936 --- /dev/null +++ b/.changeset/set-field-value-animate.md @@ -0,0 +1,10 @@ +--- +'@simplepdf/embed': minor +--- + +**Fill text fields instantly: `setFieldValue` takes an optional `animate` flag.** +- `animate: false` sets a text value in one step and resolves right away, for headless or batch filling where speed matters. +- Omitted or `true` keeps today's behavior: the value is typed out character by character, so a person watching the editor can follow along. +- Checkbox, option, signature, picture and `null` values are always set at once. +- Available everywhere the operation is: `embed.actions.setFieldValue`, `useEmbed().actions.setFieldValue`, the `setFieldValue` agentic tool on every tool subpath, and the `simplepdf_embed_set_field_value` WebMCP tool. +- The contract follows the live editor: operations sent before a document is loaded answer `bad_request:no_document_loaded`, and `loadDocument` resolves once the document and its fields are ready, failing with the new `bad_request:failed_to_load_document` when the document cannot be loaded. diff --git a/embed/embed-api.json b/embed/embed-api.json index 60a1e129..15ea6a49 100644 --- a/embed/embed-api.json +++ b/embed/embed-api.json @@ -1,5 +1,5 @@ { - "editor_version": "0b688f24-20260911T151304Z", + "editor_version": "65235d76-20261009T151312Z", "description": "This is the SimplePDF editor interface contract. Drive the editor programmatically over window.postMessage with the editor iframe: post a JSON string { \"type\": {{operation request_type}}, \"request_id\": {{a request correlation id you generate}}, \"data\": {{input matching input_schema}} } to the iframe; the editor replies with { \"type\": \"REQUEST_RESULT\", \"data\": { \"request_id\": {{the same correlation id}}, \"result\": {{result}} } } (match each reply to its request by this id), where result is { \"success\": true, \"data\": {{a value matching the operation's output_schema; null for ops that return nothing}} } or { \"success\": false, \"error\": { code, message } }. Each operation lists the op-specific `error_codes` it can return; on top of those, any op may also fail with a gateway/permission code (origin/plan/signup gating, editor-not-ready, or an internal error). Every code is within `editor_error_schema` (the complete closed union to narrow against), where each code const carries a `description` of its meaning. Outbound events (see `events`) are pushed the same way. `operations` lists every operation the editor supports. Most require the embedding origin to be allowlisted (\"whitelisted\") for the tenant in the SimplePDF admin dashboard, and the tenant plan to permit them (LOAD_DOCUMENT is always available). A call the current setup does not permit returns the matching gateway code: forbidden:origin_not_whitelisted when the origin is not allowlisted, or bad_request:plan_upgrade_required when the plan excludes it. All JSON schemas use the json_schema_dialect declared at the root. We recommend the @simplepdf/embed package for a typed, ergonomic wrapper over this contract (https://github.com/SimplePDF/simplepdf-embed).", "json_schema_dialect": "https://json-schema.org/draft/2020-12/schema", "protocol": { @@ -126,6 +126,7 @@ }, "error_codes": [ "forbidden:editing_not_allowed", + "bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:invalid_dimensions", "bad_request:invalid_value", @@ -209,6 +210,7 @@ }, "error_codes": [ "forbidden:editing_not_allowed", + "bad_request:no_document_loaded", "bad_request:invalid_field_ids", "bad_request:invalid_page", "bad_request:page_out_of_range", @@ -439,7 +441,7 @@ }, "required": ["page", "image_data_url", "image_width", "image_height", "badges"] }, - "error_codes": ["bad_request:invalid_page", "bad_request:page_out_of_range"], + "error_codes": ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"], "tool": { "name": "simplepdf_embed_get_annotated_page", "description": "Render a page as a PNG with every field on it outlined and numbered, so a vision model can SEE which field sits where on the printed form. Feed the image and the badges map to a multimodal model to label fields; get_fields returns the matching ids. The render shows the printed form and field placement, not filled-in values (read those with get_fields). Returns { page, image_data_url, image_width, image_height, badges } where badges maps each number drawn on the image to its field_id. It renders document content, so it is gated exactly like get_document_content: the embedding origin must be whitelisted for the tenant.", @@ -617,7 +619,7 @@ "output_schema": { "type": "null" }, - "error_codes": ["bad_request:invalid_page", "bad_request:page_out_of_range"], + "error_codes": ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"], "tool": { "name": "simplepdf_embed_go_to", "description": "Scroll the editor to a specific 1-based page. Returns no data.", @@ -638,7 +640,7 @@ }, { "request_type": "LOAD_DOCUMENT", - "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data.", + "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data.", "input_schema": { "type": "object", "properties": { @@ -656,15 +658,15 @@ } }, "required": ["data_url"], - "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data." + "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data." }, "output_schema": { "type": "null" }, - "error_codes": ["bad_request:invalid_value", "bad_request:invalid_page"], + "error_codes": ["bad_request:failed_to_load_document", "bad_request:invalid_value", "bad_request:invalid_page"], "tool": { "name": "simplepdf_embed_load_document", - "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data.", + "description": "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data.", "input_schema": { "type": "object", "properties": { @@ -806,7 +808,7 @@ "output_schema": { "type": "null" }, - "error_codes": ["bad_request:invalid_tool"], + "error_codes": ["bad_request:no_document_loaded", "bad_request:invalid_tool"], "tool": { "name": "simplepdf_embed_select_tool", "description": "Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data.", @@ -835,10 +837,14 @@ }, { "request_type": "SET_FIELD_VALUE", - "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.", + "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.", "input_schema": { "type": "object", "properties": { + "animate": { + "description": "Type a text value out character by character (true, the default) so a person watching the editor can follow the field being filled, or set it at once (false) for headless or batch filling where speed matters. Only text values are typed: checkbox, option, signature, picture and null values are always set at once.", + "type": "boolean" + }, "field_id": { "type": "string", "description": "ID of the field to update." @@ -856,7 +862,7 @@ } }, "required": ["field_id", "value"], - "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data." + "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data." }, "output_schema": { "type": "null" @@ -870,10 +876,14 @@ ], "tool": { "name": "simplepdf_embed_set_field_value", - "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.", + "description": "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.", "input_schema": { "type": "object", "properties": { + "animate": { + "description": "Type a text value out character by character (true, the default) so a person watching the editor can follow the field being filled, or set it at once (false) for headless or batch filling where speed matters. Only text values are typed: checkbox, option, signature, picture and null values are always set at once.", + "type": "boolean" + }, "field_id": { "description": "ID of the field to update.", "type": "string" @@ -915,7 +925,11 @@ "output_schema": { "type": "null" }, - "error_codes": ["bad_request:invalid_value", "bad_request:missing_required_fields"], + "error_codes": [ + "bad_request:no_document_loaded", + "bad_request:invalid_value", + "bad_request:missing_required_fields" + ], "tool": { "name": "simplepdf_embed_submit", "description": "Submit the completed document through the editor's finalization flow. This is irreversible. When download_copy is true the signer also gets a downloaded copy. Fails with missing_required_fields when required fields are unfilled. Returns no data.", @@ -938,7 +952,7 @@ "events": [ { "event_type": "EDITOR_READY", - "description": "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, every operation fails with bad_request:editor_not_ready. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event.", + "description": "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, LOAD_DOCUMENT fails with bad_request:editor_not_ready and every other operation with bad_request:no_document_loaded. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event.", "payload_schema": { "type": "object", "properties": {} @@ -946,7 +960,7 @@ }, { "event_type": "DOCUMENT_LOADED", - "description": "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. Wait for it before operating on the document: until it fires, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded or bad_request:editor_not_ready, and GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user.", + "description": "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. It follows the LOAD_DOCUMENT reply, which is itself sent once the document is ready, so a request sent after that reply acts on the new document; before any document, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded, and until it fires for a document the page opened itself GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user.", "payload_schema": { "type": "object", "properties": { @@ -1044,7 +1058,12 @@ { "type": "string", "const": "bad_request:event_not_allowed", - "description": "This operation is disabled for the current portal configuration." + "description": "This operation is not available in this context (the portal configuration or this page does not offer it); the message says why." + }, + { + "type": "string", + "const": "bad_request:failed_to_load_document", + "description": "The document LOAD_DOCUMENT was given could not be loaded (unreachable, not a PDF or image, corrupted, password-protected, superseded by another load, or the editor could not prepare it: the server never resolved it, or storing it failed); the message says which." }, { "type": "string", @@ -1129,7 +1148,7 @@ { "type": "string", "const": "forbidden:origin_not_whitelisted", - "description": "The embedding origin is not allowlisted for this tenant. Allowlist it in the SimplePDF admin dashboard." + "description": "The embedding origin is not allowlisted for this tenant, or is not the allowlisted origin the editor was loaded from. Allowlist it in the SimplePDF admin dashboard and let the embedding page's Referer reach the editor." }, { "type": "string", diff --git a/embed/etc/index.api.md b/embed/etc/index.api.md index 0e83df63..0d7c1df9 100644 --- a/embed/etc/index.api.md +++ b/embed/etc/index.api.md @@ -350,6 +350,7 @@ export type SelectToolInput = { // @public (undocumented) export type SetFieldValueInput = { + animate?: boolean; fieldId: string; value: string | null; }; diff --git a/embed/etc/protocol.api.md b/embed/etc/protocol.api.md index 65e18ef7..b4e9d971 100644 --- a/embed/etc/protocol.api.md +++ b/embed/etc/protocol.api.md @@ -5,7 +5,7 @@ ```ts // @public (undocumented) -export const EDITOR_ERROR_CODES: readonly ["bad_request:download_blocked", "bad_request:editor_not_ready", "bad_request:event_not_allowed", "bad_request:field_not_found", "bad_request:invalid_dimensions", "bad_request:invalid_event_type", "bad_request:invalid_field_ids", "bad_request:invalid_field_type", "bad_request:invalid_page", "bad_request:invalid_signature_url", "bad_request:invalid_tool", "bad_request:invalid_value", "bad_request:missing_required_fields", "bad_request:no_document_loaded", "bad_request:page_not_found", "bad_request:page_out_of_range", "bad_request:plan_upgrade_required", "bad_request:read_only", "bad_request:signup_required", "forbidden:editing_not_allowed", "forbidden:origin_not_whitelisted", "forbidden:whitelist_required", "unexpected:internal_error"]; +export const EDITOR_ERROR_CODES: readonly ["bad_request:download_blocked", "bad_request:editor_not_ready", "bad_request:event_not_allowed", "bad_request:failed_to_load_document", "bad_request:field_not_found", "bad_request:invalid_dimensions", "bad_request:invalid_event_type", "bad_request:invalid_field_ids", "bad_request:invalid_field_type", "bad_request:invalid_page", "bad_request:invalid_signature_url", "bad_request:invalid_tool", "bad_request:invalid_value", "bad_request:missing_required_fields", "bad_request:no_document_loaded", "bad_request:page_not_found", "bad_request:page_out_of_range", "bad_request:plan_upgrade_required", "bad_request:read_only", "bad_request:signup_required", "forbidden:editing_not_allowed", "forbidden:origin_not_whitelisted", "forbidden:whitelist_required", "unexpected:internal_error"]; // @public (undocumented) export const EXTRACTION_MODES: readonly ["auto", "ocr"]; @@ -31,7 +31,7 @@ export const OPERATIONS: readonly [{ readonly wire_type: "CREATE_FIELD"; readonly method: "createField"; readonly description: "Create a new overlay field of the given type at an (x, y) position and size (in PDF points) on a 1-based page. Returns { field_id } for the created field. Requires editing to be enabled."; - readonly error_codes: readonly ["forbidden:editing_not_allowed", "bad_request:invalid_page", "bad_request:invalid_dimensions", "bad_request:invalid_value", "bad_request:page_out_of_range", "bad_request:page_not_found", "bad_request:invalid_field_type", "bad_request:invalid_signature_url"]; + readonly error_codes: readonly ["forbidden:editing_not_allowed", "bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:invalid_dimensions", "bad_request:invalid_value", "bad_request:page_out_of_range", "bad_request:page_not_found", "bad_request:invalid_field_type", "bad_request:invalid_signature_url"]; readonly is_agentic_tool: true; readonly has_output: true; }, { @@ -39,7 +39,7 @@ export const OPERATIONS: readonly [{ readonly wire_type: "DELETE_FIELDS"; readonly method: "deleteFields"; readonly description: "Delete overlay fields by id; omit field_ids to delete every field on the given 1-based page, or omit both field_ids and page to delete every overlay field in the document. Returns { deleted_count }. Destructive; requires editing to be enabled."; - readonly error_codes: readonly ["forbidden:editing_not_allowed", "bad_request:invalid_field_ids", "bad_request:invalid_page", "bad_request:page_out_of_range", "bad_request:page_not_found"]; + readonly error_codes: readonly ["forbidden:editing_not_allowed", "bad_request:no_document_loaded", "bad_request:invalid_field_ids", "bad_request:invalid_page", "bad_request:page_out_of_range", "bad_request:page_not_found"]; readonly is_agentic_tool: true; readonly has_output: true; }, { @@ -79,7 +79,7 @@ export const OPERATIONS: readonly [{ readonly wire_type: "GET_ANNOTATED_PAGE"; readonly method: "getAnnotatedPage"; readonly description: "Render a page as a PNG with every field on it outlined and numbered, so a vision model can SEE which field sits where on the printed form. Feed the image and the badges map to a multimodal model to label fields; get_fields returns the matching ids. The render shows the printed form and field placement, not filled-in values (read those with get_fields). Returns { page, image_data_url, image_width, image_height, badges } where badges maps each number drawn on the image to its field_id. It renders document content, so it is gated exactly like get_document_content: the embedding origin must be whitelisted for the tenant."; - readonly error_codes: readonly ["bad_request:invalid_page", "bad_request:page_out_of_range"]; + readonly error_codes: readonly ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"]; readonly is_agentic_tool: true; readonly has_output: true; }, { @@ -103,15 +103,15 @@ export const OPERATIONS: readonly [{ readonly wire_type: "GO_TO"; readonly method: "goTo"; readonly description: "Scroll the editor to a specific 1-based page. Returns no data."; - readonly error_codes: readonly ["bad_request:invalid_page", "bad_request:page_out_of_range"]; + readonly error_codes: readonly ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"]; readonly is_agentic_tool: true; readonly has_output: false; }, { readonly request_type: "LOAD_DOCUMENT"; readonly wire_type: "LOAD_DOCUMENT"; readonly method: "loadDocument"; - readonly description: "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data."; - readonly error_codes: readonly ["bad_request:invalid_value", "bad_request:invalid_page"]; + readonly description: "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data."; + readonly error_codes: readonly ["bad_request:failed_to_load_document", "bad_request:invalid_value", "bad_request:invalid_page"]; readonly is_agentic_tool: false; readonly has_output: false; }, { @@ -135,14 +135,14 @@ export const OPERATIONS: readonly [{ readonly wire_type: "SELECT_TOOL"; readonly method: "selectTool"; readonly description: "Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data."; - readonly error_codes: readonly ["bad_request:invalid_tool"]; + readonly error_codes: readonly ["bad_request:no_document_loaded", "bad_request:invalid_tool"]; readonly is_agentic_tool: true; readonly has_output: false; }, { readonly request_type: "SET_FIELD_VALUE"; readonly wire_type: "SET_FIELD_VALUE"; readonly method: "setFieldValue"; - readonly description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data."; + readonly description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data."; readonly error_codes: readonly ["bad_request:invalid_value", "bad_request:invalid_signature_url", "bad_request:no_document_loaded", "bad_request:read_only", "bad_request:field_not_found"]; readonly is_agentic_tool: true; readonly has_output: false; @@ -151,7 +151,7 @@ export const OPERATIONS: readonly [{ readonly wire_type: "SUBMIT"; readonly method: "submit"; readonly description: "Submit the completed document through the editor's finalization flow. This is irreversible. When download_copy is true the signer also gets a downloaded copy. Fails with missing_required_fields when required fields are unfilled. Returns no data."; - readonly error_codes: readonly ["bad_request:invalid_value", "bad_request:missing_required_fields"]; + readonly error_codes: readonly ["bad_request:no_document_loaded", "bad_request:invalid_value", "bad_request:missing_required_fields"]; readonly is_agentic_tool: true; readonly has_output: false; }]; @@ -162,10 +162,10 @@ export const OUTBOUND_EVENT_TYPES: ("EDITOR_READY" | "DOCUMENT_LOADED" | "PAGE_F // @public (undocumented) export const OUTBOUND_EVENTS: readonly [{ readonly event_type: "EDITOR_READY"; - readonly description: "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, every operation fails with bad_request:editor_not_ready. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event."; + readonly description: "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, LOAD_DOCUMENT fails with bad_request:editor_not_ready and every other operation with bad_request:no_document_loaded. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event."; }, { readonly event_type: "DOCUMENT_LOADED"; - readonly description: "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. Wait for it before operating on the document: until it fires, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded or bad_request:editor_not_ready, and GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user."; + readonly description: "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. It follows the LOAD_DOCUMENT reply, which is itself sent once the document is ready, so a request sent after that reply acts on the new document; before any document, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded, and until it fires for a document the page opened itself GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user."; }, { readonly event_type: "PAGE_FOCUSED"; readonly description: "Pushed when the focused page changes (the user scrolls to a new page, or a GO_TO completes). The payload reports the current page."; diff --git a/embed/etc/schemas.api.md b/embed/etc/schemas.api.md index 51663198..822dadcb 100644 --- a/embed/etc/schemas.api.md +++ b/embed/etc/schemas.api.md @@ -139,6 +139,7 @@ export type SelectToolInput = z.infer; // @public (undocumented) export const SetFieldValueInput: z.ZodObject<{ + animate: z.ZodOptional; fieldId: z.ZodString; value: z.ZodNullable; }, z.core.$strip>; diff --git a/embed/etc/tanstack-ai.api.md b/embed/etc/tanstack-ai.api.md index de2cd0b4..8753caba 100644 --- a/embed/etc/tanstack-ai.api.md +++ b/embed/etc/tanstack-ai.api.md @@ -26,7 +26,7 @@ export type SimplePDFToolName = keyof typeof TOOL_DEFINITIONS; // Warnings were encountered during analysis: // -// dist/tanstack-ai.d.ts:60:5 - (ae-forgotten-export) The symbol "Embed" needs to be exported by the entry point tanstack-ai.d.ts +// dist/tanstack-ai.d.ts:61:5 - (ae-forgotten-export) The symbol "Embed" needs to be exported by the entry point tanstack-ai.d.ts // (No @packageDocumentation comment for this package) diff --git a/embed/etc/tools.api.md b/embed/etc/tools.api.md index 7509fde4..97239f8d 100644 --- a/embed/etc/tools.api.md +++ b/embed/etc/tools.api.md @@ -114,8 +114,9 @@ export const SIMPLEPDF_TOOLS: { }, zod_v4_core.$strip>; }; readonly setFieldValue: { - readonly description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data."; + readonly description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data."; readonly inputSchema: zod.ZodObject<{ + animate: zod.ZodOptional; fieldId: zod.ZodString; value: zod.ZodNullable; }, zod_v4_core.$strip>; diff --git a/embed/src/generated/contract.ts b/embed/src/generated/contract.ts index 82e5dc59..c136e428 100644 --- a/embed/src/generated/contract.ts +++ b/embed/src/generated/contract.ts @@ -5,7 +5,7 @@ import type { METHOD_NAMES } from './method-names' export const LOCALES = ["fr", "en", "it", "de", "pt", "es", "ja", "nl"] as const export type Locale = (typeof LOCALES)[number] -export const EDITOR_ERROR_CODES = ["bad_request:download_blocked", "bad_request:editor_not_ready", "bad_request:event_not_allowed", "bad_request:field_not_found", "bad_request:invalid_dimensions", "bad_request:invalid_event_type", "bad_request:invalid_field_ids", "bad_request:invalid_field_type", "bad_request:invalid_page", "bad_request:invalid_signature_url", "bad_request:invalid_tool", "bad_request:invalid_value", "bad_request:missing_required_fields", "bad_request:no_document_loaded", "bad_request:page_not_found", "bad_request:page_out_of_range", "bad_request:plan_upgrade_required", "bad_request:read_only", "bad_request:signup_required", "forbidden:editing_not_allowed", "forbidden:origin_not_whitelisted", "forbidden:whitelist_required", "unexpected:internal_error"] as const +export const EDITOR_ERROR_CODES = ["bad_request:download_blocked", "bad_request:editor_not_ready", "bad_request:event_not_allowed", "bad_request:failed_to_load_document", "bad_request:field_not_found", "bad_request:invalid_dimensions", "bad_request:invalid_event_type", "bad_request:invalid_field_ids", "bad_request:invalid_field_type", "bad_request:invalid_page", "bad_request:invalid_signature_url", "bad_request:invalid_tool", "bad_request:invalid_value", "bad_request:missing_required_fields", "bad_request:no_document_loaded", "bad_request:page_not_found", "bad_request:page_out_of_range", "bad_request:plan_upgrade_required", "bad_request:read_only", "bad_request:signup_required", "forbidden:editing_not_allowed", "forbidden:origin_not_whitelisted", "forbidden:whitelist_required", "unexpected:internal_error"] as const export type EditorErrorCode = (typeof EDITOR_ERROR_CODES)[number] export const FIELD_TYPES = ["TEXT", "SIGNATURE", "PICTURE", "CHECKBOX", "COMB_TEXT", "DROPDOWN", "RADIO"] as const @@ -45,7 +45,7 @@ export type RotatePageInput = { page: number } export type RotatePageOutput = null export type SelectToolInput = { tool: OverlayToolType | null } export type SelectToolOutput = null -export type SetFieldValueInput = { fieldId: string; value: string | null } +export type SetFieldValueInput = { animate?: boolean; fieldId: string; value: string | null } export type SetFieldValueOutput = null export type SubmitInput = { downloadCopy: boolean } export type SubmitOutput = null @@ -66,7 +66,7 @@ export const OPERATIONS = [ wire_type: "CREATE_FIELD", method: "createField", description: "Create a new overlay field of the given type at an (x, y) position and size (in PDF points) on a 1-based page. Returns { field_id } for the created field. Requires editing to be enabled.", - error_codes: ["forbidden:editing_not_allowed", "bad_request:invalid_page", "bad_request:invalid_dimensions", "bad_request:invalid_value", "bad_request:page_out_of_range", "bad_request:page_not_found", "bad_request:invalid_field_type", "bad_request:invalid_signature_url"] as const, + error_codes: ["forbidden:editing_not_allowed", "bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:invalid_dimensions", "bad_request:invalid_value", "bad_request:page_out_of_range", "bad_request:page_not_found", "bad_request:invalid_field_type", "bad_request:invalid_signature_url"] as const, is_agentic_tool: true, has_output: true, } /* CreateField */, @@ -75,7 +75,7 @@ export const OPERATIONS = [ wire_type: "DELETE_FIELDS", method: "deleteFields", description: "Delete overlay fields by id; omit field_ids to delete every field on the given 1-based page, or omit both field_ids and page to delete every overlay field in the document. Returns { deleted_count }. Destructive; requires editing to be enabled.", - error_codes: ["forbidden:editing_not_allowed", "bad_request:invalid_field_ids", "bad_request:invalid_page", "bad_request:page_out_of_range", "bad_request:page_not_found"] as const, + error_codes: ["forbidden:editing_not_allowed", "bad_request:no_document_loaded", "bad_request:invalid_field_ids", "bad_request:invalid_page", "bad_request:page_out_of_range", "bad_request:page_not_found"] as const, is_agentic_tool: true, has_output: true, } /* DeleteFields */, @@ -120,7 +120,7 @@ export const OPERATIONS = [ wire_type: "GET_ANNOTATED_PAGE", method: "getAnnotatedPage", description: "Render a page as a PNG with every field on it outlined and numbered, so a vision model can SEE which field sits where on the printed form. Feed the image and the badges map to a multimodal model to label fields; get_fields returns the matching ids. The render shows the printed form and field placement, not filled-in values (read those with get_fields). Returns { page, image_data_url, image_width, image_height, badges } where badges maps each number drawn on the image to its field_id. It renders document content, so it is gated exactly like get_document_content: the embedding origin must be whitelisted for the tenant.", - error_codes: ["bad_request:invalid_page", "bad_request:page_out_of_range"] as const, + error_codes: ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"] as const, is_agentic_tool: true, has_output: true, } /* GetAnnotatedPage */, @@ -147,7 +147,7 @@ export const OPERATIONS = [ wire_type: "GO_TO", method: "goTo", description: "Scroll the editor to a specific 1-based page. Returns no data.", - error_codes: ["bad_request:invalid_page", "bad_request:page_out_of_range"] as const, + error_codes: ["bad_request:no_document_loaded", "bad_request:invalid_page", "bad_request:page_out_of_range"] as const, is_agentic_tool: true, has_output: false, } /* GoTo */, @@ -155,8 +155,8 @@ export const OPERATIONS = [ request_type: "LOAD_DOCUMENT", wire_type: "LOAD_DOCUMENT", method: "loadDocument", - description: "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data.", - error_codes: ["bad_request:invalid_value", "bad_request:invalid_page"] as const, + description: "Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data.", + error_codes: ["bad_request:failed_to_load_document", "bad_request:invalid_value", "bad_request:invalid_page"] as const, is_agentic_tool: false, has_output: false, } /* LoadDocument */, @@ -183,7 +183,7 @@ export const OPERATIONS = [ wire_type: "SELECT_TOOL", method: "selectTool", description: "Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data.", - error_codes: ["bad_request:invalid_tool"] as const, + error_codes: ["bad_request:no_document_loaded", "bad_request:invalid_tool"] as const, is_agentic_tool: true, has_output: false, } /* SelectTool */, @@ -191,7 +191,7 @@ export const OPERATIONS = [ request_type: "SET_FIELD_VALUE", wire_type: "SET_FIELD_VALUE", method: "setFieldValue", - description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.", + description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.", error_codes: ["bad_request:invalid_value", "bad_request:invalid_signature_url", "bad_request:no_document_loaded", "bad_request:read_only", "bad_request:field_not_found"] as const, is_agentic_tool: true, has_output: false, @@ -201,7 +201,7 @@ export const OPERATIONS = [ wire_type: "SUBMIT", method: "submit", description: "Submit the completed document through the editor's finalization flow. This is irreversible. When download_copy is true the signer also gets a downloaded copy. Fails with missing_required_fields when required fields are unfilled. Returns no data.", - error_codes: ["bad_request:invalid_value", "bad_request:missing_required_fields"] as const, + error_codes: ["bad_request:no_document_loaded", "bad_request:invalid_value", "bad_request:missing_required_fields"] as const, is_agentic_tool: true, has_output: false, } /* Submit */, @@ -212,8 +212,8 @@ export type RequestType = (typeof OPERATIONS)[number]["request_type"] export type MethodName = (typeof METHOD_NAMES)[number] export const OUTBOUND_EVENTS = [ - { event_type: "EDITOR_READY", description: "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, every operation fails with bad_request:editor_not_ready. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event." }, - { event_type: "DOCUMENT_LOADED", description: "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. Wait for it before operating on the document: until it fires, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded or bad_request:editor_not_ready, and GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user." }, + { event_type: "EDITOR_READY", description: "Pushed once when the editor iframe boots in loading-placeholder mode (the loadingPlaceholder=true iframe query flag, which @simplepdf/embed sets while it waits to post LOAD_DOCUMENT) and accepts operations; before it, LOAD_DOCUMENT fails with bad_request:editor_not_ready and every other operation with bad_request:no_document_loaded. An iframe opened with a document instead goes straight to DOCUMENT_LOADED. It is not replayed: a listener attached after boot never receives it, so treat bad_request:editor_not_ready as \"retry shortly\" rather than waiting for this event." }, + { event_type: "DOCUMENT_LOADED", description: "Pushed exactly once per loaded document, when the document and its fields are ready; the payload carries the document_id. It follows the LOAD_DOCUMENT reply, which is itself sent once the document is ready, so a request sent after that reply acts on the new document; before any document, operations other than LOAD_DOCUMENT fail with bad_request:no_document_loaded, and until it fires for a document the page opened itself GET_FIELDS may report an incomplete field list. On a blank editor it fires once a document is loaded, by LOAD_DOCUMENT or by the user." }, { event_type: "PAGE_FOCUSED", description: "Pushed when the focused page changes (the user scrolls to a new page, or a GO_TO completes). The payload reports the current page." }, { event_type: "SUBMISSION_SENT", description: "Pushed after a SUBMIT completes successfully. This is how you confirm a submission landed: the SUBMIT operation itself resolves with data: null, so listen for this event to get the resulting document_id and submission_id." }, ] as const diff --git a/embed/src/generated/schemas.ts b/embed/src/generated/schemas.ts index cb8795ab..194c51ec 100644 --- a/embed/src/generated/schemas.ts +++ b/embed/src/generated/schemas.ts @@ -46,7 +46,7 @@ export const LoadDocumentInput = z.object({ dataUrl: z.string().describe("The document to load: a data URL, or an http(s) URL the editor fetches."), name: z.string().describe("Optional display name for the document.").optional(), page: z.number().int().describe("Optional 1-based page to open the document on.").optional(), -}).describe("Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data.") +}).describe("Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data.") export type LoadDocumentInput = z.infer export const MovePageInput = z.object({ fromPage: z.number().int().describe("1-based current position of the page to move."), @@ -62,9 +62,10 @@ export const SelectToolInput = z.object({ }).describe("Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data.") export type SelectToolInput = z.infer export const SetFieldValueInput = z.object({ + animate: z.boolean().describe("Type a text value out character by character (true, the default) so a person watching the editor can follow the field being filled, or set it at once (false) for headless or batch filling where speed matters. Only text values are typed: checkbox, option, signature, picture and null values are always set at once.").optional(), fieldId: z.string().describe("ID of the field to update."), value: z.string().nullable().describe("New value for the field, or null to clear it. If the field has options (see the field list), it must be one of them; otherwise a string (text/checkbox) or a data URL or http(s) URL, fetched by the editor (signature/picture)."), -}).describe("Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.") +}).describe("Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.") export type SetFieldValueInput = z.infer export const SubmitInput = z.object({ downloadCopy: z.boolean().describe("When true, the signer also receives a downloaded copy on submit."), diff --git a/embed/src/generated/tools.ts b/embed/src/generated/tools.ts index 5623e3db..644e10e1 100644 --- a/embed/src/generated/tools.ts +++ b/embed/src/generated/tools.ts @@ -17,7 +17,7 @@ export const TOOL_DEFINITIONS = { movePage: { description: "Move a page from one 1-based position to another, reordering the document. Returns no data. Destructive; requires editing to be enabled.", inputSchema: Schemas.MovePageInput }, rotatePage: { description: "Rotate a 1-based page 90 degrees clockwise. Returns no data. Destructive; requires editing to be enabled.", inputSchema: Schemas.RotatePageInput }, selectTool: { description: "Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data.", inputSchema: Schemas.SelectToolInput }, - setFieldValue: { description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.", inputSchema: Schemas.SetFieldValueInput }, + setFieldValue: { description: "Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.", inputSchema: Schemas.SetFieldValueInput }, submit: { description: "Submit the completed document through the editor's finalization flow. This is irreversible. When download_copy is true the signer also gets a downloaded copy. Fails with missing_required_fields when required fields are unfilled. Returns no data.", inputSchema: Schemas.SubmitInput }, } as const diff --git a/embed/src/generated/webmcp-tools.ts b/embed/src/generated/webmcp-tools.ts index 3c4376a9..3d4ff04e 100644 --- a/embed/src/generated/webmcp-tools.ts +++ b/embed/src/generated/webmcp-tools.ts @@ -35,10 +35,10 @@ export const WEBMCP_TOOLS = { getDocumentContent: {"name":"simplepdf_embed_get_document_content","description":"Extract the document's content page by page as Markdown (pass extraction_mode 'ocr' to force optical recognition, which returns plain text). Use it to read what the document says. Returns { name, pages: [{ page, content }] }.","inputSchema":{"type":"object","properties":{"extraction_mode":{"description":"Extraction strategy: 'auto' (default) or 'ocr' to force optical recognition.","enum":["auto","ocr"],"type":"string"}}},"annotations":{"readOnlyHint":true,"untrustedContentHint":true},"wireType":"GET_DOCUMENT_CONTENT"}, getFields: {"name":"simplepdf_embed_get_fields","description":"List every fillable field in the loaded document, including native dropdown and radio AcroFields. Each field reports its id, name, type, page, and current value. Call this first to discover field ids before reading or setting values. To SEE where each field sits on the printed page, call get_annotated_page. Returns { fields }.","inputSchema":{"type":"object","properties":{}},"annotations":{"readOnlyHint":true,"untrustedContentHint":true},"wireType":"GET_FIELDS"}, goTo: {"name":"simplepdf_embed_go_to","description":"Scroll the editor to a specific 1-based page. Returns no data.","inputSchema":{"type":"object","properties":{"page":{"description":"1-based page to navigate to.","type":"integer"}},"required":["page"]},"annotations":{"destructiveHint":false},"wireType":"GO_TO"}, - loadDocument: {"name":"simplepdf_embed_load_document","description":"Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Returns no data.","inputSchema":{"type":"object","properties":{"data_url":{"description":"The document to load: a data URL, or an http(s) URL the editor fetches.","type":"string"},"name":{"description":"Optional display name for the document.","type":"string"},"page":{"description":"Optional 1-based page to open the document on.","type":"integer"}},"required":["data_url"]},"annotations":{"destructiveHint":true,"openWorldHint":true},"wireType":"LOAD_DOCUMENT"}, + loadDocument: {"name":"simplepdf_embed_load_document","description":"Replace the document in the editor with one supplied as a base64 data URL or an http(s) URL the editor fetches. Destructive: the current document and every edit in it are discarded. Replies once the document and its fields are ready, so the next operation can act on it, and DOCUMENT_LOADED follows the reply; the URL already open is left as is and answers once it settles; a document that cannot be loaded or prepared answers bad_request:failed_to_load_document. Returns no data.","inputSchema":{"type":"object","properties":{"data_url":{"description":"The document to load: a data URL, or an http(s) URL the editor fetches.","type":"string"},"name":{"description":"Optional display name for the document.","type":"string"},"page":{"description":"Optional 1-based page to open the document on.","type":"integer"}},"required":["data_url"]},"annotations":{"destructiveHint":true,"openWorldHint":true},"wireType":"LOAD_DOCUMENT"}, movePage: {"name":"simplepdf_embed_move_page","description":"Move a page from one 1-based position to another, reordering the document. Returns no data. Destructive; requires editing to be enabled.","inputSchema":{"type":"object","properties":{"from_page":{"description":"1-based current position of the page to move.","type":"integer"},"to_page":{"description":"1-based destination position for the page.","type":"integer"}},"required":["from_page","to_page"]},"annotations":{"destructiveHint":true},"wireType":"MOVE_PAGE"}, rotatePage: {"name":"simplepdf_embed_rotate_page","description":"Rotate a 1-based page 90 degrees clockwise. Returns no data. Destructive; requires editing to be enabled.","inputSchema":{"type":"object","properties":{"page":{"description":"1-based page to rotate 90 degrees clockwise.","type":"integer"}},"required":["page"]},"annotations":{"destructiveHint":true},"wireType":"ROTATE_PAGE"}, selectTool: {"name":"simplepdf_embed_select_tool","description":"Activate a field-placement tool in the editor toolbar so the user can draw that field type, or pass null to clear the active tool. Returns no data.","inputSchema":{"type":"object","properties":{"tool":{"anyOf":[{"type":"string","enum":["TEXT","SIGNATURE","PICTURE","CHECKBOX","COMB_TEXT"]},{"type":"null"}],"description":"Tool to activate, or null to deselect."}},"required":["tool"]},"annotations":{"destructiveHint":false},"wireType":"SELECT_TOOL"}, - setFieldValue: {"name":"simplepdf_embed_set_field_value","description":"Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Returns no data.","inputSchema":{"type":"object","properties":{"field_id":{"description":"ID of the field to update.","type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"New value for the field, or null to clear it. If the field has options (see the field list), it must be one of them; otherwise a string (text/checkbox) or a data URL or http(s) URL, fetched by the editor (signature/picture)."}},"required":["field_id","value"]},"annotations":{"destructiveHint":false,"openWorldHint":true},"wireType":"SET_FIELD_VALUE"}, + setFieldValue: {"name":"simplepdf_embed_set_field_value","description":"Set the value of an existing field addressed by its id (from the field list), or clear it with null. If the field has options (see the field list), value must be one of them; otherwise value is a string (text or checkbox value) or a data URL or http(s) URL the editor fetches (signature, picture). Text values are typed out by default; pass animate: false to set them at once. Returns no data.","inputSchema":{"type":"object","properties":{"animate":{"description":"Type a text value out character by character (true, the default) so a person watching the editor can follow the field being filled, or set it at once (false) for headless or batch filling where speed matters. Only text values are typed: checkbox, option, signature, picture and null values are always set at once.","type":"boolean"},"field_id":{"description":"ID of the field to update.","type":"string"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"New value for the field, or null to clear it. If the field has options (see the field list), it must be one of them; otherwise a string (text/checkbox) or a data URL or http(s) URL, fetched by the editor (signature/picture)."}},"required":["field_id","value"]},"annotations":{"destructiveHint":false,"openWorldHint":true},"wireType":"SET_FIELD_VALUE"}, submit: {"name":"simplepdf_embed_submit","description":"Submit the completed document through the editor's finalization flow. This is irreversible. When download_copy is true the signer also gets a downloaded copy. Fails with missing_required_fields when required fields are unfilled. Returns no data.","inputSchema":{"type":"object","properties":{"download_copy":{"description":"When true, the signer also receives a downloaded copy on submit.","type":"boolean"}},"required":["download_copy"]},"annotations":{"destructiveHint":true},"wireType":"SUBMIT"}, } as const satisfies Record diff --git a/embed/test/webmcp.test.ts b/embed/test/webmcp.test.ts index ed6ada51..a6b10f24 100644 --- a/embed/test/webmcp.test.ts +++ b/embed/test/webmcp.test.ts @@ -168,7 +168,7 @@ describe('attachEmbed({ webMCP })', () => { const setFieldValue = findTool(modelContext, 'simplepdf_embed_set_field_value') expect(setFieldValue.description).toMatch(/^Set the value of an existing field/) expect(setFieldValue.inputSchema.type).toBe('object') - expect(Object.keys(setFieldValue.inputSchema.properties ?? {})).toEqual(['field_id', 'value']) + expect(Object.keys(setFieldValue.inputSchema.properties ?? {})).toEqual(['animate', 'field_id', 'value']) expect(setFieldValue.inputSchema.required).toEqual(['field_id', 'value']) for (const tool of modelContext.registered) { const hasExplicitHint = tool.annotations.readOnlyHint === true || typeof tool.annotations.destructiveHint === 'boolean' diff --git a/react/.prettierignore b/react/.prettierignore index 3394fcbe..fd6477d1 100644 --- a/react/.prettierignore +++ b/react/.prettierignore @@ -4,6 +4,7 @@ coverage/ etc/ tmp/ +package.json package-lock.json .prettierignore