@dforge-core/metadata 0.0.43 → 0.0.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,45 @@ All notable changes to `@dforge-core/metadata` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this package adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.0.45] — 2026-10-24
9
+
10
+ ### Added
11
+
12
+ - **DSL `attachText(content, fileName, encoding?, mimeType?)` / `attachBase64(base64, fileName,
13
+ mimeType?)`:** build a file for `sendEmail()`'s fourth argument, keeping its own type (an `.ics` as
14
+ `text/calendar`). Unlike a `printPdf()` result they have no owner, so a scheduled job can attach them.
15
+ Listed in `BUILTINS`; they share the per-run file limit with `downloadText()` / `downloadBase64()`.
16
+
17
+ ### Changed
18
+
19
+ - **DSL `sendEmail()`:** the attachments argument now accepts `attachText()` / `attachBase64()` results as
20
+ well as `printPdf()` ones.
21
+
22
+ ## [0.0.44] — 2026-10-21
23
+
24
+ ### Added
25
+
26
+ - **DSL `printPdf(entityCd, key, templateCd)`:** renders a print template to a PDF as the current user
27
+ and returns the stored file as a descriptor (`fileId`, `fileName`, `mimeType`, `size`, `checksum`).
28
+ Listed in `BUILTINS` with the entity argument checked at compile time.
29
+ - **DSL `sendEmail(to, subjectOrTemplate, dataOrBody?, attachments?)`:** an optional fourth argument
30
+ attaches files: a `printPdf()` result, or an array of them. At most 5 files and 10 MB per email.
31
+ - **DSL `downloadText(content, fileName, encoding?, mimeType?)` / `downloadBase64(base64, fileName,
32
+ mimeType?)`:** hand the user a file the script built (any code page such as `windows-1251`, line
33
+ endings as given). Both return the signed temp-file URL. Listed in `BUILTINS`; `download()` now points
34
+ to them.
35
+ - **`translations.schema.json`, `storedProcedures`:** result-column headers of a stored procedure
36
+ (`storedProcedures.<sp_cd>.columns.<column_cd>.label`), shared by every report bound to the procedure.
37
+ A report also takes a translated `desc`.
38
+
39
+ ### Changed
40
+
41
+ - **`reports.schema.json`, `columnDef`:** accepts `fieldTypeCd` and `format` (overrides `report.run`
42
+ applies) and `baseDatatypeCd` (read only when `columnsDef` is a dataset's whole column list). `visible`
43
+ stays accepted but is read by nothing. `ColumnDef` in `reports.ts` gains `fieldTypeCd` and `format`.
44
+ - **`entity.schema.json`, `traits`:** accepts a trait the module declares in its own `traits.json`, not only
45
+ the platform ones. Pack and install still refuse a name that is neither.
46
+
8
47
  ## [0.0.43] — 2026-10-19
9
48
 
10
49
  ### Added
@@ -53,8 +53,26 @@ interface ActionDef {
53
53
  * "Run in Background". A parameterless `isAsync` action is queued directly.
54
54
  */
55
55
  isAsync?: boolean;
56
+ /**
57
+ * Code of a print template of the action's entity. The run dialog renders it as a PDF beside the params when the
58
+ * action is opened on one record, so the user sees the document the action sends before it goes.
59
+ */
60
+ previewTemplate?: string;
61
+ /**
62
+ * Saved parameter sets the module ships for this action, keyed by set name. They install as shared sets owned by
63
+ * the module: read-only for users and refreshed on every install, and a user can save a set of their own under the
64
+ * same name, which wins for them. Each `values` key must be a param the action declares; a string starting with `=`
65
+ * is a formula. Needs the action to declare params.
66
+ */
67
+ paramSets?: Record<string, ActionParamSetDef>;
68
+ }
69
+ /** One shipped parameter set of an action. */
70
+ interface ActionParamSetDef {
71
+ description?: string;
72
+ /** Value by param code. */
73
+ values: Record<string, unknown>;
56
74
  }
57
75
  /** A `ui/actions.json` file: action code → definition. */
58
76
  type ActionsFile = Record<string, ActionDef>;
59
77
 
60
- export type { ActionExecutionMode as A, ActionDef as a, ActionsFile as b };
78
+ export type { ActionExecutionMode as A, ActionDef as a, ActionParamSetDef as b, ActionsFile as c };
@@ -1,4 +1,4 @@
1
- import { A as ActionExecutionMode } from '../actions-DvYTrCbP.js';
1
+ import { A as ActionExecutionMode } from '../actions-D-0G_mqf.js';
2
2
 
3
3
  type TokenKind = "ident" | "number" | "string" | "template" | "regex" | "punct" | "comment";
4
4
  interface Token {
package/dist/dsl/index.js CHANGED
@@ -854,9 +854,9 @@ var BUILTINS = [
854
854
  },
855
855
  {
856
856
  name: "sendEmail",
857
- signature: "sendEmail(to, subjectOrTemplate, dataOrBody?)",
857
+ signature: "sendEmail(to, subjectOrTemplate, dataOrBody?, attachments?)",
858
858
  returns: "void",
859
- doc: "Queue an outbound email. Three arguments, and the **second** picks the mode: `sendEmail(to, 'order.shipped', { ref: [code] })` sends a template, `sendEmail(to, 'Your order shipped', '<p>\u2026</p>')` sends raw HTML. A second argument with no spaces that contains `.` or `_` is read as a template code \u2014 so a raw subject like `'Shipped.'` silently becomes one; give a raw subject spaces. There is no fourth argument."
859
+ doc: "Queue an outbound email. Three arguments, and the **second** picks the mode: `sendEmail(to, 'order.shipped', { ref: [code] })` sends a template, `sendEmail(to, 'Your order shipped', '<p>\u2026</p>')` sends raw HTML. A second argument with no spaces that contains `.` or `_` is read as a template code \u2014 so a raw subject like `'Shipped.'` silently becomes one; give a raw subject spaces. The optional **fourth** argument attaches files: a `printPdf()`, `attachText()` or `attachBase64()` result, or an array of them (`[a, b]`; pass a single file as itself, because a one-name `[a]` reads as a field reference in the DSL). A `printPdf()` file can be attached only by the user who generated it (or a workspace admin) and not in a scheduled job; a file built with `attachText()` / `attachBase64()` has no owner and works everywhere, a scheduled job included. At most 5 files and 10 MB in all per email (`Email:MaxAttachments`, `Email:MaxAttachmentBytes`). A file the sender may not attach fails the action."
860
860
  },
861
861
  // External calls
862
862
  {
@@ -895,7 +895,31 @@ var BUILTINS = [
895
895
  name: "download",
896
896
  signature: "download(url, fileName?)",
897
897
  returns: "void",
898
- doc: "Set a download URL on the action result; the browser opens it when the action returns. It fetches nothing and stores nothing \u2014 the URL must already serve the bytes, e.g. the `/api/temp-file/{token}` a service handed back. To put a remote file INTO storage, fetch it with `callApi()` and write it to a file column."
898
+ doc: "Set a download URL on the action result; the browser opens it when the action returns. It fetches nothing and stores nothing \u2014 the URL must already serve the bytes, e.g. the `/api/temp-file/{token}` a service handed back. To hand over a file the script builds, use `downloadText()` / `downloadBase64()`. To put a remote file INTO storage, fetch it with `callApi()` and write it to a file column."
899
+ },
900
+ {
901
+ name: "downloadText",
902
+ signature: "downloadText(content, fileName, encoding?, mimeType?)",
903
+ returns: "string",
904
+ doc: "Hand the user a text file the script built: encodes `content` in `encoding` (`utf-8` by default; `windows-1251`, `cp866`, `koi8-u`\u2026 also work), stores it in temp storage and sets it as the action's download. Line endings are written as given (join with `'\\r\\n'` for CR LF), no BOM. Returns the signed `/api/temp-file/{token}` URL, valid for an hour (`FileStorage:TempTokenExpirationMinutes`). An action has one download: a later call replaces the earlier. In a background or scheduled run nobody receives the download, so pass the URL on in `notify()`. Max 10 MB per file, 10 files per run."
905
+ },
906
+ {
907
+ name: "downloadBase64",
908
+ signature: "downloadBase64(base64, fileName, mimeType?)",
909
+ returns: "string",
910
+ doc: "`downloadText()` for bytes: decodes `base64` and hands it to the user as `fileName` (`application/octet-stream` unless `mimeType` says otherwise). Returns the signed download URL."
911
+ },
912
+ {
913
+ name: "attachText",
914
+ signature: "attachText(content, fileName, encoding?, mimeType?)",
915
+ returns: "object",
916
+ doc: "Build a text file to attach to an email: encodes `content` in `encoding` (`utf-8` by default) and returns a descriptor for `sendEmail()`'s fourth argument, e.g. `sendEmail(to, 'Interview', body, attachText(ics, 'invite.ics', 'utf-8', 'text/calendar'))`. The file keeps `mimeType` (`text/plain` by default). It is the script's own output, so no user's rights are involved and it works in a scheduled job. Only the emails of this run can name it. Max 10 MB per file and 10 files per run, shared with `downloadText()` / `downloadBase64()`."
917
+ },
918
+ {
919
+ name: "attachBase64",
920
+ signature: "attachBase64(base64, fileName, mimeType?)",
921
+ returns: "object",
922
+ doc: "`attachText()` for bytes given as base64 (`application/octet-stream` unless `mimeType` says otherwise)."
899
923
  },
900
924
  {
901
925
  name: "getSetting",
@@ -948,6 +972,13 @@ var BUILTINS = [
948
972
  returns: "link",
949
973
  entityArg: 0,
950
974
  doc: "Build a clickable link to a record, for an `entitylink` column. Always pass a **qualified** code \u2014 `entity_cd` is only unique per module."
975
+ },
976
+ {
977
+ name: "printPdf",
978
+ signature: "printPdf(entityCd, key, templateCd)",
979
+ returns: "object",
980
+ entityArg: 0,
981
+ doc: "Render a print template to a PDF **as the current user** and return the stored file as `{ fileId, fileName, mimeType, size, checksum }` \u2014 a descriptor, never the bytes. `key` is the record's `{ column: value }` key (or a scalar for a single-column key); `templateCd` is the template's code on that entity. The record is read under the user's rights and the folder's row filter, as the Generate PDF button reads it. Always pass a **qualified** entity code. Not available in a scheduled job or a background action (no signed-in user), refused in a computing-only run, and limited to 10 per execution; each render holds the action's transaction open while it works."
951
982
  }
952
983
  ];
953
984
  var BUILTIN_BY_NAME = new Map(BUILTINS.map((b) => [b.name, b]));