@dforge-core/metadata 0.0.13 → 0.0.15
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 +144 -0
- package/dist/index.d.ts +128 -16
- package/dist/index.js.map +1 -1
- package/package.json +60 -60
- package/schemas/data_views.schema.json +40 -0
- package/schemas/manifest.schema.json +6 -0
- package/schemas/reports.schema.json +48 -19
- package/src/index.ts +3 -1
- package/src/manifest.ts +21 -0
- package/src/reports.ts +111 -12
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,150 @@ 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.15] — 2026-08-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`ManifestDef.features`** — opt-in platform behaviours a package was authored for,
|
|
13
|
+
typed as the new exported `ModuleFeature` union. Absent or empty means the
|
|
14
|
+
pre-feature behaviour for all of them, so a module written before a feature existed
|
|
15
|
+
keeps working until its author declares it and republishes.
|
|
16
|
+
|
|
17
|
+
```jsonc
|
|
18
|
+
"features": ["report-security"]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`"report-security"` makes this module's reports require the `E` right on their
|
|
22
|
+
security object; declare the matching `"report:<code>": "E"` grants in
|
|
23
|
+
`security/roles.json` first, or the reports go dark for every role. Unknown names
|
|
24
|
+
are rejected at package load rather than ignored — a misspelled feature would
|
|
25
|
+
otherwise leave the old behaviour in place while the manifest claims otherwise.
|
|
26
|
+
`schemas/manifest.schema.json` carries the matching `enum`, and the three lists
|
|
27
|
+
(schema enum, this union, and the server's `ModuleFeatures`) are edited together.
|
|
28
|
+
|
|
29
|
+
- **`ParamDef.columnType`** — `"R"` declares a REFERENCE parameter, whose submitted
|
|
30
|
+
value is the whole picked record rather than its bare key. The JSON counterpart of
|
|
31
|
+
the action DSL's `paramCd: ref <entityCd>`, stored in the same `param.column_type`.
|
|
32
|
+
The schema already accepted it; the type did not.
|
|
33
|
+
|
|
34
|
+
The choice is not cosmetic: omitting it (a plain `lookup`) submits the key, which is
|
|
35
|
+
what a filter comparing against a reference column needs, since the server
|
|
36
|
+
destructures a key object across every key column and ignores non-key fields.
|
|
37
|
+
Declare `"R"` when the report wants the record itself. Either way the picker is
|
|
38
|
+
configured by `params.link` (`{ entity, otherKey? }`), and `otherKey` is filled from
|
|
39
|
+
the target's primary key when omitted — comma-joined and paired POSITIONALLY with
|
|
40
|
+
the key columns.
|
|
41
|
+
|
|
42
|
+
- **`matrixViewConfig.calculatedMembers`** (schema) — synthetic read-only rows or
|
|
43
|
+
columns of a pivot-like view, derived by formula over OTHER members' values at each
|
|
44
|
+
cross-axis position (a Gross Margin % line, a Q1 total column). The feature shipped
|
|
45
|
+
some time ago and `gl`'s P&L matrix uses it, but `matrixViewConfig` is
|
|
46
|
+
`additionalProperties: false`, so declaring it was a validation error — editors
|
|
47
|
+
flagged a config the platform renders correctly.
|
|
48
|
+
|
|
49
|
+
The new `calculatedMember` `$def` mirrors `CalculatedMember` in `@dforge/data`:
|
|
50
|
+
`key`, `axis` (`row` default / `column`), `label`, `field`, `refs` (bracket-alias →
|
|
51
|
+
member identity), `formula`, `position`, `depth` and `format`. Platform-generic —
|
|
52
|
+
any pivot-like surface consumes the same shape, so adding an indicator is config
|
|
53
|
+
only, evaluated client-side by the stock formula engine.
|
|
54
|
+
|
|
55
|
+
- **Record-report attachments.** `ReportDef` gains `entities` — an array of
|
|
56
|
+
`ReportEntityAttachment` (also exported) declaring which entities a report can be
|
|
57
|
+
opened *from*, with the mapping from report parameter to source column on each. Each
|
|
58
|
+
entry becomes one `dForge.entity_report` row, and the report opens on a record-scoped
|
|
59
|
+
route with the record's values feeding its params server-side.
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
"credit_check": {
|
|
63
|
+
"entities": [
|
|
64
|
+
{ "entityCd": "parties.party", "params": { "customer_id": "party_id" }, "orderNum": 45 }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The binding lives on the attachment, not the report: the same report attaches to
|
|
70
|
+
several entities with different mappings, and reports stay entity-agnostic. A qualified
|
|
71
|
+
`entityCd` must name a declared dependency; source columns are limited to the PK, a
|
|
72
|
+
reference (`R`) column, or a bounded scalar, and must be type-compatible with the target
|
|
73
|
+
param. `schemas/reports.schema.json` carries the matching `entityAttachment` `$def`.
|
|
74
|
+
|
|
75
|
+
- **`ReportDef.reloadInterval`** — the report's auto-refresh interval in seconds. It has
|
|
76
|
+
worked since long before this release but was absent from the schema, and since the
|
|
77
|
+
report object is `additionalProperties: false`, setting it was a validation error.
|
|
78
|
+
|
|
79
|
+
### Changed — report parameters have a report-level home again
|
|
80
|
+
|
|
81
|
+
`ReportDef.parameters` is **kept and now implemented**. Parameters are report-scoped
|
|
82
|
+
throughout the platform — the declaration is stored once per report
|
|
83
|
+
(`report.param_set_id` → `param_set`), the authoring API is `report.params.save`, and
|
|
84
|
+
`report.get` flattens per-dataset defaults report-wide before use — but the installer had
|
|
85
|
+
only ever read the per-dataset shorthand, so a report-level block was silently dropped and
|
|
86
|
+
the report installed with no parameters at all.
|
|
87
|
+
|
|
88
|
+
Both sites are now legal and mean the same thing. The installer merges them into the
|
|
89
|
+
report's single parameter set, **report level winning** on a code collision:
|
|
90
|
+
|
|
91
|
+
```jsonc
|
|
92
|
+
"customer_statement": {
|
|
93
|
+
"parameters": {
|
|
94
|
+
"customer_id": { "label": "Customer", "fieldTypeCd": "lookup",
|
|
95
|
+
"params": { "link": { "entity": "parties.party" } }, "required": true }
|
|
96
|
+
},
|
|
97
|
+
"datasets": { "statement_invoices": { }, "statement_payments": { } }
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Declare a parameter at report level when more than one dataset uses it — there is no
|
|
102
|
+
meaningful dataset to attribute it to, which is why the exporter previously had to dump the
|
|
103
|
+
whole set onto "the first dataset that had params". `datasets.<cd>.params` stays fully
|
|
104
|
+
supported and is the right shorthand when exactly one dataset uses the parameter.
|
|
105
|
+
|
|
106
|
+
### Removed
|
|
107
|
+
|
|
108
|
+
- **`paramDef.isRequired` and `paramDef.link`.** Neither is read by the installer: the key
|
|
109
|
+
is `required` (so `isRequired` installed the parameter as optional), and a lookup's
|
|
110
|
+
binding nests under `params` as `params.link` (so a top-level `link` installed the
|
|
111
|
+
parameter with no autocomplete). Unlike `parameters` these are simply misspellings, with
|
|
112
|
+
a correct spelling already in the schema — so they are gone rather than implemented.
|
|
113
|
+
|
|
114
|
+
## [0.0.14] — 2026-08-10
|
|
115
|
+
|
|
116
|
+
### Added
|
|
117
|
+
|
|
118
|
+
- **A report parameter can borrow a column domain.** `paramDef` accepts `domain`
|
|
119
|
+
(`domain_cd` or `module_cd.domain_cd`) as an alternative to `fieldTypeCd`: the domain
|
|
120
|
+
supplies the control *and* the option list, so a list shared with the column the
|
|
121
|
+
parameter's value is written to is authored — and translated — exactly once instead of
|
|
122
|
+
being restated per parameter and left to drift. The action-DSL equivalent is
|
|
123
|
+
`paramCd: domain <domainCd>`, which has no JSON schema of its own.
|
|
124
|
+
|
|
125
|
+
`schemas/reports.schema.json` rejects exactly one combination —
|
|
126
|
+
`not: { required: ["fieldTypeCd", "domain"] }` — so declaring both is invalid, matching
|
|
127
|
+
the install-time check that refuses to silently pick a winner. Declaring neither stays
|
|
128
|
+
valid: the param installs as `text`.
|
|
129
|
+
|
|
130
|
+
### Changed
|
|
131
|
+
|
|
132
|
+
- **`ParamDef` is now a union, and `fieldTypeCd` is no longer required.** The type mirrors
|
|
133
|
+
the schema: one branch carries an optional `fieldTypeCd` (with `domain?: never`), the
|
|
134
|
+
other requires `domain` (with `fieldTypeCd?: never`). The shared members moved to an
|
|
135
|
+
exported `ParamDefBase`.
|
|
136
|
+
|
|
137
|
+
**Breaking for TypeScript consumers** in two ways, both intentional: a param literal
|
|
138
|
+
declaring both keys no longer compiles, and reading `p.fieldTypeCd` off a `ParamDef`
|
|
139
|
+
now yields `string | undefined` — a domain-backed param genuinely doesn't carry one,
|
|
140
|
+
and an inline param may omit it and take the `text` default. This is the
|
|
141
|
+
authoring-manifest type (what you write in `ui/reports.json`); the SDK's runtime
|
|
142
|
+
`ReportParamDef` is unchanged, since the server resolves the domain at install and the
|
|
143
|
+
wire payload always carries a concrete `fieldTypeCd` plus the merged option list.
|
|
144
|
+
|
|
145
|
+
- **`params.options` documentation.** The doc comment now spells out that a dropdown
|
|
146
|
+
param's options take the same rich `{value, label, icon, color}` form entity columns
|
|
147
|
+
use, and that a bare string list renders raw codes in every locale — which is what
|
|
148
|
+
action and report parameters did until dForge-core 1.20.0 gave them a place to put a
|
|
149
|
+
label. Per-locale option labels live in `translations/<locale>.json` under
|
|
150
|
+
`reports.<report_cd>.params.<param_cd>.options`.
|
|
151
|
+
|
|
8
152
|
## [0.0.13] — 2026-08-07
|
|
9
153
|
|
|
10
154
|
### Changed
|
package/dist/index.d.ts
CHANGED
|
@@ -737,27 +737,75 @@ type VizType = "table" | "chart" | "metric" | "pivot";
|
|
|
737
737
|
declare const vizTypes: readonly NamedKind[];
|
|
738
738
|
/** Chart kinds used by report `config.chartType` (curated; rendered via Chart.js). */
|
|
739
739
|
declare const chartTypes: readonly NamedKind[];
|
|
740
|
-
/**
|
|
741
|
-
interface
|
|
742
|
-
/** Field type code (see settings for the common list). */
|
|
743
|
-
fieldTypeCd: string;
|
|
740
|
+
/** Everything a report parameter carries regardless of where its control comes from. */
|
|
741
|
+
interface ParamDefBase {
|
|
744
742
|
label?: string;
|
|
745
743
|
/** Display order in the parameter form (falls back to declaration order). */
|
|
746
744
|
orderNum?: number;
|
|
747
|
-
/**
|
|
745
|
+
/**
|
|
746
|
+
* Whether the user must provide a value. Stored inverted as `param.is_nullable`.
|
|
747
|
+
* There is no `isRequired` spelling — the installer reads this key only.
|
|
748
|
+
*/
|
|
748
749
|
required?: boolean;
|
|
749
|
-
/** Alternate spelling of `required` used by some modules. Prefer `required`. */
|
|
750
|
-
isRequired?: boolean;
|
|
751
750
|
/** Default value applied when the user doesn't provide one. */
|
|
752
751
|
default?: unknown;
|
|
753
|
-
/**
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
752
|
+
/**
|
|
753
|
+
* Field-type-specific params, nested under this key — there is no top-level
|
|
754
|
+
* `link`. A lookup param needs `{ link: { entity, otherKey? } }`.
|
|
755
|
+
* Most importantly `options` for a dropdown.
|
|
756
|
+
* Options accept the same rich `{value,label,icon,color}` form entity columns
|
|
757
|
+
* use; a bare string list renders the raw codes in every locale, so label them.
|
|
758
|
+
* Omitted on a domain-backed param: the domain owns the list.
|
|
759
|
+
*/
|
|
759
760
|
params?: Record<string, unknown>;
|
|
761
|
+
/**
|
|
762
|
+
* Declares a REFERENCE parameter: the submitted value is the whole picked
|
|
763
|
+
* record rather than its bare key. The JSON counterpart of the action DSL's
|
|
764
|
+
* `paramCd: ref <entityCd>`, stored in the same `param.column_type`.
|
|
765
|
+
*
|
|
766
|
+
* Optional, and the choice is not cosmetic. Omitting it (a plain `lookup`)
|
|
767
|
+
* submits the key, which is what a filter comparing against a reference
|
|
768
|
+
* column needs — the server destructures a key object across every key
|
|
769
|
+
* column and ignores non-key fields. Declare `"R"` when the report wants the
|
|
770
|
+
* record itself, not just its identity.
|
|
771
|
+
*
|
|
772
|
+
* Either way the picker is configured by `params.link` (`{ entity, otherKey? }`);
|
|
773
|
+
* `otherKey` is filled from the target's primary key when omitted, comma-joined
|
|
774
|
+
* and paired POSITIONALLY with the key columns.
|
|
775
|
+
*/
|
|
776
|
+
columnType?: "R";
|
|
760
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* A report parameter definition. Declared in the report-level `parameters` block,
|
|
780
|
+
* or as shorthand under the `params` of the dataset that consumes it — the
|
|
781
|
+
* installer merges both into the report's single param set, so either way the
|
|
782
|
+
* parameter serves the whole report. Report level wins on a code collision, and
|
|
783
|
+
* is the only sensible home for a parameter several datasets use.
|
|
784
|
+
*
|
|
785
|
+
* A parameter takes its control from an explicit `fieldTypeCd` **or** from a
|
|
786
|
+
* column `domain` — never both. Declaring both is the one rejected combination
|
|
787
|
+
* (`not: { required: ["fieldTypeCd", "domain"] }` in `reports.schema.json`, and an
|
|
788
|
+
* install-time check that refuses to silently pick a winner). Declaring **neither**
|
|
789
|
+
* is fine: the param installs as `text`.
|
|
790
|
+
*
|
|
791
|
+
* Prefer `domain` whenever the choices are the same list a column uses (the usual
|
|
792
|
+
* case, since the value normally ends up written to that column): the options and
|
|
793
|
+
* their translations then live on the domain and are authored once, instead of
|
|
794
|
+
* being restated per parameter and left to drift.
|
|
795
|
+
*/
|
|
796
|
+
type ParamDef = (ParamDefBase & {
|
|
797
|
+
/** Field type code (see settings for the common list). Defaults to `text`. */
|
|
798
|
+
fieldTypeCd?: string;
|
|
799
|
+
domain?: never;
|
|
800
|
+
}) | (ParamDefBase & {
|
|
801
|
+
/**
|
|
802
|
+
* Column domain (`domain_cd` or `module_cd.domain_cd`) supplying the control
|
|
803
|
+
* and the option list. The DSL equivalent for action params is
|
|
804
|
+
* `paramCd: domain <domainCd>`.
|
|
805
|
+
*/
|
|
806
|
+
domain: string;
|
|
807
|
+
fieldTypeCd?: never;
|
|
808
|
+
});
|
|
761
809
|
/** SQL/entity query for a `datasetType: 'Q'` dataset. */
|
|
762
810
|
interface ReportQuery {
|
|
763
811
|
/** Source entity code. */
|
|
@@ -785,9 +833,40 @@ interface Dataset {
|
|
|
785
833
|
procedureName?: string;
|
|
786
834
|
/** Optional column metadata overrides: field code → override. */
|
|
787
835
|
columnsDef?: Record<string, ColumnDef>;
|
|
788
|
-
/**
|
|
836
|
+
/**
|
|
837
|
+
* Parameters declared on this dataset — shorthand for the report-level
|
|
838
|
+
* `parameters` block, convenient when exactly one dataset uses the parameter.
|
|
839
|
+
* The installer merges both into the report's one param set either way.
|
|
840
|
+
*/
|
|
789
841
|
params?: Record<string, ParamDef>;
|
|
790
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* One (entity, report) **record-report attachment**: the report becomes openable
|
|
845
|
+
* from that entity's record, with the record's values feeding its parameters.
|
|
846
|
+
* Each entry becomes one `dForge.entity_report` row.
|
|
847
|
+
*
|
|
848
|
+
* The binding is per-attachment, not per-report — the same report can attach to
|
|
849
|
+
* several entities with different parameter mappings, which is why the mapping
|
|
850
|
+
* lives here rather than on the report.
|
|
851
|
+
*/
|
|
852
|
+
interface ReportEntityAttachment {
|
|
853
|
+
/**
|
|
854
|
+
* Entity the report attaches to, qualified `module.entity` for anything
|
|
855
|
+
* outside the declaring module. That module must be a declared dependency.
|
|
856
|
+
*/
|
|
857
|
+
entityCd: string;
|
|
858
|
+
/**
|
|
859
|
+
* Parameter mapping: report param code → **source column on the entity**.
|
|
860
|
+
* (Not a param declaration — those live in the report's `parameters` block or a
|
|
861
|
+
* dataset's `params`.) Resolved server-side
|
|
862
|
+
* from the record's PK. Source columns are limited to the PK, reference (`R`)
|
|
863
|
+
* columns, and bounded scalars; source and target must be type-compatible.
|
|
864
|
+
* Params left unmapped keep their normal behaviour (default, or prompt).
|
|
865
|
+
*/
|
|
866
|
+
params?: Record<string, string>;
|
|
867
|
+
/** Sort position in the record's combined action + report menu. */
|
|
868
|
+
orderNum?: number;
|
|
869
|
+
}
|
|
791
870
|
/** A single visualization panel within the report layout. */
|
|
792
871
|
interface ReportPanel {
|
|
793
872
|
vizType: VizType;
|
|
@@ -807,8 +886,21 @@ interface ReportDef {
|
|
|
807
886
|
layout: ReportLayout;
|
|
808
887
|
/** Dataset code → dataset definition. */
|
|
809
888
|
datasets: Record<string, Dataset>;
|
|
810
|
-
/**
|
|
889
|
+
/** Auto-refresh interval in seconds. Omit (or 0) for no auto-refresh. */
|
|
890
|
+
reloadInterval?: number;
|
|
891
|
+
/**
|
|
892
|
+
* Report-level parameter declarations — the canonical home for a parameter, and
|
|
893
|
+
* the only one that fits a parameter several datasets use. Merged with each
|
|
894
|
+
* dataset's `params` into the report's single param set; this block wins on a
|
|
895
|
+
* code collision.
|
|
896
|
+
*/
|
|
811
897
|
parameters?: Record<string, ParamDef>;
|
|
898
|
+
/**
|
|
899
|
+
* Record-report attachments: entities this report can be opened from, with the
|
|
900
|
+
* mapping from report parameter to source column on each. Omit for a report
|
|
901
|
+
* that is only reached from a menu.
|
|
902
|
+
*/
|
|
903
|
+
entities?: ReportEntityAttachment[];
|
|
812
904
|
}
|
|
813
905
|
/** A `ui/reports.json` file: report code → definition. */
|
|
814
906
|
type ReportsFile = Record<string, ReportDef>;
|
|
@@ -823,6 +915,12 @@ type ModuleDependency = string | {
|
|
|
823
915
|
version: string;
|
|
824
916
|
entities?: string[];
|
|
825
917
|
};
|
|
918
|
+
/**
|
|
919
|
+
* A platform behaviour a package can opt into via `manifest.features`.
|
|
920
|
+
* Mirrors `dForge.Core.ModuleFeatures` and the `features` enum in
|
|
921
|
+
* manifest.schema.json — all three are edited together.
|
|
922
|
+
*/
|
|
923
|
+
type ModuleFeature = "report-security";
|
|
826
924
|
/** A module package manifest (`manifest.json`). */
|
|
827
925
|
interface ManifestDef {
|
|
828
926
|
/** Package format version (currently 1). */
|
|
@@ -860,6 +958,20 @@ interface ManifestDef {
|
|
|
860
958
|
icon?: string;
|
|
861
959
|
/** Non-English locales the package promises to translate. */
|
|
862
960
|
supportedLocales?: string[];
|
|
961
|
+
/**
|
|
962
|
+
* Opt-in platform behaviours this package was authored for. Absent or empty
|
|
963
|
+
* = the pre-feature behaviour for all of them, so a module written before a
|
|
964
|
+
* feature existed keeps working until its author declares it and republishes.
|
|
965
|
+
*
|
|
966
|
+
* Unknown names are rejected at package load, never ignored — a misspelled
|
|
967
|
+
* feature would silently leave the old behaviour in place while the manifest
|
|
968
|
+
* claims otherwise.
|
|
969
|
+
*
|
|
970
|
+
* - `report-security` — this module's reports require 'E' on their
|
|
971
|
+
* `sec_object`. Declare the matching `"report:<code>": "E"` grants in
|
|
972
|
+
* `security/roles.json` first, or the reports go dark for every role.
|
|
973
|
+
*/
|
|
974
|
+
features?: ModuleFeature[];
|
|
863
975
|
/** Initial creation date (YYYY-MM-DD). Informational. */
|
|
864
976
|
created?: string;
|
|
865
977
|
/** Last manifest edit date (YYYY-MM-DD). Informational. */
|
|
@@ -1221,4 +1333,4 @@ declare const flagDefs: readonly {
|
|
|
1221
1333
|
label: string;
|
|
1222
1334
|
}[];
|
|
1223
1335
|
|
|
1224
|
-
export { AGG_TYPE_LIST, type AccumulationConfig, type ActionDef, type ActionExecutionMode, type ActionsFile, AggType, type AlignType, type BaseDatatypeCd, type CalendarViewConfig, type ColumnDef, type ColumnTypeCd, type ColumnTypeDef, DEP_COLUMN_TYPES, type DataSource, type DataViewDef, type DataViewsFile, type Dataset, type DepColumn, type DepColumnMode, type DepColumnType, type DepEntity, type DepProvenance, type DepProvenanceKind, type DepsFile, type DeriveOptions, type DiagramViewConfig, type DomainDef, type DomainsFile, type EntityDef, type EntityEvent, type EntityReference, FILTER_GROUP_OPERATORS, FILTER_OPERATORS, type FieldDef, type FieldLink, type FieldOption, type FieldTypeCd, type FieldTypeDef, type Filter, type FilterCondition, type FilterGroup, type FilterGroupOperator, type FilterOperator, type FlagCd, type FolderDef, type FolderEntityBinding, type FoldersFile, type JobDef, type JobsFile, type KanbanViewConfig, type LedgerRegistryEntry, type ListLevelConfig, type ListViewConfig, type ManifestAuthor, type ManifestDef, type MenuDef, type MenuItemDef, type MenuItemType, type MenusFile, type ModuleDependency, NUMERIC_TOTAL, type NamedKind, type NumberSequenceDef, type ParamDef, type PeriodConfig, type PrintMargins, type PrintPageSettings, type PrintTemplateDef, type PrintTemplatesFile, type ReportDef, type ReportLayout, type ReportPanel, type ReportQuery, type ReportsFile, type RoleDef, type RolesFile, type SeedDataFile, type SettingBaseDatatype, type SettingDef, type SettingsFile, type SignConfig, type SortClause, type TraitCd, type TraitDef, type TreeGridViewConfig, type TriggerDef, type TriggersFile, type ViewColumn, type ViewType, type VizType, type WebhookPayload, type WebhookSubscription, type WebhooksFile, baseDatatypes, baseToDbDatatype, chartTypes, columnTypes, dataViewKinds, defaultParams, deriveBaseDatatype, deriveDbDatatype, expandTrait, expandTraits, fieldTypeCds, fieldTypes, fieldTypesByColumnType, flagDefs, getColumnType, getFieldType, getIdentityKeys, getLinks, getPrimaryKeys, getTrait, isFieldTypeCd, traits, vizTypes };
|
|
1336
|
+
export { AGG_TYPE_LIST, type AccumulationConfig, type ActionDef, type ActionExecutionMode, type ActionsFile, AggType, type AlignType, type BaseDatatypeCd, type CalendarViewConfig, type ColumnDef, type ColumnTypeCd, type ColumnTypeDef, DEP_COLUMN_TYPES, type DataSource, type DataViewDef, type DataViewsFile, type Dataset, type DepColumn, type DepColumnMode, type DepColumnType, type DepEntity, type DepProvenance, type DepProvenanceKind, type DepsFile, type DeriveOptions, type DiagramViewConfig, type DomainDef, type DomainsFile, type EntityDef, type EntityEvent, type EntityReference, FILTER_GROUP_OPERATORS, FILTER_OPERATORS, type FieldDef, type FieldLink, type FieldOption, type FieldTypeCd, type FieldTypeDef, type Filter, type FilterCondition, type FilterGroup, type FilterGroupOperator, type FilterOperator, type FlagCd, type FolderDef, type FolderEntityBinding, type FoldersFile, type JobDef, type JobsFile, type KanbanViewConfig, type LedgerRegistryEntry, type ListLevelConfig, type ListViewConfig, type ManifestAuthor, type ManifestDef, type MenuDef, type MenuItemDef, type MenuItemType, type MenusFile, type ModuleDependency, type ModuleFeature, NUMERIC_TOTAL, type NamedKind, type NumberSequenceDef, type ParamDef, type ParamDefBase, type PeriodConfig, type PrintMargins, type PrintPageSettings, type PrintTemplateDef, type PrintTemplatesFile, type ReportDef, type ReportEntityAttachment, type ReportLayout, type ReportPanel, type ReportQuery, type ReportsFile, type RoleDef, type RolesFile, type SeedDataFile, type SettingBaseDatatype, type SettingDef, type SettingsFile, type SignConfig, type SortClause, type TraitCd, type TraitDef, type TreeGridViewConfig, type TriggerDef, type TriggersFile, type ViewColumn, type ViewType, type VizType, type WebhookPayload, type WebhookSubscription, type WebhooksFile, baseDatatypes, baseToDbDatatype, chartTypes, columnTypes, dataViewKinds, defaultParams, deriveBaseDatatype, deriveDbDatatype, expandTrait, expandTraits, fieldTypeCds, fieldTypes, fieldTypesByColumnType, flagDefs, getColumnType, getFieldType, getIdentityKeys, getLinks, getPrimaryKeys, getTrait, isFieldTypeCd, traits, vizTypes };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/aggregation.ts","../src/field-types.ts","../src/base-datatypes.ts","../src/column-types.ts","../src/traits.ts","../src/derive.ts","../src/filter.ts","../src/entity-meta.ts","../src/data-views.ts","../src/reports.ts","../src/deps.ts","../src/index.ts"],"sourcesContent":["// Aggregation types — the kinds of aggregation a column/report value can use.\n//\n// Declared as a `const` object + derived union (not a TS `enum`) so the package\n// stays enum-free like the rest of its registries, while callers keep the\n// ergonomic `AggType.Sum` member access. `AggType.Sum === \"sum\"` at runtime, so\n// the value is interchangeable with the plain string everywhere.\n\nexport const AggType = {\n\tSum: \"sum\",\n\tCount: \"count\",\n\tAvg: \"avg\",\n\tMin: \"min\",\n\tMax: \"max\",\n\tGroup: \"group\",\n} as const;\n\n/** One of the aggregation codes (\"sum\" | \"count\" | …). */\nexport type AggType = (typeof AggType)[keyof typeof AggType];\n\n/** All aggregation types as an array (useful for iteration). */\nexport const AGG_TYPE_LIST: readonly AggType[] = Object.values(AggType);\n","// Field-type registry — mirror of\n// server/database/system-modules/metadata/seed-data/field_types.json\n//\n// This is the authoring source of truth: an author picks a `fieldTypeCd` and the\n// editor derives `baseDatatypeCd` + `dbDatatype` from the entry here. Kept in\n// sync with the server seed by the parity test in test/registries.test.ts —\n// if that test fails after a seed change, regenerate this list.\n\nimport type { FieldTypeCd, FieldTypeDef } from \"./types\";\n\n// `satisfies` (not `: readonly FieldTypeDef[]`) so the literal `cd` values are\n// preserved in the type — that powers the compile-time coverage guard below.\nexport const fieldTypes = [\n\t{ cd: \"text\", name: \"Text\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"avatar\", name: \"Avatar Name\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"email\", name: \"Email\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"phone\", name: \"Phone\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"url\", name: \"URL\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"textarea\", name: \"Multiline Text\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"number\", name: \"Number\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"SCAM\", maxLen: null, precision: null, useStringInFilter: false, defParams: { min: 0, max: 10000 } },\n\t{ cd: \"currency\", name: \"Currency\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"SCAM\", maxLen: null, precision: 2, useStringInFilter: false, defParams: { min: 0, max: 1000000 } },\n\t{ cd: \"percent\", name: \"Percent\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"CAM\", maxLen: null, precision: 2, useStringInFilter: false, defParams: { min: 0, max: 100 } },\n\t{ cd: \"checkbox\", name: \"Checkbox\", columnType: \"D\", baseDatatypeCd: \"bool\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"date\", name: \"Date\", columnType: \"D\", baseDatatypeCd: \"date\", supportedAgg: \"CM\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"datetime\", name: \"Date & Time\", columnType: \"D\", baseDatatypeCd: \"timestamp\", supportedAgg: \"CM\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"time\", name: \"Time\", columnType: \"D\", baseDatatypeCd: \"time\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"dropdown\", name: \"Dropdown\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"flags\", name: \"Flags\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true, defParams: { style: \"buttons\" } },\n\t{ cd: \"json\", name: \"JSON Editor\", columnType: \"D\", baseDatatypeCd: \"json\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"hidden\", name: \"Hidden\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"color\", name: \"Color Picker\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: 20, precision: null, useStringInFilter: false },\n\t{ cd: \"image\", name: \"Image\", columnType: \"D\", baseDatatypeCd: \"binary\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"file\", name: \"File\", columnType: \"D\", baseDatatypeCd: \"binary\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"markdown\", name: \"Markdown\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"richtext\", name: \"Rich Text Editor\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"lookup\", name: \"Lookup\", columnType: \"R\", baseDatatypeCd: \"guid\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"user\", name: \"User Picker\", columnType: \"D\", baseDatatypeCd: \"cuid\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"grid\", name: \"Detail Grid\", columnType: \"S\", baseDatatypeCd: \"set\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"list\", name: \"Detail List\", columnType: \"S\", baseDatatypeCd: \"set\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"tags\", name: \"Tags\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"entitylink\", name: \"Entity Link\", columnType: \"D\", baseDatatypeCd: \"json\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"code\", name: \"Code Editor\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n] as const satisfies readonly FieldTypeDef[];\n\n// Compile-time coverage guard: every `FieldTypeCd` must have a row above, and\n// every row's `cd` must be a `FieldTypeCd`. If the union and the array drift\n// apart, one of these two assignments fails to compile.\ntype _MissingFromArray = Exclude<FieldTypeCd, (typeof fieldTypes)[number][\"cd\"]>;\ntype _MissingFromUnion = Exclude<(typeof fieldTypes)[number][\"cd\"], FieldTypeCd>;\nconst _coverageOk: [_MissingFromArray, _MissingFromUnion] = [undefined as never, undefined as never];\nvoid _coverageOk;\n\nconst byCd = new Map<string, FieldTypeDef>(fieldTypes.map((ft) => [ft.cd, ft]));\n\n/** Set of all known field type codes, for membership checks. */\nexport const fieldTypeCds: ReadonlySet<string> = new Set(fieldTypes.map((ft) => ft.cd));\n\n/** Type guard: is `cd` one of the known field type codes? */\nexport function isFieldTypeCd(cd: string | undefined): cd is FieldTypeCd {\n\treturn cd != null && fieldTypeCds.has(cd);\n}\n\n/** Look up a field type by code, or `undefined` if unknown. */\nexport function getFieldType(cd: string): FieldTypeDef | undefined {\n\treturn byCd.get(cd);\n}\n\n/** Field types whose default column kind is `columnType` (e.g. \"D\" value types). */\nexport function fieldTypesByColumnType(columnType: string): readonly FieldTypeDef[] {\n\treturn fieldTypes.filter((ft) => ft.columnType === columnType);\n}\n","// Base datatype registry — mirror of\n// server/database/system-modules/metadata/seed-data/base_datatypes.json\n//\n// Plus the canonical mapping from an abstract base datatype to the default\n// PostgreSQL column type the platform generates. The visual editor uses this so\n// the author never has to type a raw SQL type.\n\nimport type { BaseDatatypeCd } from \"./types\";\n\nexport const baseDatatypes: readonly BaseDatatypeCd[] = [\n\t\"binary\",\n\t\"bool\",\n\t\"culture\",\n\t\"cuid\",\n\t\"date\",\n\t\"guid\",\n\t\"json\",\n\t\"link\",\n\t\"number\",\n\t\"project\",\n\t\"ref\",\n\t\"set\",\n\t\"string\",\n\t\"time\",\n\t\"timestamp\",\n\t\"xml\",\n] as const;\n\n// Default PostgreSQL type per base datatype. `null` entries are non-physical\n// (relationship/virtual) base types that never produce a column on their own.\nconst BASE_TO_DB: Record<BaseDatatypeCd, string | null> = {\n\tbinary: \"bytea\",\n\tbool: \"bool\",\n\tculture: \"varchar\",\n\tcuid: \"cuid\",\n\tdate: \"date\",\n\tguid: \"uuid\",\n\tjson: \"jsonb\",\n\tlink: null,\n\tnumber: \"numeric\",\n\tproject: \"varchar\",\n\tref: null,\n\tset: null,\n\tstring: \"varchar\",\n\ttime: \"time\",\n\ttimestamp: \"timestamptz\",\n\txml: \"xml\",\n};\n\n/** Default PostgreSQL type for a base datatype, or `null` if non-physical. */\nexport function baseToDbDatatype(base: string): string | null {\n\treturn (BASE_TO_DB as Record<string, string | null>)[base] ?? null;\n}\n","// Column-type registry — the seven column kinds a field can have. Letters match\n// the `column.column_type` values and entity.schema.json. The `name` /\n// `description` here drive the friendly \"what kind of field is this?\" picker.\n\nimport type { ColumnTypeDef } from \"./types\";\n\nexport const columnTypes: readonly ColumnTypeDef[] = [\n\t{ cd: \"D\", name: \"Value\", description: \"A plain data column stored on this entity.\" },\n\t{ cd: \"R\", name: \"Reference\", description: \"An N:1 lookup to another entity (foreign key).\" },\n\t{ cd: \"S\", name: \"Child list\", description: \"A 1:N collection of child records from another entity.\" },\n\t{ cd: \"F\", name: \"Formula\", description: \"A virtual value calculated from a formula expression.\" },\n\t{ cd: \"G\", name: \"Generated\", description: \"A physical column auto-maintained by the database (aggregate or expression).\" },\n\t{ cd: \"A\", name: \"Accumulation register\", description: \"Posts this document into a balance entity (single direction).\" },\n\t{ cd: \"L\", name: \"Ledger register\", description: \"Posts document lines into movements + balances (double entry).\" },\n] as const;\n\nconst byCd = new Map<string, ColumnTypeDef>(columnTypes.map((ct) => [ct.cd, ct]));\n\n/** Look up a column type by letter. */\nexport function getColumnType(cd: string): ColumnTypeDef | undefined {\n\treturn byCd.get(cd);\n}\n","// Trait registry — mirror of\n// server/database/system-modules/metadata/traits.json\n//\n// Traits are authoring shortcuts: adding one to an entity injects a fixed set of\n// fields (and sometimes references) at install time. The visual editor offers\n// these as checkboxes and previews the expanded fields, so authors never\n// hand-write `created_date` / `{entity}_id` etc.\n\nimport type { FieldDef, TraitDef } from \"./types\";\n\nexport const traits: readonly TraitDef[] = [\n\t{\n\t\tcd: \"identity\",\n\t\tdescription: \"Primary Key\",\n\t\tfields: {\n\t\t\t\"{entity}_id\": { dbDatatype: \"cuid\", flags: \"I\", isPk: true, isIdentity: true, isNullable: false, orderNum: 1, description: \"{Entity} ID\" },\n\t\t},\n\t},\n\t{\n\t\tcd: \"audit\",\n\t\tdescription: \"Creation and update timestamps\",\n\t\tfields: {\n\t\t\tcreated_date: { dbDatatype: \"timestamptz\", fieldTypeCd: \"datetime\", flags: \"I\", isNullable: false, orderNum: 9901, description: \"Created Date\", params: { serverDefault: { value: \"now()\", on: \"insert\" } } },\n\t\t\tlast_updated: { dbDatatype: \"timestamptz\", fieldTypeCd: \"datetime\", flags: \"I\", isNullable: false, orderNum: 9902, description: \"Last Updated\", params: { serverDefault: { value: \"now()\", on: \"save\" } } },\n\t\t},\n\t},\n\t{\n\t\tcd: \"audit-full\",\n\t\tdescription: \"Full audit with user tracking\",\n\t\tincludes: [\"audit\"],\n\t\tfields: {\n\t\t\tcreated_by: { dbDatatype: \"cuid\", flags: \"I\", isNullable: false, orderNum: 9903, description: \"Created By User ID\", params: { serverDefault: { value: \"currentUser()\", on: \"insert\" } } },\n\t\t\tcreated_by_user: { columnType: \"R\", fieldTypeCd: \"lookup\", flags: \"I\", orderNum: 9904, description: \"Created By\", link: { entity: \"user\", thisKey: \"created_by\", otherKey: \"user_id\" } },\n\t\t\tlast_updated_by: { dbDatatype: \"cuid\", flags: \"I\", isNullable: false, orderNum: 9905, description: \"Last Updated By User ID\", params: { serverDefault: { value: \"currentUser()\", on: \"save\" } } },\n\t\t\tlast_updated_by_user: { columnType: \"R\", fieldTypeCd: \"lookup\", flags: \"I\", orderNum: 9906, description: \"Last Updated By\", link: { entity: \"user\", thisKey: \"last_updated_by\", otherKey: \"user_id\" } },\n\t\t},\n\t\treferences: {\n\t\t\t\"FK_{Entity}_CreatedBy\": { from: { field: \"created_by\" }, to: { entity: \"user\", field: \"user_id\" } },\n\t\t\t\"FK_{Entity}_LastUpdatedBy\": { from: { field: \"last_updated_by\" }, to: { entity: \"user\", field: \"user_id\" } },\n\t\t},\n\t},\n\t{\n\t\tcd: \"soft-delete\",\n\t\tdescription: \"Soft delete flag\",\n\t\tfields: {\n\t\t\tactive: { dbDatatype: \"bool\", fieldTypeCd: \"checkbox\", flags: \"\", isNullable: false, formula: \"true\", orderNum: 9910, description: \"Active\" },\n\t\t},\n\t},\n\t{\n\t\tcd: \"sorting\",\n\t\tdescription: \"Display order\",\n\t\tfields: {\n\t\t\torder_num: { dbDatatype: \"int4\", fieldTypeCd: \"number\", flags: \"VE\", orderNum: 9920, description: \"Order\" },\n\t\t},\n\t},\n\t{ cd: \"postable\", description: \"Document posting support (marker trait — actual state managed by A/L columns)\", fields: {} },\n\t{ cd: \"accumulation\", description: \"Accumulation register (marker trait — config in A-type column params)\", fields: {} },\n\t{ cd: \"ledger\", description: \"Double-entry ledger (marker trait — config in L-type column params)\", fields: {} },\n\t{\n\t\tcd: \"period\",\n\t\tdescription: \"Period entity with key format, closed flag, date range\",\n\t\tfields: {\n\t\t\tperiod_key: { dbDatatype: \"varchar\", fieldTypeCd: \"text\", flags: \"VE\", isPk: true, isNullable: false, maxLen: 20, orderNum: 1, description: \"Period Key\" },\n\t\t\tdescription: { dbDatatype: \"varchar\", fieldTypeCd: \"text\", flags: \"VE\", maxLen: 100, orderNum: 30, description: \"Description\" },\n\t\t\tclosed: { dbDatatype: \"bool\", fieldTypeCd: \"checkbox\", flags: \"VE\", isNullable: false, formula: \"false\", orderNum: 40, description: \"Closed\" },\n\t\t\tstart_date: { dbDatatype: \"date\", fieldTypeCd: \"date\", flags: \"VE\", orderNum: 50, description: \"Start Date\" },\n\t\t\tend_date: { dbDatatype: \"date\", fieldTypeCd: \"date\", flags: \"VE\", orderNum: 60, description: \"End Date\" },\n\t\t},\n\t},\n] as const;\n\nconst byCd = new Map(traits.map((t) => [t.cd, t]));\n\n/** Look up a trait by code. */\nexport function getTrait(cd: string): TraitDef | undefined {\n\treturn byCd.get(cd);\n}\n\n/** Title-case a snake_case entity code for the `{Entity}` template token. */\nfunction titleCaseEntity(entity: string): string {\n\tconst local = entity.split(\".\").pop() ?? entity;\n\treturn local\n\t\t.split(/[_\\s]+/)\n\t\t.filter(Boolean)\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join(\" \");\n}\n\nfunction applyTemplate(value: string, entity: string): string {\n\tconst local = entity.split(\".\").pop() ?? entity;\n\treturn value.replace(/\\{entity\\}/g, local).replace(/\\{Entity\\}/g, titleCaseEntity(entity));\n}\n\nfunction templateFields(fields: Record<string, FieldDef>, entity: string): Record<string, FieldDef> {\n\tconst out: Record<string, FieldDef> = {};\n\tfor (const [name, def] of Object.entries(fields)) {\n\t\tconst key = applyTemplate(name, entity);\n\t\tconst next: FieldDef = { ...def };\n\t\tif (typeof next.description === \"string\") next.description = applyTemplate(next.description, entity);\n\t\tout[key] = next;\n\t}\n\treturn out;\n}\n\n/**\n * Expand a trait (and any traits it includes) into the concrete fields it adds\n * for `entityName`, with `{entity}` / `{Entity}` tokens resolved. Returns an\n * empty object for unknown or marker traits. Field order follows include-depth\n * first, then declaration order; later definitions win on key collisions.\n */\nexport function expandTrait(traitCd: string, entityName: string): Record<string, FieldDef> {\n\tconst trait = byCd.get(traitCd);\n\tif (!trait) return {};\n\tconst result: Record<string, FieldDef> = {};\n\tfor (const included of trait.includes ?? []) {\n\t\tObject.assign(result, expandTrait(included, entityName));\n\t}\n\tObject.assign(result, templateFields(trait.fields, entityName));\n\treturn result;\n}\n\n/** Expand several traits in order into one merged field map. */\nexport function expandTraits(traitCds: readonly string[], entityName: string): Record<string, FieldDef> {\n\tconst result: Record<string, FieldDef> = {};\n\tfor (const cd of traitCds) Object.assign(result, expandTrait(cd, entityName));\n\treturn result;\n}\n","// Derivation helpers — turn a friendly field-type choice into the physical\n// metadata the platform needs, so the author never types a raw SQL type.\n//\n// Defaults follow how core modules actually author fields (e.g. currency →\n// numeric(18,2), color → varchar(20)); callers may always override the result.\n\nimport { baseToDbDatatype } from \"./base-datatypes\";\nimport { getFieldType } from \"./field-types\";\n\n/** Total digits used when building a `numeric(total, scale)` type. */\nexport const NUMERIC_TOTAL = 18;\n\n/** Field types whose natural storage is unbounded `text` rather than `varchar`. */\nconst TEXT_BACKED = new Set([\"textarea\", \"markdown\", \"richtext\", \"code\"]);\n\n/**\n * Field types the server pins to a fixed column type regardless of their base\n * datatype — mirrors `DdlService.ResolveDbTypeFromFieldType`. `file`/`image`\n * classify as `binary`, but dForge stores them as a JSON metadata reference\n * (`{ storagePath, fileName, … }`), NOT inline `bytea`; the column is `jsonb`.\n * Without this override the base path derives `bytea`, and the file-attach\n * pipeline — which reads/writes that JSON — fails on save.\n */\nconst DB_DATATYPE_OVERRIDE: Record<string, string> = {\n\tfile: \"jsonb\",\n\timage: \"jsonb\",\n};\n\nexport interface DeriveOptions {\n\t/** Author-specified max length; overrides the field type's default. */\n\tmaxLen?: number | null;\n\t/** Author-specified numeric scale; overrides the field type's default. */\n\tprecision?: number | null;\n}\n\n/**\n * Derive the PostgreSQL `dbDatatype` for a field type. Returns `null` for\n * field types backed by relationships/sets (lookup, grid) that have no physical\n * column of their own. Unknown field types fall back to `varchar`.\n */\nexport function deriveDbDatatype(fieldTypeCd: string, options: DeriveOptions = {}): string | null {\n\tconst ft = getFieldType(fieldTypeCd);\n\tif (!ft) return \"varchar\";\n\n\t// Relationship-backed types (lookup → R, grid → S) never own a physical\n\t// column — the FK lives on a separate hidden column.\n\tif (ft.columnType === \"R\" || ft.columnType === \"S\") return null;\n\n\t// Server-pinned column types that don't follow the base-datatype path\n\t// (file/image → jsonb, not bytea). Mirrors ResolveDbTypeFromFieldType.\n\tconst override = DB_DATATYPE_OVERRIDE[ft.cd];\n\tif (override) return override;\n\n\tconst base = baseToDbDatatype(ft.baseDatatypeCd);\n\tif (base === null) return null; // other non-physical base (link/ref/set)\n\n\tif (ft.baseDatatypeCd === \"number\") {\n\t\tconst precision = options.precision ?? ft.precision;\n\t\treturn precision != null ? `numeric(${NUMERIC_TOTAL},${precision})` : \"numeric\";\n\t}\n\n\tif (ft.baseDatatypeCd === \"string\") {\n\t\tif (TEXT_BACKED.has(ft.cd)) return \"text\";\n\t\tconst maxLen = options.maxLen ?? ft.maxLen;\n\t\treturn maxLen != null ? `varchar(${maxLen})` : \"varchar\";\n\t}\n\n\treturn base;\n}\n\n/** Default `params` to seed a new field of this type with (or `undefined`). */\nexport function defaultParams(fieldTypeCd: string): Record<string, unknown> | undefined {\n\tconst ft = getFieldType(fieldTypeCd);\n\tif (!ft?.defParams) return undefined;\n\treturn { ...ft.defParams };\n}\n\n/** The base datatype code a field type maps to (for `baseDatatypeCd` on F columns). */\nexport function deriveBaseDatatype(fieldTypeCd: string): string | undefined {\n\treturn getFieldType(fieldTypeCd)?.baseDatatypeCd;\n}\n","// Canonical dForge filter expression.\n//\n// One shape shared by data views, reports, folders (row-level security) and the\n// API: either a single condition `{c, o, v}` or a group `{g, i: [...]}`. Mirror\n// of the `filter` $def repeated across data_views / reports / folders schemas.\n\n/**\n * Every operator the server's FilterBuilder translates — the closed set the\n * `o` enum in the data_views / reports / folders schemas mirrors, and the set\n * the installer validates a package's filters against.\n *\n * Symbolic forms and their word aliases are equivalent (`=`/`eq`, `!=`/`notEq`,\n * `>`/`gr`, …); a leading `!` negates, with `n`-prefixed spellings as the alias\n * (`!in`/`nIn`). Note the two spellings authors most often get wrong: null\n * checks are `null` / `!null` (not `isNull` / `isNotNull`) and substring\n * matching is `contains` (not `like`).\n */\nexport const FILTER_OPERATORS = [\n\t\"=\", \"eq\", \"!=\", \"notEq\",\n\t\">\", \"gr\", \">=\", \"grEq\", \"<\", \"less\", \"<=\", \"lessEq\",\n\t\"eqRef\",\n\t\"contains\", \"!contains\", \"nContain\",\n\t\"start\", \"!start\", \"nStart\",\n\t\"end\", \"!end\", \"nEnd\",\n\t\"mask\", \"!mask\", \"nMask\",\n\t\"null\", \"empty\", \"!null\", \"nEmpty\",\n\t\"in\", \"!in\", \"nIn\",\n\t\"between\", \"btw\", \"!between\", \"nBetween\",\n\t\"f\", \"func\",\n] as const;\n\nexport type FilterOperator = (typeof FILTER_OPERATORS)[number];\n\n/** Every group combinator the server recognizes. `!`/`n` forms negate the group. */\nexport const FILTER_GROUP_OPERATORS = [\"and\", \"or\", \"!and\", \"nAnd\", \"!or\", \"nOr\"] as const;\n\nexport type FilterGroupOperator = (typeof FILTER_GROUP_OPERATORS)[number];\n\n/** A single filter condition. */\nexport interface FilterCondition {\n\t/** Column code (supports dot navigation: 'customer.name'). */\n\tc: string;\n\t/** Operator — see {@link FILTER_OPERATORS}. */\n\to: FilterOperator;\n\t/** Comparison value: scalar, array (in/nIn) or a `@param_code` reference. */\n\tv?: unknown;\n}\n\n/** A boolean group of nested conditions/sub-groups. */\nexport interface FilterGroup {\n\t/** Group combinator. */\n\tg: FilterGroupOperator;\n\t/** Group items: nested conditions or sub-groups. */\n\ti: Filter[];\n}\n\n/** A filter is either a single condition or a group. */\nexport type Filter = FilterCondition | FilterGroup;\n\n/** A sort clause `{ c, d }` as used by reports / per-source order. */\nexport interface SortClause {\n\t/** Column code. */\n\tc: string;\n\t/** Sort direction (default: asc). */\n\td?: \"asc\" | \"desc\";\n}\n","// Entity introspection helpers — derive the projections clients commonly need\n// (primary keys, identity-trait keys, reference links) from a raw EntityDef.\n// Shared so the editor, web app and CLI compute these the same way instead of\n// each reimplementing the rules.\n\nimport type { EntityDef } from \"./entity\";\nimport { expandTrait } from \"./traits\";\n\n/** `{ field, target }` for each Reference (R) column that declares a link. */\nexport function getLinks(entity: EntityDef): Array<{ field: string; target: string }> {\n\tconst links: Array<{ field: string; target: string }> = [];\n\tfor (const [code, field] of Object.entries(entity.fields ?? {})) {\n\t\tif (field.columnType === \"R\" && field.link?.entity) {\n\t\t\tlinks.push({ field: code, target: field.link.entity });\n\t\t}\n\t}\n\treturn links;\n}\n\n/**\n * Identity-trait primary-key column codes for `entityCode` (e.g. `invoice_id`),\n * excluding any the author already declared explicitly. Empty unless the entity\n * carries the `identity` trait.\n */\nexport function getIdentityKeys(entity: EntityDef, entityCode: string): string[] {\n\tif (!entity.traits?.includes(\"identity\")) return [];\n\tconst explicit = new Set(Object.keys(entity.fields ?? {}));\n\treturn Object.keys(expandTrait(\"identity\", entityCode)).filter((key) => !explicit.has(key));\n}\n\n/**\n * All primary-key column codes: fields flagged `isPk`, plus identity-trait keys.\n * Order is explicit-first, then identity keys; duplicates removed.\n */\nexport function getPrimaryKeys(entity: EntityDef, entityCode: string): string[] {\n\tconst explicit = Object.entries(entity.fields ?? {})\n\t\t.filter(([, field]) => field.isPk)\n\t\t.map(([code]) => code);\n\tconst seen = new Set(explicit);\n\tconst result = [...explicit];\n\tfor (const key of getIdentityKeys(entity, entityCode)) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n","// Data-view registries + the authoring shape of a `ui/data_views.json` file.\n//\n// `dataViewKinds` is the friendly picker list; `DataViewDef` and friends mirror\n// the structural `data_views.schema.json` so editors/MCP/CLI can build views.\n\nimport type { Filter } from \"./filter\";\nimport type { NamedKind } from \"./types\";\n\nexport type { NamedKind };\n\n/** `viewType` values for `ui/data_views.json`. Source: data_views.schema.json. */\nexport type ViewType =\n\t| \"grid\"\n\t| \"list\"\n\t| \"kanban\"\n\t| \"calendar\"\n\t| \"gallery\"\n\t| \"tree-grid\"\n\t| \"diagram\"\n\t| \"master-detail\"\n\t| \"library\"\n\t| \"matrix\";\n\n/** Friendly picker list of the view kinds. */\nexport const dataViewKinds: readonly NamedKind[] = [\n\t{ cd: \"grid\", name: \"Grid\" },\n\t{ cd: \"list\", name: \"List\" },\n\t{ cd: \"kanban\", name: \"Kanban\" },\n\t{ cd: \"calendar\", name: \"Calendar\" },\n\t{ cd: \"gallery\", name: \"Gallery\" },\n\t{ cd: \"tree-grid\", name: \"Tree Grid\" },\n\t{ cd: \"diagram\", name: \"Diagram\" },\n\t{ cd: \"master-detail\", name: \"Master / Detail\" },\n\t{ cd: \"library\", name: \"Library\" },\n\t{ cd: \"matrix\", name: \"Matrix\" },\n] as const;\n\n/** A column in a data source: shorthand string code or a configured object. */\nexport type ViewColumn =\n\t| string\n\t| {\n\t\t\t/** Column code. */\n\t\t\tcolumn_cd: string;\n\t\t\t/** Column width in pixels. */\n\t\t\twidth?: number;\n\t\t\t/** Whether the column is visible (default true). */\n\t\t\tvisible?: boolean;\n\t\t\t/** Pin column to an edge. */\n\t\t\tpinned?: \"left\" | \"right\";\n\t };\n\n/** One data source within a view. */\nexport interface DataSource {\n\t/** Entity code to query. */\n\tentityCode: string;\n\t/** Nesting level (0 = root, 1+ = detail). */\n\tlevel?: number;\n\t/** Human-readable label (used in master-detail tabs). */\n\tlabel?: string;\n\t/** Column configuration. */\n\tcolumns?: ViewColumn[];\n\t/** Set field on the parent entity linking to this detail level. */\n\tparentSetField?: string;\n\t/** Per-source filter; overrides the view-level filter for this source. */\n\tfilter?: Filter;\n\t/** Per-source sort order (array of `{ c, d }` entries). */\n\torder?: unknown;\n}\n\nexport interface KanbanViewConfig {\n\t/** Dropdown/flags/reference column to group cards by. */\n\tgroupByField: string;\n}\n\nexport interface CalendarViewConfig {\n\t/** Date/timestamp column used to place events. */\n\tdateField: string;\n\t/** Column shown as event title (defaults to the entity toString). */\n\ttitleField?: string;\n\t/** Column whose value drives the event pill color. */\n\tcolorField?: string;\n}\n\nexport interface TreeGridViewConfig {\n\t/** Self-referencing FK column (parent record). */\n\tparentField: string;\n\t/** Node label field (defaults to entity toString). */\n\tlabelField?: string;\n\t/** Field containing a Bootstrap icon class per node. */\n\ticonField?: string;\n}\n\nexport interface ListLevelConfig {\n\t/** Entity code for this child level. */\n\tentityCode: string;\n\t/** FK column in the child entity linking back to the parent. */\n\tforeignKey: string;\n\t/** Columns to display inline for each child row. */\n\tcolumns?: string[];\n}\n\nexport interface ListViewConfig {\n\ttitleField?: string;\n\tsubtitleField?: string;\n\t/** Hierarchical child levels for expandable list rows. */\n\tlevels?: ListLevelConfig[];\n}\n\nexport interface DiagramViewConfig {\n\t/** Column to group diagram nodes by. */\n\tgroupByField?: string;\n\t/** Group values hidden by default. */\n\tdefaultHiddenGroups?: string[];\n}\n\n/** A single data view (value in the `ui/data_views.json` map). */\nexport interface DataViewDef {\n\tviewType: ViewType;\n\t/** Human-readable view name. */\n\tlabel?: string;\n\t/** Bootstrap icon class (e.g. 'bi-bounding-box'). */\n\ticon?: string;\n\tdescription?: string;\n\t/** Data sources (at least one; master-detail needs two). */\n\tdataSources: DataSource[];\n\t/** Default filter applied to all sources unless one declares its own. */\n\tfilter?: Filter;\n\t/** Default sort order. */\n\torder?: unknown;\n\t/** View-type-specific configuration. */\n\tviewConfig?:\n\t\t| KanbanViewConfig\n\t\t| CalendarViewConfig\n\t\t| TreeGridViewConfig\n\t\t| ListViewConfig\n\t\t| DiagramViewConfig\n\t\t| Record<string, unknown>;\n}\n\n/** A `ui/data_views.json` file: data view code → definition. */\nexport type DataViewsFile = Record<string, DataViewDef>;\n","// Report registries + the authoring shape of a `ui/reports.json` file.\n//\n// `vizTypes` / `chartTypes` are the friendly picker lists; `ReportDef` and\n// friends mirror reports.schema.json so editors/MCP/CLI can build reports.\n\nimport type { Filter, SortClause } from \"./filter\";\nimport type { NamedKind } from \"./types\";\n\n/** Report visualization types. Source: reports.schema.json (`vizType`). */\nexport type VizType = \"table\" | \"chart\" | \"metric\" | \"pivot\";\n\n/** Friendly picker list of report visualization types. */\nexport const vizTypes: readonly NamedKind[] = [\n\t{ cd: \"table\", name: \"Table\" },\n\t{ cd: \"chart\", name: \"Chart\" },\n\t{ cd: \"metric\", name: \"Metric\" },\n\t{ cd: \"pivot\", name: \"Pivot\" },\n] as const;\n\n/** Chart kinds used by report `config.chartType` (curated; rendered via Chart.js). */\nexport const chartTypes: readonly NamedKind[] = [\n\t{ cd: \"bar\", name: \"Bar\" },\n\t{ cd: \"line\", name: \"Line\" },\n\t{ cd: \"area\", name: \"Area\" },\n\t{ cd: \"pie\", name: \"Pie\" },\n\t{ cd: \"donut\", name: \"Donut\" },\n\t{ cd: \"scatter\", name: \"Scatter\" },\n\t{ cd: \"bubble\", name: \"Bubble\" },\n\t{ cd: \"heatmap\", name: \"Heatmap\" },\n\t{ cd: \"funnel\", name: \"Funnel\" },\n] as const;\n\n/** A report parameter definition (report- or dataset-level). */\nexport interface ParamDef {\n\t/** Field type code (see settings for the common list). */\n\tfieldTypeCd: string;\n\tlabel?: string;\n\t/** Display order in the parameter form (falls back to declaration order). */\n\torderNum?: number;\n\t/** Whether the user must provide a value. */\n\trequired?: boolean;\n\t/** Alternate spelling of `required` used by some modules. Prefer `required`. */\n\tisRequired?: boolean;\n\t/** Default value applied when the user doesn't provide one. */\n\tdefault?: unknown;\n\t/** Entity link for lookup-type params. */\n\tlink?: { entity: string; otherKey?: string };\n\t/** Field-type-specific params. */\n\tparams?: Record<string, unknown>;\n}\n\n/** SQL/entity query for a `datasetType: 'Q'` dataset. */\nexport interface ReportQuery {\n\t/** Source entity code. */\n\tentityCd: string;\n\t/** Column codes to select (supports dot navigation: 'customer.name'). */\n\tcolumns?: string[];\n\tfilter?: Filter;\n\tsort?: SortClause[];\n}\n\n/** Per-column metadata override on a dataset. */\nexport interface ColumnDef {\n\tlabel?: string;\n\tvisible?: boolean;\n\twidth?: number;\n}\n\n/** A report dataset (value in the report's `datasets` map). */\nexport interface Dataset {\n\t/** Display label (used in panel headings if no `title`). */\n\tcaption?: string;\n\t/** Q = SQL/entity query, S = stored procedure. */\n\tdatasetType: \"Q\" | \"S\";\n\t/** Used when `datasetType` is 'Q'. */\n\tquery?: ReportQuery;\n\t/** Used when `datasetType` is 'S'. */\n\tprocedureName?: string;\n\t/** Optional column metadata overrides: field code → override. */\n\tcolumnsDef?: Record<string, ColumnDef>;\n\t/** Dataset-level parameters (alternative to report-level `parameters`). */\n\tparams?: Record<string, ParamDef>;\n}\n\n/** A single visualization panel within the report layout. */\nexport interface ReportPanel {\n\tvizType: VizType;\n\t/** Dataset code (key in the report's `datasets` map). */\n\tdatasetCd: string;\n\ttitle?: string;\n\t/** Viz-type-specific config (chart → { chartType, categoryCol, … }). */\n\tconfig?: Record<string, unknown>;\n}\n\nexport interface ReportLayout {\n\tpanels: ReportPanel[];\n}\n\n/** A single report (value in the `ui/reports.json` map). */\nexport interface ReportDef {\n\t/** Human-readable report title. */\n\tdescription: string;\n\tlayout: ReportLayout;\n\t/** Dataset code → dataset definition. */\n\tdatasets: Record<string, Dataset>;\n\t/** Report-level parameters (alternative to per-dataset `params`). */\n\tparameters?: Record<string, ParamDef>;\n}\n\n/** A `ui/reports.json` file: report code → definition. */\nexport type ReportsFile = Record<string, ReportDef>;\n","// Dependency contracts — authoring shape of `deps/<provider>.json`. Mirror of deps.schema.json.\n//\n// One file per dependency declares everything a consumer module consumes from a\n// provider: the entities, columns (each pinned to its provider storage class — a\n// Postgres type token like int8/varchar/numeric, not a base datatype), and the\n// provenance of each usage. The provider stays the source of truth; this is the\n// consumer's import list. See docs/modules/dependency-contracts.md.\n\n/**\n * Allowed storage-class tokens for a consumed column — Postgres type names with\n * length/scale stripped. Closed allowlist, kept in lockstep with the `type` enum in\n * `deps.schema.json` (and `DependencyContractValidator.ValidColumnTypes` on the C#\n * side); the `schemas.test.ts` parity guard fails if this drifts from the schema.\n * Extend all three together if a provider column legitimately uses a type not here.\n */\nexport const DEP_COLUMN_TYPES = [\n\t\"int2\", \"int4\", \"int8\", \"smallint\", \"integer\", \"bigint\",\n\t\"numeric\", \"decimal\", \"float4\", \"float8\", \"real\", \"money\",\n\t\"varchar\", \"text\", \"char\", \"bpchar\",\n\t\"bool\", \"boolean\",\n\t\"date\", \"time\", \"timetz\", \"timestamp\", \"timestamptz\",\n\t\"uuid\", \"json\", \"jsonb\", \"bytea\",\n] as const;\n\n/**\n * Storage class pinned for a consumed column — the provider's physical Postgres type\n * with length/scale stripped (e.g. `int8`, `numeric`, `varchar`). dForge's `cuid`\n * Snowflake PK normalizes to `int8`. Pinning the storage class (not a coarse base\n * type) keeps FK/lookup compatibility meaningful — an `int8` key needs `int8`, not\n * any number. One of {@link DEP_COLUMN_TYPES}.\n */\nexport type DepColumnType = (typeof DEP_COLUMN_TYPES)[number];\n\n/** Whether the consumer reads or writes a column. Default `read`. */\nexport type DepColumnMode = \"read\" | \"write\";\n\n/** Kinds of cross-module usage a provenance token can name. */\nexport type DepProvenanceKind =\n\t| \"ref\"\n\t| \"extends\"\n\t| \"formula\"\n\t| \"action\"\n\t| \"view\"\n\t| \"report\"\n\t| \"print\"\n\t| \"role\";\n\n/**\n * A usage token of the form `<kind>:<symbol>` — e.g. `ref:invoice.customer`,\n * `extends:party`, `action:check_credit`, `role:fin.admin`. Names the consuming\n * symbol so the completeness lint can reconcile declared vs actual usage. Note:\n * `display` is intentionally not a kind — the label is the provider's concern.\n */\nexport type DepProvenance = `${DepProvenanceKind}:${string}`;\n\n/** A single consumed provider column. */\nexport interface DepColumn {\n\t/** Storage class — the provider column's physical Postgres type, params stripped (`int8`, `varchar`, `numeric`, …). */\n\ttype: DepColumnType;\n\t/** Per-column provenance: which symbols read/write/join on this column. */\n\tuse: DepProvenance[];\n\t/** `write` implies an insert/update right + settable column. Default `read`; omit for reads. */\n\tmode?: DepColumnMode;\n}\n\n/** What the consumer needs from one provider entity. */\nexport interface DepEntity {\n\t/** The provider entity's PK column — the anchor every reference joins on. No label/display. */\n\tpk: string;\n\t/** Entity-level provenance: why this entity is consumed (ref/extends/role/view/report/print/action). */\n\tuse: DepProvenance[];\n\t/** Provider columns actually read/written/joined. Omit for extension-only targets. */\n\tcolumns?: Record<string, DepColumn>;\n}\n\n/** A `deps/<provider>.json` file: the consumer's contract against one dependency. */\nexport interface DepsFile {\n\t/** Code of the dependency (provider) module this contract is against (e.g. `parties`). */\n\tmodule: string;\n\t/** Semver range the consumer requires of the provider (e.g. `>=0.1.0`). */\n\tversion: string;\n\t/** Consumed provider entities, keyed by entity code. */\n\tentities: Record<string, DepEntity>;\n}\n","// @dforge-core/metadata — canonical dForge authoring registries + module-file types.\n//\n// Single source of truth for:\n// • registries — field types, base datatypes, column types, traits, data-view\n// kinds, report viz/chart types, plus helpers that derive physical metadata\n// from a friendly field-type choice;\n// • structural types — the authoring shape of every module-package file\n// (manifest, entities, data views, reports, menus, folders, roles, settings,\n// jobs, triggers, webhooks, print templates, seed data, actions), mirrored\n// from the JSON schemas under docs/schemas/.\n//\n// No runtime dependencies; safe to import from editors, the web app, the CLI,\n// the MCP server and the VS Code extension.\n\n// ── Shared core types & registries ──────────────────────────────────────────\nexport type {\n\tAlignType,\n\tBaseDatatypeCd,\n\tColumnTypeCd,\n\tColumnTypeDef,\n\tFieldDef,\n\tFieldLink,\n\tFieldOption,\n\tFieldTypeCd,\n\tFieldTypeDef,\n\tFlagCd,\n\tNamedKind,\n\tTraitDef,\n} from \"./types\";\n\nexport { AggType, AGG_TYPE_LIST } from \"./aggregation\";\n\nexport { fieldTypes, fieldTypeCds, isFieldTypeCd, getFieldType, fieldTypesByColumnType } from \"./field-types\";\nexport { baseDatatypes, baseToDbDatatype } from \"./base-datatypes\";\nexport { columnTypes, getColumnType } from \"./column-types\";\nexport { traits, getTrait, expandTrait, expandTraits } from \"./traits\";\nexport {\n\tderiveDbDatatype,\n\tderiveBaseDatatype,\n\tdefaultParams,\n\tNUMERIC_TOTAL,\n\ttype DeriveOptions,\n} from \"./derive\";\n\n// ── Shared filter expression (data views / reports / folders / API) ──────────\nexport type {\n\tFilter,\n\tFilterCondition,\n\tFilterGroup,\n\tFilterGroupOperator,\n\tFilterOperator,\n\tSortClause,\n} from \"./filter\";\nexport { FILTER_GROUP_OPERATORS, FILTER_OPERATORS } from \"./filter\";\n\n// ── Module-file structural types ─────────────────────────────────────────────\nexport type {\n\tEntityDef,\n\tEntityReference,\n\tNumberSequenceDef,\n\tPeriodConfig,\n\tAccumulationConfig,\n\tSignConfig,\n\tLedgerRegistryEntry,\n\tTraitCd,\n} from \"./entity\";\n\n// Entity introspection helpers (primary keys, identity keys, reference links).\nexport { getLinks, getIdentityKeys, getPrimaryKeys } from \"./entity-meta\";\n\nexport {\n\tdataViewKinds,\n\ttype DataViewsFile,\n\ttype DataViewDef,\n\ttype DataSource,\n\ttype ViewColumn,\n\ttype ViewType,\n\ttype KanbanViewConfig,\n\ttype CalendarViewConfig,\n\ttype TreeGridViewConfig,\n\ttype ListViewConfig,\n\ttype ListLevelConfig,\n\ttype DiagramViewConfig,\n} from \"./data-views\";\n\nexport {\n\tvizTypes,\n\tchartTypes,\n\ttype ReportsFile,\n\ttype ReportDef,\n\ttype ReportLayout,\n\ttype ReportPanel,\n\ttype Dataset,\n\ttype ReportQuery,\n\ttype ColumnDef,\n\ttype ParamDef,\n\ttype VizType,\n} from \"./reports\";\n\nexport type { ManifestDef, ManifestAuthor, ModuleDependency } from \"./manifest\";\nexport type { DepsFile, DepEntity, DepColumn, DepColumnType, DepColumnMode, DepProvenance, DepProvenanceKind } from \"./deps\";\nexport { DEP_COLUMN_TYPES } from \"./deps\";\nexport type { DomainsFile, DomainDef } from \"./domains\";\nexport type { MenusFile, MenuDef, MenuItemDef, MenuItemType } from \"./menus\";\nexport type { FoldersFile, FolderDef, FolderEntityBinding } from \"./folders\";\nexport type { RolesFile, RoleDef } from \"./roles\";\nexport type { SettingsFile, SettingDef, SettingBaseDatatype } from \"./settings\";\nexport type { JobsFile, JobDef } from \"./jobs\";\nexport type { TriggersFile, TriggerDef, EntityEvent } from \"./triggers\";\nexport type { WebhooksFile, WebhookSubscription, WebhookPayload } from \"./webhooks\";\nexport type { PrintTemplatesFile, PrintTemplateDef, PrintPageSettings, PrintMargins } from \"./print-templates\";\nexport type { SeedDataFile } from \"./seed-data\";\nexport type { ActionsFile, ActionDef, ActionExecutionMode } from \"./actions\";\n\n// Display flag catalog — the only flags valid on an authored field\n// (entity.schema.json `flags` pattern is ^[VIEMH]*$).\nexport const flagDefs: readonly { value: \"V\" | \"I\" | \"E\" | \"M\" | \"H\"; label: string }[] = [\n\t{ value: \"V\", label: \"Visible\" },\n\t{ value: \"I\", label: \"Identity\" },\n\t{ value: \"E\", label: \"Editable\" },\n\t{ value: \"M\", label: \"Mandatory\" },\n\t{ value: \"H\", label: \"Hidden\" },\n] as const;\n"],"mappings":"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","names":["byCd","byCd"]}
|
|
1
|
+
{"version":3,"sources":["../src/aggregation.ts","../src/field-types.ts","../src/base-datatypes.ts","../src/column-types.ts","../src/traits.ts","../src/derive.ts","../src/filter.ts","../src/entity-meta.ts","../src/data-views.ts","../src/reports.ts","../src/deps.ts","../src/index.ts"],"sourcesContent":["// Aggregation types — the kinds of aggregation a column/report value can use.\n//\n// Declared as a `const` object + derived union (not a TS `enum`) so the package\n// stays enum-free like the rest of its registries, while callers keep the\n// ergonomic `AggType.Sum` member access. `AggType.Sum === \"sum\"` at runtime, so\n// the value is interchangeable with the plain string everywhere.\n\nexport const AggType = {\n\tSum: \"sum\",\n\tCount: \"count\",\n\tAvg: \"avg\",\n\tMin: \"min\",\n\tMax: \"max\",\n\tGroup: \"group\",\n} as const;\n\n/** One of the aggregation codes (\"sum\" | \"count\" | …). */\nexport type AggType = (typeof AggType)[keyof typeof AggType];\n\n/** All aggregation types as an array (useful for iteration). */\nexport const AGG_TYPE_LIST: readonly AggType[] = Object.values(AggType);\n","// Field-type registry — mirror of\n// server/database/system-modules/metadata/seed-data/field_types.json\n//\n// This is the authoring source of truth: an author picks a `fieldTypeCd` and the\n// editor derives `baseDatatypeCd` + `dbDatatype` from the entry here. Kept in\n// sync with the server seed by the parity test in test/registries.test.ts —\n// if that test fails after a seed change, regenerate this list.\n\nimport type { FieldTypeCd, FieldTypeDef } from \"./types\";\n\n// `satisfies` (not `: readonly FieldTypeDef[]`) so the literal `cd` values are\n// preserved in the type — that powers the compile-time coverage guard below.\nexport const fieldTypes = [\n\t{ cd: \"text\", name: \"Text\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"avatar\", name: \"Avatar Name\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"email\", name: \"Email\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"phone\", name: \"Phone\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"url\", name: \"URL\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"textarea\", name: \"Multiline Text\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"number\", name: \"Number\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"SCAM\", maxLen: null, precision: null, useStringInFilter: false, defParams: { min: 0, max: 10000 } },\n\t{ cd: \"currency\", name: \"Currency\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"SCAM\", maxLen: null, precision: 2, useStringInFilter: false, defParams: { min: 0, max: 1000000 } },\n\t{ cd: \"percent\", name: \"Percent\", columnType: \"D\", baseDatatypeCd: \"number\", supportedAgg: \"CAM\", maxLen: null, precision: 2, useStringInFilter: false, defParams: { min: 0, max: 100 } },\n\t{ cd: \"checkbox\", name: \"Checkbox\", columnType: \"D\", baseDatatypeCd: \"bool\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"date\", name: \"Date\", columnType: \"D\", baseDatatypeCd: \"date\", supportedAgg: \"CM\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"datetime\", name: \"Date & Time\", columnType: \"D\", baseDatatypeCd: \"timestamp\", supportedAgg: \"CM\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"time\", name: \"Time\", columnType: \"D\", baseDatatypeCd: \"time\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"dropdown\", name: \"Dropdown\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"flags\", name: \"Flags\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true, defParams: { style: \"buttons\" } },\n\t{ cd: \"json\", name: \"JSON Editor\", columnType: \"D\", baseDatatypeCd: \"json\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"hidden\", name: \"Hidden\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"color\", name: \"Color Picker\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: 20, precision: null, useStringInFilter: false },\n\t{ cd: \"image\", name: \"Image\", columnType: \"D\", baseDatatypeCd: \"binary\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"file\", name: \"File\", columnType: \"D\", baseDatatypeCd: \"binary\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"markdown\", name: \"Markdown\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"richtext\", name: \"Rich Text Editor\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: null, maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"lookup\", name: \"Lookup\", columnType: \"R\", baseDatatypeCd: \"guid\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"user\", name: \"User Picker\", columnType: \"D\", baseDatatypeCd: \"cuid\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"grid\", name: \"Detail Grid\", columnType: \"S\", baseDatatypeCd: \"set\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"list\", name: \"Detail List\", columnType: \"S\", baseDatatypeCd: \"set\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"tags\", name: \"Tags\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: true },\n\t{ cd: \"entitylink\", name: \"Entity Link\", columnType: \"D\", baseDatatypeCd: \"json\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n\t{ cd: \"code\", name: \"Code Editor\", columnType: \"D\", baseDatatypeCd: \"string\", supportedAgg: \"C\", maxLen: null, precision: null, useStringInFilter: false },\n] as const satisfies readonly FieldTypeDef[];\n\n// Compile-time coverage guard: every `FieldTypeCd` must have a row above, and\n// every row's `cd` must be a `FieldTypeCd`. If the union and the array drift\n// apart, one of these two assignments fails to compile.\ntype _MissingFromArray = Exclude<FieldTypeCd, (typeof fieldTypes)[number][\"cd\"]>;\ntype _MissingFromUnion = Exclude<(typeof fieldTypes)[number][\"cd\"], FieldTypeCd>;\nconst _coverageOk: [_MissingFromArray, _MissingFromUnion] = [undefined as never, undefined as never];\nvoid _coverageOk;\n\nconst byCd = new Map<string, FieldTypeDef>(fieldTypes.map((ft) => [ft.cd, ft]));\n\n/** Set of all known field type codes, for membership checks. */\nexport const fieldTypeCds: ReadonlySet<string> = new Set(fieldTypes.map((ft) => ft.cd));\n\n/** Type guard: is `cd` one of the known field type codes? */\nexport function isFieldTypeCd(cd: string | undefined): cd is FieldTypeCd {\n\treturn cd != null && fieldTypeCds.has(cd);\n}\n\n/** Look up a field type by code, or `undefined` if unknown. */\nexport function getFieldType(cd: string): FieldTypeDef | undefined {\n\treturn byCd.get(cd);\n}\n\n/** Field types whose default column kind is `columnType` (e.g. \"D\" value types). */\nexport function fieldTypesByColumnType(columnType: string): readonly FieldTypeDef[] {\n\treturn fieldTypes.filter((ft) => ft.columnType === columnType);\n}\n","// Base datatype registry — mirror of\n// server/database/system-modules/metadata/seed-data/base_datatypes.json\n//\n// Plus the canonical mapping from an abstract base datatype to the default\n// PostgreSQL column type the platform generates. The visual editor uses this so\n// the author never has to type a raw SQL type.\n\nimport type { BaseDatatypeCd } from \"./types\";\n\nexport const baseDatatypes: readonly BaseDatatypeCd[] = [\n\t\"binary\",\n\t\"bool\",\n\t\"culture\",\n\t\"cuid\",\n\t\"date\",\n\t\"guid\",\n\t\"json\",\n\t\"link\",\n\t\"number\",\n\t\"project\",\n\t\"ref\",\n\t\"set\",\n\t\"string\",\n\t\"time\",\n\t\"timestamp\",\n\t\"xml\",\n] as const;\n\n// Default PostgreSQL type per base datatype. `null` entries are non-physical\n// (relationship/virtual) base types that never produce a column on their own.\nconst BASE_TO_DB: Record<BaseDatatypeCd, string | null> = {\n\tbinary: \"bytea\",\n\tbool: \"bool\",\n\tculture: \"varchar\",\n\tcuid: \"cuid\",\n\tdate: \"date\",\n\tguid: \"uuid\",\n\tjson: \"jsonb\",\n\tlink: null,\n\tnumber: \"numeric\",\n\tproject: \"varchar\",\n\tref: null,\n\tset: null,\n\tstring: \"varchar\",\n\ttime: \"time\",\n\ttimestamp: \"timestamptz\",\n\txml: \"xml\",\n};\n\n/** Default PostgreSQL type for a base datatype, or `null` if non-physical. */\nexport function baseToDbDatatype(base: string): string | null {\n\treturn (BASE_TO_DB as Record<string, string | null>)[base] ?? null;\n}\n","// Column-type registry — the seven column kinds a field can have. Letters match\n// the `column.column_type` values and entity.schema.json. The `name` /\n// `description` here drive the friendly \"what kind of field is this?\" picker.\n\nimport type { ColumnTypeDef } from \"./types\";\n\nexport const columnTypes: readonly ColumnTypeDef[] = [\n\t{ cd: \"D\", name: \"Value\", description: \"A plain data column stored on this entity.\" },\n\t{ cd: \"R\", name: \"Reference\", description: \"An N:1 lookup to another entity (foreign key).\" },\n\t{ cd: \"S\", name: \"Child list\", description: \"A 1:N collection of child records from another entity.\" },\n\t{ cd: \"F\", name: \"Formula\", description: \"A virtual value calculated from a formula expression.\" },\n\t{ cd: \"G\", name: \"Generated\", description: \"A physical column auto-maintained by the database (aggregate or expression).\" },\n\t{ cd: \"A\", name: \"Accumulation register\", description: \"Posts this document into a balance entity (single direction).\" },\n\t{ cd: \"L\", name: \"Ledger register\", description: \"Posts document lines into movements + balances (double entry).\" },\n] as const;\n\nconst byCd = new Map<string, ColumnTypeDef>(columnTypes.map((ct) => [ct.cd, ct]));\n\n/** Look up a column type by letter. */\nexport function getColumnType(cd: string): ColumnTypeDef | undefined {\n\treturn byCd.get(cd);\n}\n","// Trait registry — mirror of\n// server/database/system-modules/metadata/traits.json\n//\n// Traits are authoring shortcuts: adding one to an entity injects a fixed set of\n// fields (and sometimes references) at install time. The visual editor offers\n// these as checkboxes and previews the expanded fields, so authors never\n// hand-write `created_date` / `{entity}_id` etc.\n\nimport type { FieldDef, TraitDef } from \"./types\";\n\nexport const traits: readonly TraitDef[] = [\n\t{\n\t\tcd: \"identity\",\n\t\tdescription: \"Primary Key\",\n\t\tfields: {\n\t\t\t\"{entity}_id\": { dbDatatype: \"cuid\", flags: \"I\", isPk: true, isIdentity: true, isNullable: false, orderNum: 1, description: \"{Entity} ID\" },\n\t\t},\n\t},\n\t{\n\t\tcd: \"audit\",\n\t\tdescription: \"Creation and update timestamps\",\n\t\tfields: {\n\t\t\tcreated_date: { dbDatatype: \"timestamptz\", fieldTypeCd: \"datetime\", flags: \"I\", isNullable: false, orderNum: 9901, description: \"Created Date\", params: { serverDefault: { value: \"now()\", on: \"insert\" } } },\n\t\t\tlast_updated: { dbDatatype: \"timestamptz\", fieldTypeCd: \"datetime\", flags: \"I\", isNullable: false, orderNum: 9902, description: \"Last Updated\", params: { serverDefault: { value: \"now()\", on: \"save\" } } },\n\t\t},\n\t},\n\t{\n\t\tcd: \"audit-full\",\n\t\tdescription: \"Full audit with user tracking\",\n\t\tincludes: [\"audit\"],\n\t\tfields: {\n\t\t\tcreated_by: { dbDatatype: \"cuid\", flags: \"I\", isNullable: false, orderNum: 9903, description: \"Created By User ID\", params: { serverDefault: { value: \"currentUser()\", on: \"insert\" } } },\n\t\t\tcreated_by_user: { columnType: \"R\", fieldTypeCd: \"lookup\", flags: \"I\", orderNum: 9904, description: \"Created By\", link: { entity: \"user\", thisKey: \"created_by\", otherKey: \"user_id\" } },\n\t\t\tlast_updated_by: { dbDatatype: \"cuid\", flags: \"I\", isNullable: false, orderNum: 9905, description: \"Last Updated By User ID\", params: { serverDefault: { value: \"currentUser()\", on: \"save\" } } },\n\t\t\tlast_updated_by_user: { columnType: \"R\", fieldTypeCd: \"lookup\", flags: \"I\", orderNum: 9906, description: \"Last Updated By\", link: { entity: \"user\", thisKey: \"last_updated_by\", otherKey: \"user_id\" } },\n\t\t},\n\t\treferences: {\n\t\t\t\"FK_{Entity}_CreatedBy\": { from: { field: \"created_by\" }, to: { entity: \"user\", field: \"user_id\" } },\n\t\t\t\"FK_{Entity}_LastUpdatedBy\": { from: { field: \"last_updated_by\" }, to: { entity: \"user\", field: \"user_id\" } },\n\t\t},\n\t},\n\t{\n\t\tcd: \"soft-delete\",\n\t\tdescription: \"Soft delete flag\",\n\t\tfields: {\n\t\t\tactive: { dbDatatype: \"bool\", fieldTypeCd: \"checkbox\", flags: \"\", isNullable: false, formula: \"true\", orderNum: 9910, description: \"Active\" },\n\t\t},\n\t},\n\t{\n\t\tcd: \"sorting\",\n\t\tdescription: \"Display order\",\n\t\tfields: {\n\t\t\torder_num: { dbDatatype: \"int4\", fieldTypeCd: \"number\", flags: \"VE\", orderNum: 9920, description: \"Order\" },\n\t\t},\n\t},\n\t{ cd: \"postable\", description: \"Document posting support (marker trait — actual state managed by A/L columns)\", fields: {} },\n\t{ cd: \"accumulation\", description: \"Accumulation register (marker trait — config in A-type column params)\", fields: {} },\n\t{ cd: \"ledger\", description: \"Double-entry ledger (marker trait — config in L-type column params)\", fields: {} },\n\t{\n\t\tcd: \"period\",\n\t\tdescription: \"Period entity with key format, closed flag, date range\",\n\t\tfields: {\n\t\t\tperiod_key: { dbDatatype: \"varchar\", fieldTypeCd: \"text\", flags: \"VE\", isPk: true, isNullable: false, maxLen: 20, orderNum: 1, description: \"Period Key\" },\n\t\t\tdescription: { dbDatatype: \"varchar\", fieldTypeCd: \"text\", flags: \"VE\", maxLen: 100, orderNum: 30, description: \"Description\" },\n\t\t\tclosed: { dbDatatype: \"bool\", fieldTypeCd: \"checkbox\", flags: \"VE\", isNullable: false, formula: \"false\", orderNum: 40, description: \"Closed\" },\n\t\t\tstart_date: { dbDatatype: \"date\", fieldTypeCd: \"date\", flags: \"VE\", orderNum: 50, description: \"Start Date\" },\n\t\t\tend_date: { dbDatatype: \"date\", fieldTypeCd: \"date\", flags: \"VE\", orderNum: 60, description: \"End Date\" },\n\t\t},\n\t},\n] as const;\n\nconst byCd = new Map(traits.map((t) => [t.cd, t]));\n\n/** Look up a trait by code. */\nexport function getTrait(cd: string): TraitDef | undefined {\n\treturn byCd.get(cd);\n}\n\n/** Title-case a snake_case entity code for the `{Entity}` template token. */\nfunction titleCaseEntity(entity: string): string {\n\tconst local = entity.split(\".\").pop() ?? entity;\n\treturn local\n\t\t.split(/[_\\s]+/)\n\t\t.filter(Boolean)\n\t\t.map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n\t\t.join(\" \");\n}\n\nfunction applyTemplate(value: string, entity: string): string {\n\tconst local = entity.split(\".\").pop() ?? entity;\n\treturn value.replace(/\\{entity\\}/g, local).replace(/\\{Entity\\}/g, titleCaseEntity(entity));\n}\n\nfunction templateFields(fields: Record<string, FieldDef>, entity: string): Record<string, FieldDef> {\n\tconst out: Record<string, FieldDef> = {};\n\tfor (const [name, def] of Object.entries(fields)) {\n\t\tconst key = applyTemplate(name, entity);\n\t\tconst next: FieldDef = { ...def };\n\t\tif (typeof next.description === \"string\") next.description = applyTemplate(next.description, entity);\n\t\tout[key] = next;\n\t}\n\treturn out;\n}\n\n/**\n * Expand a trait (and any traits it includes) into the concrete fields it adds\n * for `entityName`, with `{entity}` / `{Entity}` tokens resolved. Returns an\n * empty object for unknown or marker traits. Field order follows include-depth\n * first, then declaration order; later definitions win on key collisions.\n */\nexport function expandTrait(traitCd: string, entityName: string): Record<string, FieldDef> {\n\tconst trait = byCd.get(traitCd);\n\tif (!trait) return {};\n\tconst result: Record<string, FieldDef> = {};\n\tfor (const included of trait.includes ?? []) {\n\t\tObject.assign(result, expandTrait(included, entityName));\n\t}\n\tObject.assign(result, templateFields(trait.fields, entityName));\n\treturn result;\n}\n\n/** Expand several traits in order into one merged field map. */\nexport function expandTraits(traitCds: readonly string[], entityName: string): Record<string, FieldDef> {\n\tconst result: Record<string, FieldDef> = {};\n\tfor (const cd of traitCds) Object.assign(result, expandTrait(cd, entityName));\n\treturn result;\n}\n","// Derivation helpers — turn a friendly field-type choice into the physical\n// metadata the platform needs, so the author never types a raw SQL type.\n//\n// Defaults follow how core modules actually author fields (e.g. currency →\n// numeric(18,2), color → varchar(20)); callers may always override the result.\n\nimport { baseToDbDatatype } from \"./base-datatypes\";\nimport { getFieldType } from \"./field-types\";\n\n/** Total digits used when building a `numeric(total, scale)` type. */\nexport const NUMERIC_TOTAL = 18;\n\n/** Field types whose natural storage is unbounded `text` rather than `varchar`. */\nconst TEXT_BACKED = new Set([\"textarea\", \"markdown\", \"richtext\", \"code\"]);\n\n/**\n * Field types the server pins to a fixed column type regardless of their base\n * datatype — mirrors `DdlService.ResolveDbTypeFromFieldType`. `file`/`image`\n * classify as `binary`, but dForge stores them as a JSON metadata reference\n * (`{ storagePath, fileName, … }`), NOT inline `bytea`; the column is `jsonb`.\n * Without this override the base path derives `bytea`, and the file-attach\n * pipeline — which reads/writes that JSON — fails on save.\n */\nconst DB_DATATYPE_OVERRIDE: Record<string, string> = {\n\tfile: \"jsonb\",\n\timage: \"jsonb\",\n};\n\nexport interface DeriveOptions {\n\t/** Author-specified max length; overrides the field type's default. */\n\tmaxLen?: number | null;\n\t/** Author-specified numeric scale; overrides the field type's default. */\n\tprecision?: number | null;\n}\n\n/**\n * Derive the PostgreSQL `dbDatatype` for a field type. Returns `null` for\n * field types backed by relationships/sets (lookup, grid) that have no physical\n * column of their own. Unknown field types fall back to `varchar`.\n */\nexport function deriveDbDatatype(fieldTypeCd: string, options: DeriveOptions = {}): string | null {\n\tconst ft = getFieldType(fieldTypeCd);\n\tif (!ft) return \"varchar\";\n\n\t// Relationship-backed types (lookup → R, grid → S) never own a physical\n\t// column — the FK lives on a separate hidden column.\n\tif (ft.columnType === \"R\" || ft.columnType === \"S\") return null;\n\n\t// Server-pinned column types that don't follow the base-datatype path\n\t// (file/image → jsonb, not bytea). Mirrors ResolveDbTypeFromFieldType.\n\tconst override = DB_DATATYPE_OVERRIDE[ft.cd];\n\tif (override) return override;\n\n\tconst base = baseToDbDatatype(ft.baseDatatypeCd);\n\tif (base === null) return null; // other non-physical base (link/ref/set)\n\n\tif (ft.baseDatatypeCd === \"number\") {\n\t\tconst precision = options.precision ?? ft.precision;\n\t\treturn precision != null ? `numeric(${NUMERIC_TOTAL},${precision})` : \"numeric\";\n\t}\n\n\tif (ft.baseDatatypeCd === \"string\") {\n\t\tif (TEXT_BACKED.has(ft.cd)) return \"text\";\n\t\tconst maxLen = options.maxLen ?? ft.maxLen;\n\t\treturn maxLen != null ? `varchar(${maxLen})` : \"varchar\";\n\t}\n\n\treturn base;\n}\n\n/** Default `params` to seed a new field of this type with (or `undefined`). */\nexport function defaultParams(fieldTypeCd: string): Record<string, unknown> | undefined {\n\tconst ft = getFieldType(fieldTypeCd);\n\tif (!ft?.defParams) return undefined;\n\treturn { ...ft.defParams };\n}\n\n/** The base datatype code a field type maps to (for `baseDatatypeCd` on F columns). */\nexport function deriveBaseDatatype(fieldTypeCd: string): string | undefined {\n\treturn getFieldType(fieldTypeCd)?.baseDatatypeCd;\n}\n","// Canonical dForge filter expression.\n//\n// One shape shared by data views, reports, folders (row-level security) and the\n// API: either a single condition `{c, o, v}` or a group `{g, i: [...]}`. Mirror\n// of the `filter` $def repeated across data_views / reports / folders schemas.\n\n/**\n * Every operator the server's FilterBuilder translates — the closed set the\n * `o` enum in the data_views / reports / folders schemas mirrors, and the set\n * the installer validates a package's filters against.\n *\n * Symbolic forms and their word aliases are equivalent (`=`/`eq`, `!=`/`notEq`,\n * `>`/`gr`, …); a leading `!` negates, with `n`-prefixed spellings as the alias\n * (`!in`/`nIn`). Note the two spellings authors most often get wrong: null\n * checks are `null` / `!null` (not `isNull` / `isNotNull`) and substring\n * matching is `contains` (not `like`).\n */\nexport const FILTER_OPERATORS = [\n\t\"=\", \"eq\", \"!=\", \"notEq\",\n\t\">\", \"gr\", \">=\", \"grEq\", \"<\", \"less\", \"<=\", \"lessEq\",\n\t\"eqRef\",\n\t\"contains\", \"!contains\", \"nContain\",\n\t\"start\", \"!start\", \"nStart\",\n\t\"end\", \"!end\", \"nEnd\",\n\t\"mask\", \"!mask\", \"nMask\",\n\t\"null\", \"empty\", \"!null\", \"nEmpty\",\n\t\"in\", \"!in\", \"nIn\",\n\t\"between\", \"btw\", \"!between\", \"nBetween\",\n\t\"f\", \"func\",\n] as const;\n\nexport type FilterOperator = (typeof FILTER_OPERATORS)[number];\n\n/** Every group combinator the server recognizes. `!`/`n` forms negate the group. */\nexport const FILTER_GROUP_OPERATORS = [\"and\", \"or\", \"!and\", \"nAnd\", \"!or\", \"nOr\"] as const;\n\nexport type FilterGroupOperator = (typeof FILTER_GROUP_OPERATORS)[number];\n\n/** A single filter condition. */\nexport interface FilterCondition {\n\t/** Column code (supports dot navigation: 'customer.name'). */\n\tc: string;\n\t/** Operator — see {@link FILTER_OPERATORS}. */\n\to: FilterOperator;\n\t/** Comparison value: scalar, array (in/nIn) or a `@param_code` reference. */\n\tv?: unknown;\n}\n\n/** A boolean group of nested conditions/sub-groups. */\nexport interface FilterGroup {\n\t/** Group combinator. */\n\tg: FilterGroupOperator;\n\t/** Group items: nested conditions or sub-groups. */\n\ti: Filter[];\n}\n\n/** A filter is either a single condition or a group. */\nexport type Filter = FilterCondition | FilterGroup;\n\n/** A sort clause `{ c, d }` as used by reports / per-source order. */\nexport interface SortClause {\n\t/** Column code. */\n\tc: string;\n\t/** Sort direction (default: asc). */\n\td?: \"asc\" | \"desc\";\n}\n","// Entity introspection helpers — derive the projections clients commonly need\n// (primary keys, identity-trait keys, reference links) from a raw EntityDef.\n// Shared so the editor, web app and CLI compute these the same way instead of\n// each reimplementing the rules.\n\nimport type { EntityDef } from \"./entity\";\nimport { expandTrait } from \"./traits\";\n\n/** `{ field, target }` for each Reference (R) column that declares a link. */\nexport function getLinks(entity: EntityDef): Array<{ field: string; target: string }> {\n\tconst links: Array<{ field: string; target: string }> = [];\n\tfor (const [code, field] of Object.entries(entity.fields ?? {})) {\n\t\tif (field.columnType === \"R\" && field.link?.entity) {\n\t\t\tlinks.push({ field: code, target: field.link.entity });\n\t\t}\n\t}\n\treturn links;\n}\n\n/**\n * Identity-trait primary-key column codes for `entityCode` (e.g. `invoice_id`),\n * excluding any the author already declared explicitly. Empty unless the entity\n * carries the `identity` trait.\n */\nexport function getIdentityKeys(entity: EntityDef, entityCode: string): string[] {\n\tif (!entity.traits?.includes(\"identity\")) return [];\n\tconst explicit = new Set(Object.keys(entity.fields ?? {}));\n\treturn Object.keys(expandTrait(\"identity\", entityCode)).filter((key) => !explicit.has(key));\n}\n\n/**\n * All primary-key column codes: fields flagged `isPk`, plus identity-trait keys.\n * Order is explicit-first, then identity keys; duplicates removed.\n */\nexport function getPrimaryKeys(entity: EntityDef, entityCode: string): string[] {\n\tconst explicit = Object.entries(entity.fields ?? {})\n\t\t.filter(([, field]) => field.isPk)\n\t\t.map(([code]) => code);\n\tconst seen = new Set(explicit);\n\tconst result = [...explicit];\n\tfor (const key of getIdentityKeys(entity, entityCode)) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n","// Data-view registries + the authoring shape of a `ui/data_views.json` file.\n//\n// `dataViewKinds` is the friendly picker list; `DataViewDef` and friends mirror\n// the structural `data_views.schema.json` so editors/MCP/CLI can build views.\n\nimport type { Filter } from \"./filter\";\nimport type { NamedKind } from \"./types\";\n\nexport type { NamedKind };\n\n/** `viewType` values for `ui/data_views.json`. Source: data_views.schema.json. */\nexport type ViewType =\n\t| \"grid\"\n\t| \"list\"\n\t| \"kanban\"\n\t| \"calendar\"\n\t| \"gallery\"\n\t| \"tree-grid\"\n\t| \"diagram\"\n\t| \"master-detail\"\n\t| \"library\"\n\t| \"matrix\";\n\n/** Friendly picker list of the view kinds. */\nexport const dataViewKinds: readonly NamedKind[] = [\n\t{ cd: \"grid\", name: \"Grid\" },\n\t{ cd: \"list\", name: \"List\" },\n\t{ cd: \"kanban\", name: \"Kanban\" },\n\t{ cd: \"calendar\", name: \"Calendar\" },\n\t{ cd: \"gallery\", name: \"Gallery\" },\n\t{ cd: \"tree-grid\", name: \"Tree Grid\" },\n\t{ cd: \"diagram\", name: \"Diagram\" },\n\t{ cd: \"master-detail\", name: \"Master / Detail\" },\n\t{ cd: \"library\", name: \"Library\" },\n\t{ cd: \"matrix\", name: \"Matrix\" },\n] as const;\n\n/** A column in a data source: shorthand string code or a configured object. */\nexport type ViewColumn =\n\t| string\n\t| {\n\t\t\t/** Column code. */\n\t\t\tcolumn_cd: string;\n\t\t\t/** Column width in pixels. */\n\t\t\twidth?: number;\n\t\t\t/** Whether the column is visible (default true). */\n\t\t\tvisible?: boolean;\n\t\t\t/** Pin column to an edge. */\n\t\t\tpinned?: \"left\" | \"right\";\n\t };\n\n/** One data source within a view. */\nexport interface DataSource {\n\t/** Entity code to query. */\n\tentityCode: string;\n\t/** Nesting level (0 = root, 1+ = detail). */\n\tlevel?: number;\n\t/** Human-readable label (used in master-detail tabs). */\n\tlabel?: string;\n\t/** Column configuration. */\n\tcolumns?: ViewColumn[];\n\t/** Set field on the parent entity linking to this detail level. */\n\tparentSetField?: string;\n\t/** Per-source filter; overrides the view-level filter for this source. */\n\tfilter?: Filter;\n\t/** Per-source sort order (array of `{ c, d }` entries). */\n\torder?: unknown;\n}\n\nexport interface KanbanViewConfig {\n\t/** Dropdown/flags/reference column to group cards by. */\n\tgroupByField: string;\n}\n\nexport interface CalendarViewConfig {\n\t/** Date/timestamp column used to place events. */\n\tdateField: string;\n\t/** Column shown as event title (defaults to the entity toString). */\n\ttitleField?: string;\n\t/** Column whose value drives the event pill color. */\n\tcolorField?: string;\n}\n\nexport interface TreeGridViewConfig {\n\t/** Self-referencing FK column (parent record). */\n\tparentField: string;\n\t/** Node label field (defaults to entity toString). */\n\tlabelField?: string;\n\t/** Field containing a Bootstrap icon class per node. */\n\ticonField?: string;\n}\n\nexport interface ListLevelConfig {\n\t/** Entity code for this child level. */\n\tentityCode: string;\n\t/** FK column in the child entity linking back to the parent. */\n\tforeignKey: string;\n\t/** Columns to display inline for each child row. */\n\tcolumns?: string[];\n}\n\nexport interface ListViewConfig {\n\ttitleField?: string;\n\tsubtitleField?: string;\n\t/** Hierarchical child levels for expandable list rows. */\n\tlevels?: ListLevelConfig[];\n}\n\nexport interface DiagramViewConfig {\n\t/** Column to group diagram nodes by. */\n\tgroupByField?: string;\n\t/** Group values hidden by default. */\n\tdefaultHiddenGroups?: string[];\n}\n\n/** A single data view (value in the `ui/data_views.json` map). */\nexport interface DataViewDef {\n\tviewType: ViewType;\n\t/** Human-readable view name. */\n\tlabel?: string;\n\t/** Bootstrap icon class (e.g. 'bi-bounding-box'). */\n\ticon?: string;\n\tdescription?: string;\n\t/** Data sources (at least one; master-detail needs two). */\n\tdataSources: DataSource[];\n\t/** Default filter applied to all sources unless one declares its own. */\n\tfilter?: Filter;\n\t/** Default sort order. */\n\torder?: unknown;\n\t/** View-type-specific configuration. */\n\tviewConfig?:\n\t\t| KanbanViewConfig\n\t\t| CalendarViewConfig\n\t\t| TreeGridViewConfig\n\t\t| ListViewConfig\n\t\t| DiagramViewConfig\n\t\t| Record<string, unknown>;\n}\n\n/** A `ui/data_views.json` file: data view code → definition. */\nexport type DataViewsFile = Record<string, DataViewDef>;\n","// Report registries + the authoring shape of a `ui/reports.json` file.\n//\n// `vizTypes` / `chartTypes` are the friendly picker lists; `ReportDef` and\n// friends mirror reports.schema.json so editors/MCP/CLI can build reports.\n\nimport type { Filter, SortClause } from \"./filter\";\nimport type { NamedKind } from \"./types\";\n\n/** Report visualization types. Source: reports.schema.json (`vizType`). */\nexport type VizType = \"table\" | \"chart\" | \"metric\" | \"pivot\";\n\n/** Friendly picker list of report visualization types. */\nexport const vizTypes: readonly NamedKind[] = [\n\t{ cd: \"table\", name: \"Table\" },\n\t{ cd: \"chart\", name: \"Chart\" },\n\t{ cd: \"metric\", name: \"Metric\" },\n\t{ cd: \"pivot\", name: \"Pivot\" },\n] as const;\n\n/** Chart kinds used by report `config.chartType` (curated; rendered via Chart.js). */\nexport const chartTypes: readonly NamedKind[] = [\n\t{ cd: \"bar\", name: \"Bar\" },\n\t{ cd: \"line\", name: \"Line\" },\n\t{ cd: \"area\", name: \"Area\" },\n\t{ cd: \"pie\", name: \"Pie\" },\n\t{ cd: \"donut\", name: \"Donut\" },\n\t{ cd: \"scatter\", name: \"Scatter\" },\n\t{ cd: \"bubble\", name: \"Bubble\" },\n\t{ cd: \"heatmap\", name: \"Heatmap\" },\n\t{ cd: \"funnel\", name: \"Funnel\" },\n] as const;\n\n/** Everything a report parameter carries regardless of where its control comes from. */\nexport interface ParamDefBase {\n\tlabel?: string;\n\t/** Display order in the parameter form (falls back to declaration order). */\n\torderNum?: number;\n\t/**\n\t * Whether the user must provide a value. Stored inverted as `param.is_nullable`.\n\t * There is no `isRequired` spelling — the installer reads this key only.\n\t */\n\trequired?: boolean;\n\t/** Default value applied when the user doesn't provide one. */\n\tdefault?: unknown;\n\t/**\n\t * Field-type-specific params, nested under this key — there is no top-level\n\t * `link`. A lookup param needs `{ link: { entity, otherKey? } }`.\n\t * Most importantly `options` for a dropdown.\n\t * Options accept the same rich `{value,label,icon,color}` form entity columns\n\t * use; a bare string list renders the raw codes in every locale, so label them.\n\t * Omitted on a domain-backed param: the domain owns the list.\n\t */\n\tparams?: Record<string, unknown>;\n\t/**\n\t * Declares a REFERENCE parameter: the submitted value is the whole picked\n\t * record rather than its bare key. The JSON counterpart of the action DSL's\n\t * `paramCd: ref <entityCd>`, stored in the same `param.column_type`.\n\t *\n\t * Optional, and the choice is not cosmetic. Omitting it (a plain `lookup`)\n\t * submits the key, which is what a filter comparing against a reference\n\t * column needs — the server destructures a key object across every key\n\t * column and ignores non-key fields. Declare `\"R\"` when the report wants the\n\t * record itself, not just its identity.\n\t *\n\t * Either way the picker is configured by `params.link` (`{ entity, otherKey? }`);\n\t * `otherKey` is filled from the target's primary key when omitted, comma-joined\n\t * and paired POSITIONALLY with the key columns.\n\t */\n\tcolumnType?: \"R\";\n}\n\n/**\n * A report parameter definition. Declared in the report-level `parameters` block,\n * or as shorthand under the `params` of the dataset that consumes it — the\n * installer merges both into the report's single param set, so either way the\n * parameter serves the whole report. Report level wins on a code collision, and\n * is the only sensible home for a parameter several datasets use.\n *\n * A parameter takes its control from an explicit `fieldTypeCd` **or** from a\n * column `domain` — never both. Declaring both is the one rejected combination\n * (`not: { required: [\"fieldTypeCd\", \"domain\"] }` in `reports.schema.json`, and an\n * install-time check that refuses to silently pick a winner). Declaring **neither**\n * is fine: the param installs as `text`.\n *\n * Prefer `domain` whenever the choices are the same list a column uses (the usual\n * case, since the value normally ends up written to that column): the options and\n * their translations then live on the domain and are authored once, instead of\n * being restated per parameter and left to drift.\n */\nexport type ParamDef =\n\t| (ParamDefBase & {\n\t\t/** Field type code (see settings for the common list). Defaults to `text`. */\n\t\tfieldTypeCd?: string;\n\t\tdomain?: never;\n\t})\n\t| (ParamDefBase & {\n\t\t/**\n\t\t * Column domain (`domain_cd` or `module_cd.domain_cd`) supplying the control\n\t\t * and the option list. The DSL equivalent for action params is\n\t\t * `paramCd: domain <domainCd>`.\n\t\t */\n\t\tdomain: string;\n\t\tfieldTypeCd?: never;\n\t});\n\n/** SQL/entity query for a `datasetType: 'Q'` dataset. */\nexport interface ReportQuery {\n\t/** Source entity code. */\n\tentityCd: string;\n\t/** Column codes to select (supports dot navigation: 'customer.name'). */\n\tcolumns?: string[];\n\tfilter?: Filter;\n\tsort?: SortClause[];\n}\n\n/** Per-column metadata override on a dataset. */\nexport interface ColumnDef {\n\tlabel?: string;\n\tvisible?: boolean;\n\twidth?: number;\n}\n\n/** A report dataset (value in the report's `datasets` map). */\nexport interface Dataset {\n\t/** Display label (used in panel headings if no `title`). */\n\tcaption?: string;\n\t/** Q = SQL/entity query, S = stored procedure. */\n\tdatasetType: \"Q\" | \"S\";\n\t/** Used when `datasetType` is 'Q'. */\n\tquery?: ReportQuery;\n\t/** Used when `datasetType` is 'S'. */\n\tprocedureName?: string;\n\t/** Optional column metadata overrides: field code → override. */\n\tcolumnsDef?: Record<string, ColumnDef>;\n\t/**\n\t * Parameters declared on this dataset — shorthand for the report-level\n\t * `parameters` block, convenient when exactly one dataset uses the parameter.\n\t * The installer merges both into the report's one param set either way.\n\t */\n\tparams?: Record<string, ParamDef>;\n}\n\n/**\n * One (entity, report) **record-report attachment**: the report becomes openable\n * from that entity's record, with the record's values feeding its parameters.\n * Each entry becomes one `dForge.entity_report` row.\n *\n * The binding is per-attachment, not per-report — the same report can attach to\n * several entities with different parameter mappings, which is why the mapping\n * lives here rather than on the report.\n */\nexport interface ReportEntityAttachment {\n\t/**\n\t * Entity the report attaches to, qualified `module.entity` for anything\n\t * outside the declaring module. That module must be a declared dependency.\n\t */\n\tentityCd: string;\n\t/**\n\t * Parameter mapping: report param code → **source column on the entity**.\n\t * (Not a param declaration — those live in the report's `parameters` block or a\n\t * dataset's `params`.) Resolved server-side\n\t * from the record's PK. Source columns are limited to the PK, reference (`R`)\n\t * columns, and bounded scalars; source and target must be type-compatible.\n\t * Params left unmapped keep their normal behaviour (default, or prompt).\n\t */\n\tparams?: Record<string, string>;\n\t/** Sort position in the record's combined action + report menu. */\n\torderNum?: number;\n}\n\n/** A single visualization panel within the report layout. */\nexport interface ReportPanel {\n\tvizType: VizType;\n\t/** Dataset code (key in the report's `datasets` map). */\n\tdatasetCd: string;\n\ttitle?: string;\n\t/** Viz-type-specific config (chart → { chartType, categoryCol, … }). */\n\tconfig?: Record<string, unknown>;\n}\n\nexport interface ReportLayout {\n\tpanels: ReportPanel[];\n}\n\n/** A single report (value in the `ui/reports.json` map). */\nexport interface ReportDef {\n\t/** Human-readable report title. */\n\tdescription: string;\n\tlayout: ReportLayout;\n\t/** Dataset code → dataset definition. */\n\tdatasets: Record<string, Dataset>;\n\t/** Auto-refresh interval in seconds. Omit (or 0) for no auto-refresh. */\n\treloadInterval?: number;\n\t/**\n\t * Report-level parameter declarations — the canonical home for a parameter, and\n\t * the only one that fits a parameter several datasets use. Merged with each\n\t * dataset's `params` into the report's single param set; this block wins on a\n\t * code collision.\n\t */\n\tparameters?: Record<string, ParamDef>;\n\t/**\n\t * Record-report attachments: entities this report can be opened from, with the\n\t * mapping from report parameter to source column on each. Omit for a report\n\t * that is only reached from a menu.\n\t */\n\tentities?: ReportEntityAttachment[];\n}\n\n/** A `ui/reports.json` file: report code → definition. */\nexport type ReportsFile = Record<string, ReportDef>;\n","// Dependency contracts — authoring shape of `deps/<provider>.json`. Mirror of deps.schema.json.\n//\n// One file per dependency declares everything a consumer module consumes from a\n// provider: the entities, columns (each pinned to its provider storage class — a\n// Postgres type token like int8/varchar/numeric, not a base datatype), and the\n// provenance of each usage. The provider stays the source of truth; this is the\n// consumer's import list. See docs/modules/dependency-contracts.md.\n\n/**\n * Allowed storage-class tokens for a consumed column — Postgres type names with\n * length/scale stripped. Closed allowlist, kept in lockstep with the `type` enum in\n * `deps.schema.json` (and `DependencyContractValidator.ValidColumnTypes` on the C#\n * side); the `schemas.test.ts` parity guard fails if this drifts from the schema.\n * Extend all three together if a provider column legitimately uses a type not here.\n */\nexport const DEP_COLUMN_TYPES = [\n\t\"int2\", \"int4\", \"int8\", \"smallint\", \"integer\", \"bigint\",\n\t\"numeric\", \"decimal\", \"float4\", \"float8\", \"real\", \"money\",\n\t\"varchar\", \"text\", \"char\", \"bpchar\",\n\t\"bool\", \"boolean\",\n\t\"date\", \"time\", \"timetz\", \"timestamp\", \"timestamptz\",\n\t\"uuid\", \"json\", \"jsonb\", \"bytea\",\n] as const;\n\n/**\n * Storage class pinned for a consumed column — the provider's physical Postgres type\n * with length/scale stripped (e.g. `int8`, `numeric`, `varchar`). dForge's `cuid`\n * Snowflake PK normalizes to `int8`. Pinning the storage class (not a coarse base\n * type) keeps FK/lookup compatibility meaningful — an `int8` key needs `int8`, not\n * any number. One of {@link DEP_COLUMN_TYPES}.\n */\nexport type DepColumnType = (typeof DEP_COLUMN_TYPES)[number];\n\n/** Whether the consumer reads or writes a column. Default `read`. */\nexport type DepColumnMode = \"read\" | \"write\";\n\n/** Kinds of cross-module usage a provenance token can name. */\nexport type DepProvenanceKind =\n\t| \"ref\"\n\t| \"extends\"\n\t| \"formula\"\n\t| \"action\"\n\t| \"view\"\n\t| \"report\"\n\t| \"print\"\n\t| \"role\";\n\n/**\n * A usage token of the form `<kind>:<symbol>` — e.g. `ref:invoice.customer`,\n * `extends:party`, `action:check_credit`, `role:fin.admin`. Names the consuming\n * symbol so the completeness lint can reconcile declared vs actual usage. Note:\n * `display` is intentionally not a kind — the label is the provider's concern.\n */\nexport type DepProvenance = `${DepProvenanceKind}:${string}`;\n\n/** A single consumed provider column. */\nexport interface DepColumn {\n\t/** Storage class — the provider column's physical Postgres type, params stripped (`int8`, `varchar`, `numeric`, …). */\n\ttype: DepColumnType;\n\t/** Per-column provenance: which symbols read/write/join on this column. */\n\tuse: DepProvenance[];\n\t/** `write` implies an insert/update right + settable column. Default `read`; omit for reads. */\n\tmode?: DepColumnMode;\n}\n\n/** What the consumer needs from one provider entity. */\nexport interface DepEntity {\n\t/** The provider entity's PK column — the anchor every reference joins on. No label/display. */\n\tpk: string;\n\t/** Entity-level provenance: why this entity is consumed (ref/extends/role/view/report/print/action). */\n\tuse: DepProvenance[];\n\t/** Provider columns actually read/written/joined. Omit for extension-only targets. */\n\tcolumns?: Record<string, DepColumn>;\n}\n\n/** A `deps/<provider>.json` file: the consumer's contract against one dependency. */\nexport interface DepsFile {\n\t/** Code of the dependency (provider) module this contract is against (e.g. `parties`). */\n\tmodule: string;\n\t/** Semver range the consumer requires of the provider (e.g. `>=0.1.0`). */\n\tversion: string;\n\t/** Consumed provider entities, keyed by entity code. */\n\tentities: Record<string, DepEntity>;\n}\n","// @dforge-core/metadata — canonical dForge authoring registries + module-file types.\n//\n// Single source of truth for:\n// • registries — field types, base datatypes, column types, traits, data-view\n// kinds, report viz/chart types, plus helpers that derive physical metadata\n// from a friendly field-type choice;\n// • structural types — the authoring shape of every module-package file\n// (manifest, entities, data views, reports, menus, folders, roles, settings,\n// jobs, triggers, webhooks, print templates, seed data, actions), mirrored\n// from the JSON schemas under docs/schemas/.\n//\n// No runtime dependencies; safe to import from editors, the web app, the CLI,\n// the MCP server and the VS Code extension.\n\n// ── Shared core types & registries ──────────────────────────────────────────\nexport type {\n\tAlignType,\n\tBaseDatatypeCd,\n\tColumnTypeCd,\n\tColumnTypeDef,\n\tFieldDef,\n\tFieldLink,\n\tFieldOption,\n\tFieldTypeCd,\n\tFieldTypeDef,\n\tFlagCd,\n\tNamedKind,\n\tTraitDef,\n} from \"./types\";\n\nexport { AggType, AGG_TYPE_LIST } from \"./aggregation\";\n\nexport { fieldTypes, fieldTypeCds, isFieldTypeCd, getFieldType, fieldTypesByColumnType } from \"./field-types\";\nexport { baseDatatypes, baseToDbDatatype } from \"./base-datatypes\";\nexport { columnTypes, getColumnType } from \"./column-types\";\nexport { traits, getTrait, expandTrait, expandTraits } from \"./traits\";\nexport {\n\tderiveDbDatatype,\n\tderiveBaseDatatype,\n\tdefaultParams,\n\tNUMERIC_TOTAL,\n\ttype DeriveOptions,\n} from \"./derive\";\n\n// ── Shared filter expression (data views / reports / folders / API) ──────────\nexport type {\n\tFilter,\n\tFilterCondition,\n\tFilterGroup,\n\tFilterGroupOperator,\n\tFilterOperator,\n\tSortClause,\n} from \"./filter\";\nexport { FILTER_GROUP_OPERATORS, FILTER_OPERATORS } from \"./filter\";\n\n// ── Module-file structural types ─────────────────────────────────────────────\nexport type {\n\tEntityDef,\n\tEntityReference,\n\tNumberSequenceDef,\n\tPeriodConfig,\n\tAccumulationConfig,\n\tSignConfig,\n\tLedgerRegistryEntry,\n\tTraitCd,\n} from \"./entity\";\n\n// Entity introspection helpers (primary keys, identity keys, reference links).\nexport { getLinks, getIdentityKeys, getPrimaryKeys } from \"./entity-meta\";\n\nexport {\n\tdataViewKinds,\n\ttype DataViewsFile,\n\ttype DataViewDef,\n\ttype DataSource,\n\ttype ViewColumn,\n\ttype ViewType,\n\ttype KanbanViewConfig,\n\ttype CalendarViewConfig,\n\ttype TreeGridViewConfig,\n\ttype ListViewConfig,\n\ttype ListLevelConfig,\n\ttype DiagramViewConfig,\n} from \"./data-views\";\n\nexport {\n\tvizTypes,\n\tchartTypes,\n\ttype ReportsFile,\n\ttype ReportDef,\n\ttype ReportEntityAttachment,\n\ttype ReportLayout,\n\ttype ReportPanel,\n\ttype Dataset,\n\ttype ReportQuery,\n\ttype ColumnDef,\n\ttype ParamDef,\n\ttype ParamDefBase,\n\ttype VizType,\n} from \"./reports\";\n\nexport type { ManifestDef, ManifestAuthor, ModuleDependency, ModuleFeature } from \"./manifest\";\nexport type { DepsFile, DepEntity, DepColumn, DepColumnType, DepColumnMode, DepProvenance, DepProvenanceKind } from \"./deps\";\nexport { DEP_COLUMN_TYPES } from \"./deps\";\nexport type { DomainsFile, DomainDef } from \"./domains\";\nexport type { MenusFile, MenuDef, MenuItemDef, MenuItemType } from \"./menus\";\nexport type { FoldersFile, FolderDef, FolderEntityBinding } from \"./folders\";\nexport type { RolesFile, RoleDef } from \"./roles\";\nexport type { SettingsFile, SettingDef, SettingBaseDatatype } from \"./settings\";\nexport type { JobsFile, JobDef } from \"./jobs\";\nexport type { TriggersFile, TriggerDef, EntityEvent } from \"./triggers\";\nexport type { WebhooksFile, WebhookSubscription, WebhookPayload } from \"./webhooks\";\nexport type { PrintTemplatesFile, PrintTemplateDef, PrintPageSettings, PrintMargins } from \"./print-templates\";\nexport type { SeedDataFile } from \"./seed-data\";\nexport type { ActionsFile, ActionDef, ActionExecutionMode } from \"./actions\";\n\n// Display flag catalog — the only flags valid on an authored field\n// (entity.schema.json `flags` pattern is ^[VIEMH]*$).\nexport const flagDefs: readonly { value: \"V\" | \"I\" | \"E\" | \"M\" | \"H\"; label: string }[] = [\n\t{ value: \"V\", label: \"Visible\" },\n\t{ value: \"I\", label: \"Identity\" },\n\t{ value: \"E\", label: \"Editable\" },\n\t{ value: \"M\", label: \"Mandatory\" },\n\t{ value: \"H\", label: \"Hidden\" },\n] as const;\n"],"mappings":"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","names":["byCd","byCd"]}
|
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
2
|
+
"name": "@dforge-core/metadata",
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"description": "Canonical dForge authoring registries — field types, base datatypes, column types, traits, data-view kinds and chart types — with derivation helpers. Runtime-dependency-free; the single source of truth shared by editors, the web app and the CLI.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "dForge",
|
|
7
|
+
"homepage": "https://github.com/iash44/dForge-core/tree/main/clients/packages/metadata#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/iash44/dForge-core.git",
|
|
11
|
+
"directory": "clients/packages/metadata"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/iash44/dForge-core/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"dforge",
|
|
18
|
+
"metadata",
|
|
19
|
+
"field-type",
|
|
20
|
+
"trait",
|
|
21
|
+
"registry",
|
|
22
|
+
"low-code"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"module": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"source": "./src/index.ts",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./schemas/*": "./schemas/*",
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"src",
|
|
43
|
+
"schemas",
|
|
44
|
+
"CHANGELOG.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"sync-schemas": "node scripts/sync-schemas.mjs",
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"dev": "tsup --watch",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"prepack": "pnpm sync-schemas && pnpm typecheck && pnpm build",
|
|
53
|
+
"package": "pnpm pack"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^25.9.4",
|
|
57
|
+
"ajv": "^8.20.0",
|
|
58
|
+
"tsup": "^8.5.1",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vitest": "^4.1.10"
|
|
61
|
+
}
|
|
62
62
|
}
|
|
@@ -247,11 +247,51 @@
|
|
|
247
247
|
"additionalProperties": false
|
|
248
248
|
},
|
|
249
249
|
|
|
250
|
+
"calculatedMember": {
|
|
251
|
+
"type": "object",
|
|
252
|
+
"description": "A synthetic, read-only member of a pivot-like view — a row (default) or column derived by a formula over other members at each cross-axis position. Platform-generic: any pivot-like surface consumes the same shape, so a module declares the metric in config with no platform code change. Pure presentation — no storage, evaluated client-side by the stock formula engine.",
|
|
253
|
+
"required": ["key", "label", "refs", "formula"],
|
|
254
|
+
"properties": {
|
|
255
|
+
"key": { "type": "string", "description": "Stable render key. Must not collide with a real member key." },
|
|
256
|
+
"axis": { "type": "string", "enum": ["row", "column"], "default": "row", "description": "Which axis the member is added to. A calculated ROW is a formula over other rows evaluated once per column; a calculated COLUMN is the transpose." },
|
|
257
|
+
"label": { "type": "string", "description": "Member label shown in the row/column head." },
|
|
258
|
+
"field": { "type": "string", "description": "Value field the refs read. Defaults to the surface's first value field." },
|
|
259
|
+
"refs": {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"description": "Formula bracket-alias → referenced member identity on the same axis.",
|
|
262
|
+
"additionalProperties": { "type": "string" }
|
|
263
|
+
},
|
|
264
|
+
"formula": { "type": "string", "description": "Formula over the aliases, e.g. `[gp] / [rev] * 100`. Same `[name]` syntax as column formulas. A non-finite result (÷0, missing denominator) renders empty." },
|
|
265
|
+
"position": {
|
|
266
|
+
"description": "Placement on the axis. Defaults to the end.",
|
|
267
|
+
"oneOf": [
|
|
268
|
+
{ "type": "object", "required": ["after"], "properties": { "after": { "type": "string", "description": "Key of the member to place this one after." } }, "additionalProperties": false },
|
|
269
|
+
{ "type": "object", "required": ["at"], "properties": { "at": { "type": "string", "enum": ["end"] } }, "additionalProperties": false }
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
"depth": { "type": "integer", "minimum": 0, "description": "Indent depth (row members only; 0 = top level)." },
|
|
273
|
+
"format": {
|
|
274
|
+
"type": "object",
|
|
275
|
+
"description": "Display format for the result.",
|
|
276
|
+
"properties": {
|
|
277
|
+
"style": { "type": "string", "enum": ["number", "percent"], "default": "number" },
|
|
278
|
+
"decimals": { "type": "integer", "minimum": 0, "default": 1 }
|
|
279
|
+
},
|
|
280
|
+
"additionalProperties": false
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"additionalProperties": false
|
|
284
|
+
},
|
|
250
285
|
"matrixViewConfig": {
|
|
251
286
|
"type": "object",
|
|
252
287
|
"description": "Matrix (pivot) view: rowAxis × colAxis grid with a value-source cell entity holding one record per (rowKey, colKey).",
|
|
253
288
|
"required": ["rowAxis", "colAxis", "cell"],
|
|
254
289
|
"properties": {
|
|
290
|
+
"calculatedMembers": {
|
|
291
|
+
"type": "array",
|
|
292
|
+
"description": "Synthetic read-only members derived by formula over OTHER members' values (e.g. a Gross Margin % row). Spliced into the rendered axis; never loaded or saved.",
|
|
293
|
+
"items": { "$ref": "#/$defs/calculatedMember" }
|
|
294
|
+
},
|
|
255
295
|
"rowAxis": {
|
|
256
296
|
"description": "Row axis values: an entity's records ('dataset') or a column's dropdown options ('dropdown').",
|
|
257
297
|
"oneOf": [
|
|
@@ -133,6 +133,12 @@
|
|
|
133
133
|
"items": { "type": "string", "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" },
|
|
134
134
|
"description": "Non-English locales the package promises to translate. Each entry MUST match a translations/<locale>.json file, and every translatable resource (entity/field labels, folders, views, menus + items, actions + params, reports + datasets + params, settings) MUST have a label in that file. English is the default — don't list 'en' or 'en-US'."
|
|
135
135
|
},
|
|
136
|
+
"features": {
|
|
137
|
+
"type": "array",
|
|
138
|
+
"items": { "type": "string", "enum": ["report-security"] },
|
|
139
|
+
"uniqueItems": true,
|
|
140
|
+
"description": "Opt-in platform behaviours this package was authored for. Absent or empty = the pre-feature behaviour for all of them, so a module written before a feature existed keeps working until its author declares it and republishes. Unknown names are REJECTED at package load, never ignored — a misspelled feature would silently leave the old behaviour in place while the manifest claims otherwise. Values: 'report-security' = this module's reports require 'E' on their sec_object; declare the matching \"report:<code>\": \"E\" grants in security/roles.json first, or the reports go dark for every role."
|
|
141
|
+
},
|
|
136
142
|
"created": {
|
|
137
143
|
"type": "string",
|
|
138
144
|
"format": "date",
|
|
@@ -24,10 +24,42 @@
|
|
|
24
24
|
"description": "Map of dataset code → dataset definition. Panels reference datasets by code via `datasetCd`.",
|
|
25
25
|
"additionalProperties": { "$ref": "#/$defs/dataset" }
|
|
26
26
|
},
|
|
27
|
+
"reloadInterval": {
|
|
28
|
+
"type": "integer",
|
|
29
|
+
"minimum": 0,
|
|
30
|
+
"description": "Auto-refresh interval in seconds. Omit (or 0) for no auto-refresh."
|
|
31
|
+
},
|
|
27
32
|
"parameters": {
|
|
28
33
|
"type": "object",
|
|
29
|
-
"description": "Report-level
|
|
34
|
+
"description": "Report-level parameter declarations — the canonical home for a parameter, and the only one that fits a parameter several datasets use. Parameters are report-scoped throughout the platform: one `param_set` per report, `report.params.save` in the authoring API, and `report.get` flattens per-dataset defaults report-wide before use. A parameter declared under a dataset's `params` is shorthand for declaring it here; the installer merges both into one set, with this block winning on a code collision.",
|
|
30
35
|
"additionalProperties": { "$ref": "#/$defs/paramDef" }
|
|
36
|
+
},
|
|
37
|
+
"entities": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"description": "Record-report attachments: entities this report can be opened from, with the mapping from report parameter to source column on that entity. Each entry becomes one `dForge.entity_report` row. See docs/business-logic/record-reports.md.",
|
|
40
|
+
"items": { "$ref": "#/$defs/entityAttachment" }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"additionalProperties": false
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"entityAttachment": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"description": "One (entity, report) attachment. The binding is per-attachment, not per-report — the same report can attach to several entities with different parameter mappings.",
|
|
49
|
+
"required": ["entityCd"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"entityCd": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": "Entity the report attaches to, qualified `module.entity` for anything outside the declaring module. The owning module must be this module or a declared dependency."
|
|
54
|
+
},
|
|
55
|
+
"params": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"description": "Parameter mapping: report param code → source column on the entity. Stored as `entity_report.param_map` and resolved server-side from the record's PK. Source columns are limited to the PK, reference (`R`) columns, and bounded scalars (number, date/datetime, bool, dropdown/radio/flags code); source and target must be type-compatible. Params left unmapped keep their normal behaviour (default value, or prompt the user).",
|
|
58
|
+
"additionalProperties": { "type": "string" }
|
|
59
|
+
},
|
|
60
|
+
"orderNum": {
|
|
61
|
+
"type": "integer",
|
|
62
|
+
"description": "Sort position in the record's combined action + report menu."
|
|
31
63
|
}
|
|
32
64
|
},
|
|
33
65
|
"additionalProperties": false
|
|
@@ -228,7 +260,7 @@
|
|
|
228
260
|
},
|
|
229
261
|
"params": {
|
|
230
262
|
"type": "object",
|
|
231
|
-
"description": "
|
|
263
|
+
"description": "Parameters declared on this dataset — shorthand for the report-level `parameters` block, convenient when exactly one dataset uses the parameter. Either way the parameter is REPORT-scoped: `ReportRegistrar` merges the report-level block and every dataset's `params` into the report's one `param_set`, so a parameter declared here serves the whole report (the param bar, saved param sets, `@param` filters in any dataset, and record-report `entities[].params` mappings). On a code collision the report-level block wins. Declare a parameter used by several datasets at report level — there is no meaningful dataset to attribute it to.",
|
|
232
264
|
"additionalProperties": { "$ref": "#/$defs/paramDef" }
|
|
233
265
|
}
|
|
234
266
|
},
|
|
@@ -314,41 +346,38 @@
|
|
|
314
346
|
|
|
315
347
|
"paramDef": {
|
|
316
348
|
"type": "object",
|
|
317
|
-
"required": ["fieldTypeCd"],
|
|
349
|
+
"not": { "required": ["fieldTypeCd", "domain"] },
|
|
318
350
|
"properties": {
|
|
319
351
|
"fieldTypeCd": {
|
|
320
352
|
"type": "string",
|
|
321
|
-
"description": "Field type code (see settings.schema.json for the common list)"
|
|
353
|
+
"description": "Field type code (see settings.schema.json for the common list). Omit when `domain` is set — the domain supplies the control. May also be omitted entirely: a param declaring neither key installs as `text` (ReportRegistrar.DefaultParamFieldTypeCd). The one rejected combination is declaring both."
|
|
354
|
+
},
|
|
355
|
+
"domain": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
"description": "Column domain (`domain_cd` or `module_cd.domain_cd`) the parameter borrows its control and option list from. The options and their translations stay on the domain, so a list shared with an entity column is authored once. The DSL equivalent for action params is `paramCd: domain <domainCd>`.",
|
|
358
|
+
"pattern": "^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)?$"
|
|
322
359
|
},
|
|
323
360
|
"label": { "type": "string" },
|
|
324
361
|
"orderNum": {
|
|
325
362
|
"type": "integer",
|
|
326
363
|
"description": "Display order of the parameter in the report's parameter form. Read by ReportRegistrar (paramDef.OrderNum); falls back to declaration order when omitted."
|
|
327
364
|
},
|
|
365
|
+
"columnType": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"enum": ["R"],
|
|
368
|
+
"description": "Declares a REFERENCE parameter: its submitted value is the whole picked record rather than the bare key. The JSON counterpart of the action DSL's `paramCd: ref <entityCd>`, stored in the same `param.column_type`. Optional — omitting it (a plain `lookup`) submits the key, which is what a filter comparing against a reference column needs, since the server destructures a key object across every key column and ignores non-key fields. Declare \"R\" when the report wants the record itself, not just its identity."
|
|
369
|
+
},
|
|
328
370
|
"required": {
|
|
329
371
|
"type": "boolean",
|
|
330
372
|
"default": false,
|
|
331
|
-
"description": "Whether the user must provide a value
|
|
332
|
-
},
|
|
333
|
-
"isRequired": {
|
|
334
|
-
"type": "boolean",
|
|
335
|
-
"description": "Alternate spelling of `required` used by some modules. Prefer `required` for new code."
|
|
373
|
+
"description": "Whether the user must provide a value. Stored inverted as `param.is_nullable`. There is no `isRequired` spelling — `ReportParamDef` reads this key only."
|
|
336
374
|
},
|
|
337
375
|
"default": {
|
|
338
376
|
"description": "Default value applied if the user doesn't provide one"
|
|
339
377
|
},
|
|
340
|
-
"link": {
|
|
341
|
-
"type": "object",
|
|
342
|
-
"description": "Entity link for lookup-type params (alternative to nesting under `params.link`). Shape: { entity: '<code>', otherKey?: '<column>' }.",
|
|
343
|
-
"properties": {
|
|
344
|
-
"entity": { "type": "string" },
|
|
345
|
-
"otherKey": { "type": "string" }
|
|
346
|
-
},
|
|
347
|
-
"additionalProperties": false
|
|
348
|
-
},
|
|
349
378
|
"params": {
|
|
350
379
|
"type": "object",
|
|
351
|
-
"description": "Field-type-specific params
|
|
380
|
+
"description": "Field-type-specific params, nested under this key — there is no top-level `link`. A `lookup` param needs `{ \"link\": { \"entity\": \"<code>\", \"otherKey\": \"<column>\" } }`; `otherKey` auto-fills from the target's PK when omitted. Without `params.link` a lookup param installs, warns, and has no autocomplete."
|
|
352
381
|
}
|
|
353
382
|
},
|
|
354
383
|
"additionalProperties": false
|
package/src/index.ts
CHANGED
|
@@ -88,16 +88,18 @@ export {
|
|
|
88
88
|
chartTypes,
|
|
89
89
|
type ReportsFile,
|
|
90
90
|
type ReportDef,
|
|
91
|
+
type ReportEntityAttachment,
|
|
91
92
|
type ReportLayout,
|
|
92
93
|
type ReportPanel,
|
|
93
94
|
type Dataset,
|
|
94
95
|
type ReportQuery,
|
|
95
96
|
type ColumnDef,
|
|
96
97
|
type ParamDef,
|
|
98
|
+
type ParamDefBase,
|
|
97
99
|
type VizType,
|
|
98
100
|
} from "./reports";
|
|
99
101
|
|
|
100
|
-
export type { ManifestDef, ManifestAuthor, ModuleDependency } from "./manifest";
|
|
102
|
+
export type { ManifestDef, ManifestAuthor, ModuleDependency, ModuleFeature } from "./manifest";
|
|
101
103
|
export type { DepsFile, DepEntity, DepColumn, DepColumnType, DepColumnMode, DepProvenance, DepProvenanceKind } from "./deps";
|
|
102
104
|
export { DEP_COLUMN_TYPES } from "./deps";
|
|
103
105
|
export type { DomainsFile, DomainDef } from "./domains";
|
package/src/manifest.ts
CHANGED
|
@@ -10,6 +10,13 @@ export interface ManifestAuthor {
|
|
|
10
10
|
/** A dependency value: a semver range, or a partial-dep object. */
|
|
11
11
|
export type ModuleDependency = string | { version: string; entities?: string[] };
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* A platform behaviour a package can opt into via `manifest.features`.
|
|
15
|
+
* Mirrors `dForge.Core.ModuleFeatures` and the `features` enum in
|
|
16
|
+
* manifest.schema.json — all three are edited together.
|
|
17
|
+
*/
|
|
18
|
+
export type ModuleFeature = "report-security";
|
|
19
|
+
|
|
13
20
|
/** A module package manifest (`manifest.json`). */
|
|
14
21
|
export interface ManifestDef {
|
|
15
22
|
/** Package format version (currently 1). */
|
|
@@ -47,6 +54,20 @@ export interface ManifestDef {
|
|
|
47
54
|
icon?: string;
|
|
48
55
|
/** Non-English locales the package promises to translate. */
|
|
49
56
|
supportedLocales?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Opt-in platform behaviours this package was authored for. Absent or empty
|
|
59
|
+
* = the pre-feature behaviour for all of them, so a module written before a
|
|
60
|
+
* feature existed keeps working until its author declares it and republishes.
|
|
61
|
+
*
|
|
62
|
+
* Unknown names are rejected at package load, never ignored — a misspelled
|
|
63
|
+
* feature would silently leave the old behaviour in place while the manifest
|
|
64
|
+
* claims otherwise.
|
|
65
|
+
*
|
|
66
|
+
* - `report-security` — this module's reports require 'E' on their
|
|
67
|
+
* `sec_object`. Declare the matching `"report:<code>": "E"` grants in
|
|
68
|
+
* `security/roles.json` first, or the reports go dark for every role.
|
|
69
|
+
*/
|
|
70
|
+
features?: ModuleFeature[];
|
|
50
71
|
/** Initial creation date (YYYY-MM-DD). Informational. */
|
|
51
72
|
created?: string;
|
|
52
73
|
/** Last manifest edit date (YYYY-MM-DD). Informational. */
|
package/src/reports.ts
CHANGED
|
@@ -30,25 +30,79 @@ export const chartTypes: readonly NamedKind[] = [
|
|
|
30
30
|
{ cd: "funnel", name: "Funnel" },
|
|
31
31
|
] as const;
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
export interface
|
|
35
|
-
/** Field type code (see settings for the common list). */
|
|
36
|
-
fieldTypeCd: string;
|
|
33
|
+
/** Everything a report parameter carries regardless of where its control comes from. */
|
|
34
|
+
export interface ParamDefBase {
|
|
37
35
|
label?: string;
|
|
38
36
|
/** Display order in the parameter form (falls back to declaration order). */
|
|
39
37
|
orderNum?: number;
|
|
40
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Whether the user must provide a value. Stored inverted as `param.is_nullable`.
|
|
40
|
+
* There is no `isRequired` spelling — the installer reads this key only.
|
|
41
|
+
*/
|
|
41
42
|
required?: boolean;
|
|
42
|
-
/** Alternate spelling of `required` used by some modules. Prefer `required`. */
|
|
43
|
-
isRequired?: boolean;
|
|
44
43
|
/** Default value applied when the user doesn't provide one. */
|
|
45
44
|
default?: unknown;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Field-type-specific params, nested under this key — there is no top-level
|
|
47
|
+
* `link`. A lookup param needs `{ link: { entity, otherKey? } }`.
|
|
48
|
+
* Most importantly `options` for a dropdown.
|
|
49
|
+
* Options accept the same rich `{value,label,icon,color}` form entity columns
|
|
50
|
+
* use; a bare string list renders the raw codes in every locale, so label them.
|
|
51
|
+
* Omitted on a domain-backed param: the domain owns the list.
|
|
52
|
+
*/
|
|
49
53
|
params?: Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Declares a REFERENCE parameter: the submitted value is the whole picked
|
|
56
|
+
* record rather than its bare key. The JSON counterpart of the action DSL's
|
|
57
|
+
* `paramCd: ref <entityCd>`, stored in the same `param.column_type`.
|
|
58
|
+
*
|
|
59
|
+
* Optional, and the choice is not cosmetic. Omitting it (a plain `lookup`)
|
|
60
|
+
* submits the key, which is what a filter comparing against a reference
|
|
61
|
+
* column needs — the server destructures a key object across every key
|
|
62
|
+
* column and ignores non-key fields. Declare `"R"` when the report wants the
|
|
63
|
+
* record itself, not just its identity.
|
|
64
|
+
*
|
|
65
|
+
* Either way the picker is configured by `params.link` (`{ entity, otherKey? }`);
|
|
66
|
+
* `otherKey` is filled from the target's primary key when omitted, comma-joined
|
|
67
|
+
* and paired POSITIONALLY with the key columns.
|
|
68
|
+
*/
|
|
69
|
+
columnType?: "R";
|
|
50
70
|
}
|
|
51
71
|
|
|
72
|
+
/**
|
|
73
|
+
* A report parameter definition. Declared in the report-level `parameters` block,
|
|
74
|
+
* or as shorthand under the `params` of the dataset that consumes it — the
|
|
75
|
+
* installer merges both into the report's single param set, so either way the
|
|
76
|
+
* parameter serves the whole report. Report level wins on a code collision, and
|
|
77
|
+
* is the only sensible home for a parameter several datasets use.
|
|
78
|
+
*
|
|
79
|
+
* A parameter takes its control from an explicit `fieldTypeCd` **or** from a
|
|
80
|
+
* column `domain` — never both. Declaring both is the one rejected combination
|
|
81
|
+
* (`not: { required: ["fieldTypeCd", "domain"] }` in `reports.schema.json`, and an
|
|
82
|
+
* install-time check that refuses to silently pick a winner). Declaring **neither**
|
|
83
|
+
* is fine: the param installs as `text`.
|
|
84
|
+
*
|
|
85
|
+
* Prefer `domain` whenever the choices are the same list a column uses (the usual
|
|
86
|
+
* case, since the value normally ends up written to that column): the options and
|
|
87
|
+
* their translations then live on the domain and are authored once, instead of
|
|
88
|
+
* being restated per parameter and left to drift.
|
|
89
|
+
*/
|
|
90
|
+
export type ParamDef =
|
|
91
|
+
| (ParamDefBase & {
|
|
92
|
+
/** Field type code (see settings for the common list). Defaults to `text`. */
|
|
93
|
+
fieldTypeCd?: string;
|
|
94
|
+
domain?: never;
|
|
95
|
+
})
|
|
96
|
+
| (ParamDefBase & {
|
|
97
|
+
/**
|
|
98
|
+
* Column domain (`domain_cd` or `module_cd.domain_cd`) supplying the control
|
|
99
|
+
* and the option list. The DSL equivalent for action params is
|
|
100
|
+
* `paramCd: domain <domainCd>`.
|
|
101
|
+
*/
|
|
102
|
+
domain: string;
|
|
103
|
+
fieldTypeCd?: never;
|
|
104
|
+
});
|
|
105
|
+
|
|
52
106
|
/** SQL/entity query for a `datasetType: 'Q'` dataset. */
|
|
53
107
|
export interface ReportQuery {
|
|
54
108
|
/** Source entity code. */
|
|
@@ -78,10 +132,42 @@ export interface Dataset {
|
|
|
78
132
|
procedureName?: string;
|
|
79
133
|
/** Optional column metadata overrides: field code → override. */
|
|
80
134
|
columnsDef?: Record<string, ColumnDef>;
|
|
81
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Parameters declared on this dataset — shorthand for the report-level
|
|
137
|
+
* `parameters` block, convenient when exactly one dataset uses the parameter.
|
|
138
|
+
* The installer merges both into the report's one param set either way.
|
|
139
|
+
*/
|
|
82
140
|
params?: Record<string, ParamDef>;
|
|
83
141
|
}
|
|
84
142
|
|
|
143
|
+
/**
|
|
144
|
+
* One (entity, report) **record-report attachment**: the report becomes openable
|
|
145
|
+
* from that entity's record, with the record's values feeding its parameters.
|
|
146
|
+
* Each entry becomes one `dForge.entity_report` row.
|
|
147
|
+
*
|
|
148
|
+
* The binding is per-attachment, not per-report — the same report can attach to
|
|
149
|
+
* several entities with different parameter mappings, which is why the mapping
|
|
150
|
+
* lives here rather than on the report.
|
|
151
|
+
*/
|
|
152
|
+
export interface ReportEntityAttachment {
|
|
153
|
+
/**
|
|
154
|
+
* Entity the report attaches to, qualified `module.entity` for anything
|
|
155
|
+
* outside the declaring module. That module must be a declared dependency.
|
|
156
|
+
*/
|
|
157
|
+
entityCd: string;
|
|
158
|
+
/**
|
|
159
|
+
* Parameter mapping: report param code → **source column on the entity**.
|
|
160
|
+
* (Not a param declaration — those live in the report's `parameters` block or a
|
|
161
|
+
* dataset's `params`.) Resolved server-side
|
|
162
|
+
* from the record's PK. Source columns are limited to the PK, reference (`R`)
|
|
163
|
+
* columns, and bounded scalars; source and target must be type-compatible.
|
|
164
|
+
* Params left unmapped keep their normal behaviour (default, or prompt).
|
|
165
|
+
*/
|
|
166
|
+
params?: Record<string, string>;
|
|
167
|
+
/** Sort position in the record's combined action + report menu. */
|
|
168
|
+
orderNum?: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
85
171
|
/** A single visualization panel within the report layout. */
|
|
86
172
|
export interface ReportPanel {
|
|
87
173
|
vizType: VizType;
|
|
@@ -103,8 +189,21 @@ export interface ReportDef {
|
|
|
103
189
|
layout: ReportLayout;
|
|
104
190
|
/** Dataset code → dataset definition. */
|
|
105
191
|
datasets: Record<string, Dataset>;
|
|
106
|
-
/**
|
|
192
|
+
/** Auto-refresh interval in seconds. Omit (or 0) for no auto-refresh. */
|
|
193
|
+
reloadInterval?: number;
|
|
194
|
+
/**
|
|
195
|
+
* Report-level parameter declarations — the canonical home for a parameter, and
|
|
196
|
+
* the only one that fits a parameter several datasets use. Merged with each
|
|
197
|
+
* dataset's `params` into the report's single param set; this block wins on a
|
|
198
|
+
* code collision.
|
|
199
|
+
*/
|
|
107
200
|
parameters?: Record<string, ParamDef>;
|
|
201
|
+
/**
|
|
202
|
+
* Record-report attachments: entities this report can be opened from, with the
|
|
203
|
+
* mapping from report parameter to source column on each. Omit for a report
|
|
204
|
+
* that is only reached from a menu.
|
|
205
|
+
*/
|
|
206
|
+
entities?: ReportEntityAttachment[];
|
|
108
207
|
}
|
|
109
208
|
|
|
110
209
|
/** A `ui/reports.json` file: report code → definition. */
|