@holistics/anfra-sdk 0.7.1 → 0.8.0

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.
@@ -86,6 +86,19 @@ interface User {
86
86
  */
87
87
  interface SdkFeatures {
88
88
  dateDrill?: boolean;
89
+ /**
90
+ * Whether the host can export a query's result (`query.export()`): its Backend has
91
+ * `exportQuery`. `mountDataApp` says so for every frame; `createSdk` reads it off the Backend
92
+ * when the host does not. An author shows an export button when this and
93
+ * `user.permissions.canExportData` are both true.
94
+ */
95
+ export?: boolean;
96
+ /**
97
+ * Whether `Anfra.render()` can save a rendering here: the host turned it on
98
+ * (`mountDataApp({ render: true })`). An author shows a render button when this and
99
+ * `user.permissions.canExportData` are both true.
100
+ */
101
+ render?: boolean;
89
102
  }
90
103
  interface SdkEnvironment {
91
104
  datasets: Record<string, DatasetDescriptor>;
@@ -94,6 +107,37 @@ interface SdkEnvironment {
94
107
  backend: Backend;
95
108
  /** Absent means the host did not say, and nothing is blocked; only an explicit `false` throws. */
96
109
  features?: SdkFeatures;
110
+ /** Draws and saves a rendering: given by the frame bootstrap, which can reach the page and the host. */
111
+ render?: (request: RenderRequest) => Promise<Rendering>;
112
+ }
113
+ /** A rendering's file format. A PDF is one page the size of the rendering. */
114
+ type RenderFormat = 'png' | 'pdf';
115
+ /**
116
+ * What to render, and how. `block` or `container` names one node of the structure by its id;
117
+ * neither renders the whole app.
118
+ */
119
+ interface RenderRequest {
120
+ block?: string;
121
+ container?: string;
122
+ format: RenderFormat;
123
+ /** The file's name, with the format's extension added when it has none. */
124
+ filename?: string;
125
+ /** Device pixels per CSS pixel. Defaults to the screen's, at least 2, lowered to fit a canvas. */
126
+ pixelRatio?: number;
127
+ }
128
+ /** A picture of the app, or of one node, as the reader saw it: saved for them, and handed back. */
129
+ interface Rendering {
130
+ filename: string;
131
+ format: RenderFormat;
132
+ /** In CSS pixels: what was drawn, before `pixelRatio`. */
133
+ width: number;
134
+ height: number;
135
+ blob: Blob;
136
+ /**
137
+ * Images left blank in the picture, by URL: their servers send no CORS headers, so the browser
138
+ * won't let them be drawn. Their space is kept. Empty when nothing was left out.
139
+ */
140
+ omitted: string[];
97
141
  }
98
142
  type ConditionValue = string | number | boolean;
99
143
  /**
@@ -522,6 +566,57 @@ interface BackendQueryResult {
522
566
  };
523
567
  debug?: QueryDebug;
524
568
  }
569
+ /** A file format an export can be written in. CSV is the only one yet; a server may add more. */
570
+ type ExportFormat = 'csv' | (string & {});
571
+ /** A format's options. Each applies to the formats it names; the server refuses one given to another. */
572
+ interface ExportFormatOptions {
573
+ /** csv: the header row: the columns' labels (the default), their names, or none. */
574
+ header?: 'labels' | 'names' | 'none';
575
+ /** csv: start the file with a UTF-8 byte-order mark, which Excel needs to read non-ASCII text. */
576
+ bom?: boolean;
577
+ }
578
+ /** What `query.export()` takes. Every field is optional. */
579
+ interface ExportOptions {
580
+ /**
581
+ * The file's name, with the format's extension added when it has none. Defaults to the app's
582
+ * title and the query's name (`Sales - revenueByMonth.csv`), or the query's name alone.
583
+ */
584
+ filename?: string;
585
+ /** `csv` unless given. */
586
+ format?: ExportFormat;
587
+ /** For CSV, `bom` defaults to `true`: a person opens what a Data App exports. */
588
+ formatOptions?: ExportFormatOptions;
589
+ /** Cancels the export. `query.abort()` does not: an export is not the query's run. */
590
+ signal?: AbortSignal;
591
+ }
592
+ /**
593
+ * A query's whole result as a file: what the Backend made, and the host has already started
594
+ * saving for the reader. `url` works with a plain `GET` until `expiresAt`.
595
+ */
596
+ interface ExportResult {
597
+ url: string;
598
+ filename: string;
599
+ format: ExportFormat;
600
+ /** The rows the file holds. */
601
+ rowCount: number;
602
+ expiresAt: Date;
603
+ }
604
+ /**
605
+ * An export: the same query a run sends, built by the same code so the two cannot drift, but with
606
+ * no page (an export is every row) and no cache to bust; plus the file's format and name.
607
+ */
608
+ interface BackendExportRequest {
609
+ /** The dataset's `name`, as in `DatasetDescriptor.name`. */
610
+ dataset: string;
611
+ /** The query's AQL, verbatim. */
612
+ aql: string;
613
+ input: QueryInput;
614
+ /** Absent when the app declares none, leaving the backend's default. */
615
+ timezone?: string;
616
+ format?: ExportFormat;
617
+ formatOptions?: ExportFormatOptions;
618
+ filename?: string;
619
+ }
525
620
  interface FieldSuggestionsRequest {
526
621
  /** The dataset's `name`. */
527
622
  dataset: string;
@@ -540,6 +635,11 @@ interface FieldSuggestionsRequest {
540
635
  interface Backend {
541
636
  submitQuery(request: BackendQueryRequest, signal: AbortSignal): Promise<BackendQueryResult>;
542
637
  fieldSuggestions(request: FieldSuggestionsRequest, signal: AbortSignal): Promise<ConditionValue[]>;
638
+ /**
639
+ * Export a query's whole result as a file, and answer its link once the file is ready. Optional:
640
+ * a host that cannot export leaves it out, and `query.export()` rejects with a `TransportError`.
641
+ */
642
+ exportQuery?(request: BackendExportRequest, signal: AbortSignal): Promise<ExportResult>;
543
643
  }
544
644
 
545
- export { type StructureKind as $, type Aggregation as A, type Backend as B, type ColumnMeta as C, type DatasetDescriptor as D, type EntityKind as E, FILTER_AGGREGATIONS as F, type InspectedQuery as G, type InspectedSelection as H, type InspectedApp as I, type InspectedStructure as J, type LocateKind as K, type Listener as L, type LocateTarget as M, type MappingJson as N, type Operator as O, type QueryDeclaration as P, type QueryDebug as Q, type QueryInput as R, type QueryResult as S, type QuerySort as T, type QueryState as U, type Row as V, type SdkEnvironment as W, type SdkFeatures as X, type Selection as Y, type SelectionCondition as Z, type SemanticType as _, type AppDeclaration as a, type StructureNode as a0, type Unsubscribe as a1, type User as a2, type AppJson as b, type ArrowType as c, type BackendCondition as d, type BackendDateDrill as e, type BackendFilter as f, type BackendQueryRequest as g, type BackendQueryResult as h, type BackendSort as i, type Condition as j, type ConditionValue as k, type ControlMappingJson as l, type CrossFilterJson as m, type DateDrillDeclaration as n, type DateGrain as o, type DateTransformation as p, type EntityRef as q, type EntityUsage as r, type ExecuteOptions as s, type ExecuteSummary as t, type FieldSuggestionsRequest as u, type FilterAggregation as v, type FilterDeclaration as w, type FilterValueType as x, type InspectedControl as y, type InspectedError as z };
645
+ export { type RenderRequest as $, type Aggregation as A, type Backend as B, type ColumnMeta as C, type DatasetDescriptor as D, type EntityKind as E, FILTER_AGGREGATIONS as F, type FilterAggregation as G, type FilterDeclaration as H, type FilterValueType as I, type InspectedApp as J, type InspectedControl as K, type InspectedError as L, type InspectedQuery as M, type InspectedSelection as N, type InspectedStructure as O, type Listener as P, type LocateKind as Q, type LocateTarget as R, type MappingJson as S, type Operator as T, type QueryDebug as U, type QueryDeclaration as V, type QueryInput as W, type QueryResult as X, type QuerySort as Y, type QueryState as Z, type RenderFormat as _, type AppDeclaration as a, type Rendering as a0, type Row as a1, type SdkEnvironment as a2, type SdkFeatures as a3, type Selection as a4, type SelectionCondition as a5, type SemanticType as a6, type StructureKind as a7, type StructureNode as a8, type Unsubscribe as a9, type User as aa, type AppJson as b, type ArrowType as c, type BackendCondition as d, type BackendDateDrill as e, type BackendExportRequest as f, type BackendFilter as g, type BackendQueryRequest as h, type BackendQueryResult as i, type BackendSort as j, type Condition as k, type ConditionValue as l, type ControlMappingJson as m, type CrossFilterJson as n, type DateDrillDeclaration as o, type DateGrain as p, type DateTransformation as q, type EntityRef as r, type EntityUsage as s, type ExecuteOptions as t, type ExecuteSummary as u, type ExportFormat as v, type ExportFormatOptions as w, type ExportOptions as x, type ExportResult as y, type FieldSuggestionsRequest as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holistics/anfra-sdk",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "Data Apps on anfra: the authoring layer (app), what hosts one (host), the core API client (api), and their shared contract (common)",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -51,6 +51,7 @@
51
51
  "devDependencies": {
52
52
  "@types/node": "^22.20.4",
53
53
  "esbuild": "^0.28.2",
54
+ "html-to-image": "1.11.13",
54
55
  "jsdom": "^26.1.0",
55
56
  "openapi-typescript": "^7.13.0",
56
57
  "tsup": "^8.5.1",
@@ -1,7 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
-
5
- export {
6
- __publicField
7
- };