@softr/sdk 0.0.4 → 0.0.6

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/dist/tanstack.js CHANGED
@@ -1,6 +1,10 @@
1
+ import { i as dealiasOrderBy, n as buildOrderBy, r as dealiasFilterCriteria, t as buildFilterCriteria } from "./query-C6022JhD.js";
1
2
  import { createMiddleware } from "@tanstack/start";
2
3
 
3
4
  //#region src/core/datasource.ts
5
+ const MAX_RECORD_COUNT = 100;
6
+ const COUNT_CNT = "COUNT_CNT";
7
+ const APP_TIMEZONE = "UTC";
4
8
  var DatasourceAPIImpl = class {
5
9
  id;
6
10
  fetch;
@@ -8,43 +12,207 @@ var DatasourceAPIImpl = class {
8
12
  this.id = id;
9
13
  this.fetch = fetch$1;
10
14
  }
11
- async list(options) {
12
- const params = new URLSearchParams();
13
- if (options?.page != null) params.set("page", String(options.page));
14
- if (options?.limit != null) params.set("limit", String(options.limit));
15
- if (options?.filters?.length) params.set("filters", JSON.stringify(options.filters));
16
- if (options?.sort?.length) params.set("sort", JSON.stringify(options.sort));
17
- const query = params.toString() ? `?${params}` : "";
18
- const res = await this.fetch(`/api/datasources/${this.id}/records${query}`);
19
- if (!res.ok) throw new Error(`Softr datasource list failed: ${res.status}`);
20
- return res.json();
21
- }
22
- async get(recordId) {
23
- const res = await this.fetch(`/api/datasources/${this.id}/records/${recordId}`);
24
- if (!res.ok) throw new Error(`Softr datasource get failed: ${res.status}`);
25
- return res.json();
26
- }
27
- async create(data) {
15
+ async list(options = {}) {
16
+ const { select, where, orderBy } = options;
17
+ const count = Math.min(options.limit ?? 20, MAX_RECORD_COUNT);
18
+ const offset = options.offset ?? null;
19
+ const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
20
+ const sortingOption = orderBy ? dealiasOrderBy(buildOrderBy(orderBy), select ?? {}) : void 0;
21
+ const res = await this.fetch(`/api/datasources/${this.id}/records`, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ "X-User-Timezone": APP_TIMEZONE
26
+ },
27
+ body: JSON.stringify({
28
+ options: {
29
+ timeZone: APP_TIMEZONE,
30
+ userLocale: "en-US"
31
+ },
32
+ filterCriteria,
33
+ sortingOption,
34
+ pagingOption: {
35
+ offset,
36
+ count
37
+ }
38
+ })
39
+ });
40
+ if (!res.ok) throw new Error(`Softr datasource list failed for "${this.id}": ${res.status}`);
41
+ const payload = await res.json();
42
+ const nextOffset = payload.offset < payload.total ? payload.offset : null;
43
+ return {
44
+ records: payload.items.map((item) => ({
45
+ id: item.id,
46
+ fields: select ? aliasFields(item.fields, select) : item.fields
47
+ })),
48
+ total: payload.total,
49
+ nextOffset
50
+ };
51
+ }
52
+ async get(options) {
53
+ if (options.id !== void 0) {
54
+ if (!options.id) throw new Error(`Softr datasource get: id must not be empty`);
55
+ const res = await this.fetch(`/api/datasources/${this.id}/records/${options.id}`, {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ "X-User-Timezone": APP_TIMEZONE
60
+ },
61
+ body: JSON.stringify({ options: {
62
+ timeZone: APP_TIMEZONE,
63
+ userLocale: "en-US"
64
+ } })
65
+ });
66
+ if (!res.ok) throw new Error(`Softr datasource get failed for "${this.id}": ${res.status}`);
67
+ const contentLength = res.headers.get("Content-Length");
68
+ if (contentLength && parseInt(contentLength, 10) === 0) return null;
69
+ return res.json();
70
+ }
71
+ return (await this.list({
72
+ where: options.where,
73
+ limit: 1
74
+ })).records[0] ?? null;
75
+ }
76
+ async create(options) {
28
77
  const res = await this.fetch(`/api/datasources/${this.id}/records`, {
29
78
  method: "POST",
30
79
  headers: { "Content-Type": "application/json" },
31
- body: JSON.stringify(data)
80
+ body: JSON.stringify({ fields: options.fields })
32
81
  });
33
- if (!res.ok) throw new Error(`Softr datasource create failed: ${res.status}`);
34
- return res.json();
82
+ if (!res.ok) throw new Error(`Softr datasource create failed for "${this.id}": ${res.status}`);
83
+ return (await res.json()).record;
35
84
  }
36
- async update(recordId, data) {
37
- const res = await this.fetch(`/api/datasources/${this.id}/records/${recordId}`, {
85
+ async update(options) {
86
+ if (!options.id) throw new Error(`Softr datasource update: id must not be empty`);
87
+ const res = await this.fetch(`/api/datasources/${this.id}/records/${options.id}`, {
38
88
  method: "PATCH",
39
89
  headers: { "Content-Type": "application/json" },
40
- body: JSON.stringify(data)
90
+ body: JSON.stringify({ fields: options.fields })
41
91
  });
42
- if (!res.ok) throw new Error(`Softr datasource update failed: ${res.status}`);
43
- return res.json();
92
+ if (!res.ok) throw new Error(`Softr datasource update failed for "${this.id}": ${res.status}`);
93
+ return (await res.json()).record;
44
94
  }
45
- async delete(recordId) {
46
- const res = await this.fetch(`/api/datasources/${this.id}/records/${recordId}`, { method: "DELETE" });
47
- if (!res.ok) throw new Error(`Softr datasource delete failed: ${res.status}`);
95
+ async delete(id) {
96
+ const res = await this.fetch(`/api/datasources/${this.id}/records/${id}`, { method: "DELETE" });
97
+ if (!res.ok) throw new Error(`Softr datasource delete failed for "${this.id}": ${res.status}`);
98
+ }
99
+ async metric(options) {
100
+ const { select, where, aggregation, field } = options;
101
+ const fieldId = field ? select?.[field] ?? field : void 0;
102
+ const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
103
+ const res = await this.fetch(`/api/datasources/${this.id}/chartMetricData`, {
104
+ method: "POST",
105
+ headers: {
106
+ "Content-Type": "application/json",
107
+ "X-User-Timezone": APP_TIMEZONE
108
+ },
109
+ body: JSON.stringify({
110
+ options: {
111
+ timeZone: APP_TIMEZONE,
112
+ userLocale: "en-US"
113
+ },
114
+ calculationField: {
115
+ field: fieldId,
116
+ aggregation
117
+ },
118
+ filterCriteria
119
+ })
120
+ });
121
+ if (!res.ok) throw new Error(`Softr datasource metric failed for "${this.id}": ${res.status}`);
122
+ const payload = await res.json();
123
+ const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
124
+ let value;
125
+ if (aggregation === "COUNT") value = payload.data.find((item) => COUNT_CNT in item)?.[COUNT_CNT] ?? null;
126
+ else {
127
+ if (!fieldId) throw new Error(`field is required for aggregation "${aggregation}"`);
128
+ value = payload.data.find((item) => fieldId in item)?.[fieldId] ?? null;
129
+ }
130
+ return {
131
+ value,
132
+ executionTimestamp
133
+ };
134
+ }
135
+ async chartData(options) {
136
+ const { select, where, groupBy, metrics, orderBy } = options;
137
+ const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
138
+ const sortingOption = orderBy ? dealiasOrderBy(buildOrderBy(orderBy), select ?? {})[0] : void 0;
139
+ const groupByFields = (Array.isArray(groupBy) ? groupBy : [groupBy]).map((field) => ({ field: select?.[field] ?? field }));
140
+ const yAxisFields = Object.values(metrics).map(({ field, aggregation }) => ({
141
+ field: field ? select?.[field] ?? field : void 0,
142
+ aggregation
143
+ }));
144
+ const res = await this.fetch(`/api/datasources/${this.id}/chartData`, {
145
+ method: "POST",
146
+ headers: {
147
+ "Content-Type": "application/json",
148
+ "X-User-Timezone": APP_TIMEZONE
149
+ },
150
+ body: JSON.stringify({
151
+ filterCriteria,
152
+ sortingOption,
153
+ xAxisFields: groupByFields,
154
+ yAxisFields
155
+ })
156
+ });
157
+ if (!res.ok) throw new Error(`Softr datasource chartData failed for "${this.id}": ${res.status}`);
158
+ const payload = await res.json();
159
+ const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
160
+ const aliases = {};
161
+ const multipleMetrics = Object.keys(metrics).length > 1;
162
+ for (const [alias, { field, aggregation }] of Object.entries(metrics)) if (aggregation === "COUNT") aliases[COUNT_CNT] = alias;
163
+ else {
164
+ const fieldId = field ? select?.[field] ?? field : field;
165
+ if (fieldId) {
166
+ const suffix = multipleMetrics ? `_${aggregation.toLowerCase()}` : "";
167
+ aliases[fieldId + suffix] = alias;
168
+ }
169
+ }
170
+ for (const field of Array.isArray(groupBy) ? groupBy : [groupBy]) aliases[select?.[field] ?? field] = field;
171
+ return {
172
+ data: payload.data.map((item) => {
173
+ const row = {};
174
+ for (const [rawKey, alias] of Object.entries(aliases)) if (rawKey in item) row[alias] = item[rawKey];
175
+ return row;
176
+ }),
177
+ executionTimestamp
178
+ };
179
+ }
180
+ };
181
+ function aliasFields(fields, aliases) {
182
+ const result = {};
183
+ for (const [alias, fieldId] of Object.entries(aliases)) result[alias] = fields[fieldId];
184
+ return result;
185
+ }
186
+
187
+ //#endregion
188
+ //#region src/core/integration.ts
189
+ var IntegrationAPIImpl = class {
190
+ id;
191
+ request;
192
+ constructor(id, fetch$1) {
193
+ this.id = id;
194
+ this.request = fetch$1;
195
+ }
196
+ async fetch(input, init) {
197
+ const req = new Request(input, init);
198
+ if (req.signal.aborted) throw req.signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
199
+ const headers = {};
200
+ new Headers(req.headers).forEach((value, key) => {
201
+ headers[key] = value;
202
+ });
203
+ const payload = {
204
+ method: req.method,
205
+ url: req.url,
206
+ headers
207
+ };
208
+ const method = req.method.toUpperCase();
209
+ if (method !== "GET" && method !== "HEAD" && req.body !== null) payload.body = await req.clone().text();
210
+ return this.request(`/api/integrations/${this.id}/proxy`, {
211
+ method: "POST",
212
+ headers: { "Content-Type": "application/json" },
213
+ body: JSON.stringify(payload),
214
+ signal: req.signal
215
+ });
48
216
  }
49
217
  };
50
218
 
@@ -108,6 +276,9 @@ var SoftrSDKImpl = class {
108
276
  datasource(id) {
109
277
  return new DatasourceAPIImpl(id, this._fetch.bind(this));
110
278
  }
279
+ integration(id) {
280
+ return new IntegrationAPIImpl(id, this._fetch.bind(this));
281
+ }
111
282
  workflow(id) {
112
283
  return new WorkflowAPIImpl(id, this._fetch.bind(this));
113
284
  }