All checks were successful
CD / Build and push images (push) Successful in 3m19s
CI / Lint, typecheck, test (push) Successful in 2m55s
CI / Auth e2e pack (push) Successful in 3m45s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
Uploading a Word/OpenOffice document to POST /ponds/:id/import enqueues a conversion job (the #62 queue) that produces a new page in the pond; the client polls GET /jobs/:id for the created resultPageId. Pipeline (ImportService, ADR 0009): pandoc-server is stateless and hands back a document's media no other way, so we convert in two passes — docx/odt → html with embed-resources inlines every image as a data: URI, then html → gfm produces clean structural Markdown with those data URIs still inline. Embedded images are stored as pond files (with quota accounting) and their references rewritten to file ids on the Markdown text before parsing (the editor parser only admits png/jpeg/gif/webp data URIs); an image whose bytes the upload pipeline rejects is dropped, not fatal. The title comes from a leading top-level heading (removed from the body) else the file name. The page is created from the resulting Yjs state. The shared conversion worker routes import-kind jobs to the pipeline via a token (breaking a module cycle), so import inherits the queue's locking, retry, and restart-survival. Media stored during a failed attempt is rolled back; a pond that runs out of storage fails the job with quota_exceeded. - schema: ConversionJob gains pond_id / source_name / result_page_id (migration 20260710041215_import_pages_conversion); ConversionJobView gains resultPageId. - PagesService.createWithState / yjs-content docToState build a page from a prepared document; FilesService.linkAttachmentsToPage links import media. - fixtures/import/: representative .docx/.odt corpus (headings, lists, nested lists, tables, images, links, bold/italic) with expected-Markdown snapshots; scripts/gen-import-fixtures.mjs regenerates them. - tests: import.service.db.test.ts drives the full pipeline with a fake converter (CI); import.fixtures.test.ts runs the real two-pass conversion over the corpus and a 50-page timing check against a reachable sidecar. - i18n: import_unsupported_format (de+en). Limits documented (25 MiB input, 60 s per pass). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
76 lines
4.2 KiB
JSON
76 lines
4.2 KiB
JSON
{
|
|
"bad_request": "The request is invalid.",
|
|
"unauthorized": "Please sign in to continue.",
|
|
"forbidden": "You do not have permission for this action.",
|
|
"not_found": "The requested resource does not exist.",
|
|
"conflict": "The request conflicts with the current state.",
|
|
"gone": "This resource is no longer available.",
|
|
"payload_too_large": "The submitted data is too large.",
|
|
"rate_limited": "Too many requests — please try again later.",
|
|
"internal_error": "Internal server error.",
|
|
"registration_closed": "Registration is currently closed on this instance.",
|
|
"token_invalid": "This link is invalid or has expired.",
|
|
"login_failed": "Username/e-mail or password is incorrect.",
|
|
"login_backoff": "Too many failed attempts — please wait a few minutes.",
|
|
"email_unverified": "Please confirm your e-mail address first.",
|
|
"account_disabled": "This account has been disabled.",
|
|
"password_incorrect": "The current password is incorrect.",
|
|
"csrf_origin_mismatch": "The request came from an unexpected origin.",
|
|
"cannot_revoke_current_session": "Use sign-out to end your current session.",
|
|
"personal_pond_undeletable": "The personal pond cannot be deleted.",
|
|
"quota_exceeded": "The quota has been reached (limit: {{limit}}).",
|
|
"slug_taken": "This slug is already taken in this pond.",
|
|
"page_document_too_large": "The page is too large (limit: {{limitBytes}} bytes).",
|
|
"invalid_page_state": "The submitted page content is invalid.",
|
|
"page_trashed": "This page has been moved to the trash.",
|
|
"label_name_taken": "A label with this name already exists at this level.",
|
|
"label_cycle": "A label cannot be moved into its own subtree.",
|
|
"label_depth_exceeded": "Labels can be nested at most {{max}} levels deep.",
|
|
"label_has_pages": "This label still has pages assigned; confirm to detach them.",
|
|
"label_wrong_pond": "This label belongs to a different pond.",
|
|
"unsupported_file_type": "This file type is not supported.",
|
|
"upload_type_not_allowed": "This file type is not allowed on this instance.",
|
|
"file_too_large": "The file is too large (limit: {{limitBytes}} bytes).",
|
|
"converter_unavailable": "The document converter is currently unavailable. Please try again later.",
|
|
"converter_timeout": "The conversion took too long and was cancelled.",
|
|
"conversion_failed": "This document could not be converted.",
|
|
"import_unsupported_format": "Only Word (.docx) and OpenDocument (.odt) documents can be imported.",
|
|
"network": "The server could not be reached.",
|
|
"grant_exists": "This grant already exists.",
|
|
"grant_pond_admin_scope": "A Pond Admin grant must apply to the whole pond and a specific user.",
|
|
"grant_pond_admin_personal_pond": "A personal pond's only administrator is its owner.",
|
|
"grant_subject_id_mismatch": "The grant's subject is inconsistent.",
|
|
"grant_scope_id_mismatch": "The grant's scope is inconsistent.",
|
|
"grant_scope_not_found": "The label or page this grant points to does not exist in this pond.",
|
|
"grant_subject_not_found": "This user does not exist.",
|
|
"grant_last_admin": "The last Pond Admin cannot be removed.",
|
|
"member_not_found": "No user with that username or e-mail exists.",
|
|
"member_exists": "This user is already a member of this pond.",
|
|
"member_not_a_member": "This user is not a member of this pond.",
|
|
"member_is_owner": "The pond owner's membership cannot be changed here.",
|
|
"cannot_modify_self": "You cannot perform this action on your own account.",
|
|
"last_site_admin": "The last Site Admin cannot be removed.",
|
|
"validation": {
|
|
"required": "This field is required.",
|
|
"taken": "This value is already taken.",
|
|
"username": {
|
|
"tooShort": "The username needs at least 3 characters.",
|
|
"tooLong": "The username can have at most 32 characters.",
|
|
"charset": "Only letters, digits, and hyphens are allowed."
|
|
},
|
|
"password": {
|
|
"tooShort": "The password needs at least 10 characters.",
|
|
"tooLong": "The password can have at most 128 characters.",
|
|
"tooCommon": "This password is too common."
|
|
},
|
|
"email": {
|
|
"invalid": "Please enter a valid e-mail address."
|
|
},
|
|
"displayName": {
|
|
"required": "Please enter a display name."
|
|
},
|
|
"labelColor": "Please enter a colour like #a1b2c3.",
|
|
"tooLong": "The input is too long."
|
|
}
|
|
}
|