Documentation
¶
Overview ¶
Package newdoc answers one question: what are the BYTES of a brand-new, empty document of type X?
Why this is not trivial ¶
For a .md or a .csv the answer is "none" — a zero-byte file is a valid, empty text file and every editor opens it. For a .docx it is not: an Office document is a ZIP of XML parts, and a zero-byte file named report.docx is rejected by Word, by OnlyOffice and by LibreOffice alike. The same is true of .xlsx, .pptx and the OpenDocument trio. So "create an empty file" splits into two genuinely different jobs and this package owns the hard one.
Why the bytes are embedded rather than generated ¶
The obvious alternative is to shell out to `soffice --headless --convert-to` at create time. It was rejected because it is not available where the product runs: the full image (ghcr.io/brf-tech/filex:vX) carries LibreOffice, but `:slim` and the bare `filex` binary deliberately carry no external tools at all — that is the documented point of those distributions. A feature that silently works on one image and 500s on another is worse than a feature with a narrower promise, so the bytes come from the binary itself: a few KB of XML, identical on every distribution, with no process to spawn and nothing to be absent.
Why the templates are XML files and not .docx blobs ¶
The parts live under templates/ as readable XML and are zipped in memory on demand. A committed .docx would be an opaque binary in the diff — nobody could review a change to it, and nobody could tell a corrupted one from a deliberate one. As text, every part is reviewable and the ZIP container is reconstructed by code that is itself tested.
⚠ The ZIP is built with an explicit part manifest, NOT by walking the embedded tree. Two of the formats care about entry ORDER: an OpenDocument file must carry `mimetype` as its FIRST entry, STORED (uncompressed) and with no extra field, because that is what puts the media type at byte offset 38 where every magic-byte sniffer looks for it. A lexical walk puts META-INF first and the file stops being recognisable as an ODF document while still being a perfectly valid ZIP — which is exactly the kind of failure that passes every test that only asks "does it unzip?".
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrUnknownType = errors.New("newdoc: unknown document type")
ErrUnknownType is returned for an extension this build cannot create.
Functions ¶
Types ¶
type Group ¶
type Group string
Group is the coarse family a type belongs to. It exists for the picker's section headings; it is NOT the capability gate (see Type.Requires).
type Requirement ¶
type Requirement string
Requirement names the external service a client needs before it should offer this type to a person.
⚠ The server states the dependency; it does not resolve it. Whether OnlyOffice is actually reachable is already answered by /api/files/capabilities (external.onlyoffice), and an embedder may point at a document server this process cannot see — so the client is the only place that knows the true answer. What the client must NOT do is re-derive the dependency from a hardcoded extension list of its own: that list would rot the moment this registry grows a type.
const ( // RequiresNothing — a built-in editor handles it (code / markdown). RequiresNothing Requirement = "" // RequiresOnlyOffice — only the OnlyOffice surface can open it. RequiresOnlyOffice Requirement = "onlyoffice" // RequiresDrawio — only the drawio surface can open it. RequiresDrawio Requirement = "drawio" )
type Type ¶
type Type struct {
Ext string `json:"ext"`
Group Group `json:"group"`
MIME string `json:"mime"`
Requires Requirement `json:"requires,omitempty"`
// ExtRequired says the file must carry this extension (#56). True for the
// containers — an office document or a diagram is a ZIP or an XML file
// that its editor finds BY extension, so "report" with no extension is a
// document nothing opens. False for text: the new file is zero bytes and
// is just as valid called LICENSE, Makefile or test.conf, so the person
// names it whatever they like.
//
// ⚠ Never `omitempty`. A client tells a server from before #56 by this
// key being ABSENT (that server appends the extension to every type), so
// `false` has to be on the wire.
ExtRequired bool `json:"ext_required"`
}
Type is one creatable document type, as published to clients.
There is deliberately no label here. Labels are localised, the catalogues live in the frontend package, and a server-rendered English string would be the one piece of this dialog that could not be translated.