@softr/sdk 0.0.10 → 0.0.12
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/index.d.ts +3 -516
- package/dist/index.js +2 -845
- package/dist/server.d.ts +32 -2
- package/dist/server.js +243 -13
- package/dist/session-kTqxT5_K.js +891 -0
- package/dist/types-n-Sir_Y2.d.ts +482 -0
- package/package.json +1 -1
- package/dist/session-Blx62HHJ.js +0 -334
- package/dist/user-D23hwTsf.d.ts +0 -28
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as User } from "./
|
|
1
|
+
import { c as ListResult, h as UpdateOptions, i as CreateOptions, l as MetricOptions, n as ChartDataOptions, o as GetOptions, p as SoftrRecord, r as ChartDataResult, s as ListOptions, u as MetricResult, v as User } from "./types-n-Sir_Y2.js";
|
|
2
2
|
import "@tanstack/react-start/server-only";
|
|
3
3
|
|
|
4
4
|
//#region src/auth/methods/utils.d.ts
|
|
@@ -82,4 +82,34 @@ declare const auth: {
|
|
|
82
82
|
confirmSignUp: typeof confirmSignUp;
|
|
83
83
|
};
|
|
84
84
|
//#endregion
|
|
85
|
-
|
|
85
|
+
//#region src/core/datasource.d.ts
|
|
86
|
+
declare function listRecords(datasourceId: string, options?: ListOptions): Promise<ListResult>;
|
|
87
|
+
declare function getRecord(datasourceId: string, options: GetOptions): Promise<SoftrRecord | null>;
|
|
88
|
+
declare function createRecord(datasourceId: string, options: CreateOptions): Promise<SoftrRecord>;
|
|
89
|
+
declare function updateRecord(datasourceId: string, options: UpdateOptions): Promise<SoftrRecord>;
|
|
90
|
+
declare function deleteRecord(datasourceId: string, id: string): Promise<void>;
|
|
91
|
+
declare function getMetric(datasourceId: string, options: MetricOptions): Promise<MetricResult>;
|
|
92
|
+
declare function getChartData(datasourceId: string, options: ChartDataOptions): Promise<ChartDataResult>;
|
|
93
|
+
declare const ds: {
|
|
94
|
+
list: typeof listRecords;
|
|
95
|
+
get: typeof getRecord;
|
|
96
|
+
create: typeof createRecord;
|
|
97
|
+
update: typeof updateRecord;
|
|
98
|
+
delete: typeof deleteRecord;
|
|
99
|
+
metric: typeof getMetric;
|
|
100
|
+
chartData: typeof getChartData;
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/core/workflow.d.ts
|
|
104
|
+
declare function triggerWorkflow(workflowId: string, payload?: Record<string, unknown>): Promise<void>;
|
|
105
|
+
declare const workflow: {
|
|
106
|
+
trigger: typeof triggerWorkflow;
|
|
107
|
+
};
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/core/integration.d.ts
|
|
110
|
+
declare function integrationFetch(integrationId: string, input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
111
|
+
declare const integration: {
|
|
112
|
+
fetch: typeof integrationFetch;
|
|
113
|
+
};
|
|
114
|
+
//#endregion
|
|
115
|
+
export { auth, ds, integration, workflow };
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as readSessionToken, c as
|
|
1
|
+
import { _ as dealiasOrderBy, a as readSessionToken, c as readUserTimezone, d as panic, f as softAssert, g as dealiasFilterCriteria, h as buildOrderBy, l as writeCookies, m as buildFilterCriteria, n as makeSessionDataCookie, o as fetchVisitor, p as todo, r as makeSessionTokenCookie, s as platformFetch, t as clearSession } from "./session-kTqxT5_K.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import "@tanstack/react-start/server-only";
|
|
4
4
|
|
|
@@ -18,9 +18,6 @@ async function describe(response, action) {
|
|
|
18
18
|
const said = body.success && body.data.message ? body.data.message : response.statusText;
|
|
19
19
|
return `Softr platform refused the ${action}: ${response.status} ${said}`.trim();
|
|
20
20
|
}
|
|
21
|
-
function endpoint(config, path) {
|
|
22
|
-
return `${config.platformApiUrl}/v1/applications/${config.applicationId}/users/${path}`;
|
|
23
|
-
}
|
|
24
21
|
|
|
25
22
|
//#endregion
|
|
26
23
|
//#region src/auth/methods/password.ts
|
|
@@ -35,8 +32,7 @@ const signInBody = z.object({
|
|
|
35
32
|
* so the next request costs no round-trip.
|
|
36
33
|
*/
|
|
37
34
|
async function signIn(credentials) {
|
|
38
|
-
const
|
|
39
|
-
const response = await fetch(endpoint(config, "sign-in"), {
|
|
35
|
+
const response = await platformFetch("sign-in", {
|
|
40
36
|
method: "POST",
|
|
41
37
|
headers: {
|
|
42
38
|
"content-type": "application/json",
|
|
@@ -73,11 +69,10 @@ async function signIn(credentials) {
|
|
|
73
69
|
* because the local half already succeeded.
|
|
74
70
|
*/
|
|
75
71
|
async function signOut() {
|
|
76
|
-
const config = sessionConfig();
|
|
77
72
|
const token = readSessionToken();
|
|
78
73
|
clearSession();
|
|
79
74
|
if (!token) return;
|
|
80
|
-
const response = await
|
|
75
|
+
const response = await platformFetch("sign-out", {
|
|
81
76
|
method: "POST",
|
|
82
77
|
headers: {
|
|
83
78
|
authorization: `Bearer ${token}`,
|
|
@@ -95,7 +90,7 @@ async function signOut() {
|
|
|
95
90
|
* User only exists once `confirmSignUp` returns the code.
|
|
96
91
|
*/
|
|
97
92
|
async function signUp(details) {
|
|
98
|
-
const response = await
|
|
93
|
+
const response = await platformFetch("sign-up", {
|
|
99
94
|
method: "POST",
|
|
100
95
|
headers: {
|
|
101
96
|
"content-type": "application/json",
|
|
@@ -120,8 +115,7 @@ async function signUp(details) {
|
|
|
120
115
|
* `users/new`.
|
|
121
116
|
*/
|
|
122
117
|
async function confirmSignUp(details) {
|
|
123
|
-
const
|
|
124
|
-
const verified = await fetch(endpoint(config, "sign-up"), {
|
|
118
|
+
const verified = await platformFetch("sign-up", {
|
|
125
119
|
method: "POST",
|
|
126
120
|
headers: {
|
|
127
121
|
"content-type": "application/json",
|
|
@@ -138,7 +132,7 @@ async function confirmSignUp(details) {
|
|
|
138
132
|
const verifiedBody = await verified.text();
|
|
139
133
|
let token = tokenBody.parse(verifiedBody.length === 0 ? {} : JSON.parse(verifiedBody)).jwt;
|
|
140
134
|
if (!token) {
|
|
141
|
-
const created = await
|
|
135
|
+
const created = await platformFetch("new", {
|
|
142
136
|
method: "POST",
|
|
143
137
|
headers: {
|
|
144
138
|
"content-type": "application/json",
|
|
@@ -199,4 +193,240 @@ const auth = {
|
|
|
199
193
|
};
|
|
200
194
|
|
|
201
195
|
//#endregion
|
|
202
|
-
|
|
196
|
+
//#region src/core/datasource.ts
|
|
197
|
+
const MAX_RECORD_COUNT = 100;
|
|
198
|
+
const COUNT_CNT = "COUNT_CNT";
|
|
199
|
+
const BASE_URL$2 = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
|
|
200
|
+
async function listRecords(datasourceId, options = {}) {
|
|
201
|
+
const { select, where, orderBy } = options;
|
|
202
|
+
const count = Math.min(options.limit ?? 20, MAX_RECORD_COUNT);
|
|
203
|
+
const offset = options.offset ?? null;
|
|
204
|
+
const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
|
|
205
|
+
const sortingOption = orderBy ? dealiasOrderBy(buildOrderBy(orderBy), select ?? {}) : void 0;
|
|
206
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/records`, {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: {
|
|
209
|
+
"Content-Type": "application/json",
|
|
210
|
+
"X-User-Timezone": options.timeZone ?? readUserTimezone() ?? "UTC",
|
|
211
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
212
|
+
},
|
|
213
|
+
body: JSON.stringify({
|
|
214
|
+
options: { userLocale: "en-US" },
|
|
215
|
+
filterCriteria,
|
|
216
|
+
sortingOption,
|
|
217
|
+
pagingOption: {
|
|
218
|
+
offset,
|
|
219
|
+
count
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
if (!res.ok) throw new Error(`Softr datasource list failed for "${datasourceId}": ${res.status}`);
|
|
224
|
+
const payload = await res.json();
|
|
225
|
+
const nextOffset = payload.offset < payload.total ? payload.offset : null;
|
|
226
|
+
return {
|
|
227
|
+
records: payload.items.map((item) => ({
|
|
228
|
+
id: item.id,
|
|
229
|
+
fields: select ? aliasFields(item.fields, select) : item.fields
|
|
230
|
+
})),
|
|
231
|
+
total: payload.total,
|
|
232
|
+
nextOffset
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async function getRecord(datasourceId, options) {
|
|
236
|
+
if (options.id !== void 0) {
|
|
237
|
+
if (!options.id) throw new Error(`Softr datasource get: id must not be empty`);
|
|
238
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/records/${options.id}`, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: {
|
|
241
|
+
"Content-Type": "application/json",
|
|
242
|
+
"X-User-Timezone": options.timeZone ?? readUserTimezone() ?? "UTC",
|
|
243
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
244
|
+
},
|
|
245
|
+
body: JSON.stringify({ options: { userLocale: "en-US" } })
|
|
246
|
+
});
|
|
247
|
+
if (!res.ok) throw new Error(`Softr datasource get failed for "${datasourceId}": ${res.status}`);
|
|
248
|
+
const contentLength = res.headers.get("Content-Length");
|
|
249
|
+
if (contentLength && parseInt(contentLength, 10) === 0) return null;
|
|
250
|
+
return res.json();
|
|
251
|
+
}
|
|
252
|
+
return (await listRecords(datasourceId, {
|
|
253
|
+
where: options.where,
|
|
254
|
+
limit: 1,
|
|
255
|
+
timeZone: options.timeZone
|
|
256
|
+
})).records[0] ?? null;
|
|
257
|
+
}
|
|
258
|
+
async function createRecord(datasourceId, options) {
|
|
259
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/records`, {
|
|
260
|
+
method: "POST",
|
|
261
|
+
headers: {
|
|
262
|
+
"Content-Type": "application/json",
|
|
263
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
264
|
+
},
|
|
265
|
+
body: JSON.stringify({ fields: options.fields })
|
|
266
|
+
});
|
|
267
|
+
if (!res.ok) throw new Error(`Softr datasource create failed for "${datasourceId}": ${res.status}`);
|
|
268
|
+
return (await res.json()).record;
|
|
269
|
+
}
|
|
270
|
+
async function updateRecord(datasourceId, options) {
|
|
271
|
+
if (!options.id) throw new Error(`Softr datasource update: id must not be empty`);
|
|
272
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/records/${options.id}`, {
|
|
273
|
+
method: "PATCH",
|
|
274
|
+
headers: {
|
|
275
|
+
"Content-Type": "application/json",
|
|
276
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
277
|
+
},
|
|
278
|
+
body: JSON.stringify({ fields: options.fields })
|
|
279
|
+
});
|
|
280
|
+
if (!res.ok) throw new Error(`Softr datasource update failed for "${datasourceId}": ${res.status}`);
|
|
281
|
+
return (await res.json()).record;
|
|
282
|
+
}
|
|
283
|
+
async function deleteRecord(datasourceId, id) {
|
|
284
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/records/${id}`, {
|
|
285
|
+
method: "DELETE",
|
|
286
|
+
headers: { "Authorization": `Bearer ${readSessionToken()}` }
|
|
287
|
+
});
|
|
288
|
+
if (!res.ok) throw new Error(`Softr datasource delete failed for "${datasourceId}": ${res.status}`);
|
|
289
|
+
}
|
|
290
|
+
async function getMetric(datasourceId, options) {
|
|
291
|
+
const { select, where, aggregation, field } = options;
|
|
292
|
+
const fieldId = field ? select?.[field] ?? field : void 0;
|
|
293
|
+
const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
|
|
294
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/chartMetricData`, {
|
|
295
|
+
method: "POST",
|
|
296
|
+
headers: {
|
|
297
|
+
"Content-Type": "application/json",
|
|
298
|
+
"X-User-Timezone": options.timeZone ?? readUserTimezone() ?? "UTC",
|
|
299
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
300
|
+
},
|
|
301
|
+
body: JSON.stringify({
|
|
302
|
+
options: { userLocale: "en-US" },
|
|
303
|
+
calculationField: {
|
|
304
|
+
field: fieldId,
|
|
305
|
+
aggregation
|
|
306
|
+
},
|
|
307
|
+
filterCriteria
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
if (!res.ok) throw new Error(`Softr datasource metric failed for "${datasourceId}": ${res.status}`);
|
|
311
|
+
const payload = await res.json();
|
|
312
|
+
const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
|
|
313
|
+
let value;
|
|
314
|
+
if (aggregation === "COUNT") value = payload.data.find((item) => COUNT_CNT in item)?.[COUNT_CNT] ?? null;
|
|
315
|
+
else {
|
|
316
|
+
if (!fieldId) throw new Error(`field is required for aggregation "${aggregation}"`);
|
|
317
|
+
value = payload.data.find((item) => fieldId in item)?.[fieldId] ?? null;
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
value,
|
|
321
|
+
executionTimestamp
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
async function getChartData(datasourceId, options) {
|
|
325
|
+
const { select, where, groupBy, metrics, orderBy } = options;
|
|
326
|
+
const filterCriteria = where ? dealiasFilterCriteria(buildFilterCriteria(where), select ?? {}) : {};
|
|
327
|
+
const sortingOption = orderBy ? dealiasOrderBy(buildOrderBy(orderBy), select ?? {})[0] : void 0;
|
|
328
|
+
const groupByFields = (Array.isArray(groupBy) ? groupBy : [groupBy]).map((field) => ({ field: select?.[field] ?? field }));
|
|
329
|
+
const yAxisFields = Object.values(metrics).map(({ field, aggregation }) => ({
|
|
330
|
+
field: field ? select?.[field] ?? field : void 0,
|
|
331
|
+
aggregation
|
|
332
|
+
}));
|
|
333
|
+
const res = await fetch(`${BASE_URL$2()}/api/datasources/${datasourceId}/chartData`, {
|
|
334
|
+
method: "POST",
|
|
335
|
+
headers: {
|
|
336
|
+
"Content-Type": "application/json",
|
|
337
|
+
"X-User-Timezone": options.timeZone ?? readUserTimezone() ?? "UTC",
|
|
338
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
339
|
+
},
|
|
340
|
+
body: JSON.stringify({
|
|
341
|
+
options: { userLocale: "en-US" },
|
|
342
|
+
filterCriteria,
|
|
343
|
+
sortingOption,
|
|
344
|
+
xAxisFields: groupByFields,
|
|
345
|
+
yAxisFields
|
|
346
|
+
})
|
|
347
|
+
});
|
|
348
|
+
if (!res.ok) throw new Error(`Softr datasource chartData failed for "${datasourceId}": ${res.status}`);
|
|
349
|
+
const payload = await res.json();
|
|
350
|
+
const executionTimestamp = /* @__PURE__ */ new Date(payload.executionTimestamp * 1e3);
|
|
351
|
+
const aliases = {};
|
|
352
|
+
const multipleMetrics = Object.keys(metrics).length > 1;
|
|
353
|
+
for (const [alias, { field, aggregation }] of Object.entries(metrics)) if (aggregation === "COUNT") aliases[COUNT_CNT] = alias;
|
|
354
|
+
else {
|
|
355
|
+
const fieldId = field ? select?.[field] ?? field : field;
|
|
356
|
+
if (fieldId) {
|
|
357
|
+
const suffix = multipleMetrics ? `_${aggregation.toLowerCase()}` : "";
|
|
358
|
+
aliases[fieldId + suffix] = alias;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
for (const field of Array.isArray(groupBy) ? groupBy : [groupBy]) aliases[select?.[field] ?? field] = field;
|
|
362
|
+
return {
|
|
363
|
+
data: payload.data.map((item) => {
|
|
364
|
+
const row = {};
|
|
365
|
+
for (const [rawKey, alias] of Object.entries(aliases)) if (rawKey in item) row[alias] = item[rawKey];
|
|
366
|
+
return row;
|
|
367
|
+
}),
|
|
368
|
+
executionTimestamp
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function aliasFields(fields, aliases) {
|
|
372
|
+
const result = {};
|
|
373
|
+
for (const [alias, fieldId] of Object.entries(aliases)) result[alias] = fields[fieldId];
|
|
374
|
+
return result;
|
|
375
|
+
}
|
|
376
|
+
const ds = {
|
|
377
|
+
list: listRecords,
|
|
378
|
+
get: getRecord,
|
|
379
|
+
create: createRecord,
|
|
380
|
+
update: updateRecord,
|
|
381
|
+
delete: deleteRecord,
|
|
382
|
+
metric: getMetric,
|
|
383
|
+
chartData: getChartData
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/core/workflow.ts
|
|
388
|
+
const BASE_URL$1 = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
|
|
389
|
+
async function triggerWorkflow(workflowId, payload) {
|
|
390
|
+
const res = await fetch(`${BASE_URL$1()}/api/workflows/${workflowId}/trigger`, {
|
|
391
|
+
method: "POST",
|
|
392
|
+
headers: {
|
|
393
|
+
"Authorization": `Bearer ${readSessionToken()}`,
|
|
394
|
+
...payload ? { "Content-Type": "application/json" } : {}
|
|
395
|
+
},
|
|
396
|
+
...payload ? { body: JSON.stringify(payload) } : {}
|
|
397
|
+
});
|
|
398
|
+
if (!res.ok) throw new Error(`Softr workflow trigger failed: ${res.status}`);
|
|
399
|
+
}
|
|
400
|
+
const workflow = { trigger: triggerWorkflow };
|
|
401
|
+
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/core/integration.ts
|
|
404
|
+
const BASE_URL = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
|
|
405
|
+
async function integrationFetch(integrationId, input, init) {
|
|
406
|
+
const req = new Request(input, init);
|
|
407
|
+
if (req.signal.aborted) throw req.signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
408
|
+
const reqHeaders = {};
|
|
409
|
+
new Headers(req.headers).forEach((value, key) => {
|
|
410
|
+
reqHeaders[key] = value;
|
|
411
|
+
});
|
|
412
|
+
const payload = {
|
|
413
|
+
method: req.method,
|
|
414
|
+
url: req.url,
|
|
415
|
+
headers: reqHeaders
|
|
416
|
+
};
|
|
417
|
+
const method = req.method.toUpperCase();
|
|
418
|
+
if (method !== "GET" && method !== "HEAD" && req.body !== null) payload.body = await req.clone().text();
|
|
419
|
+
return fetch(`${BASE_URL()}/api/integrations/${integrationId}/proxy`, {
|
|
420
|
+
method: "POST",
|
|
421
|
+
headers: {
|
|
422
|
+
"Content-Type": "application/json",
|
|
423
|
+
"Authorization": `Bearer ${readSessionToken()}`
|
|
424
|
+
},
|
|
425
|
+
body: JSON.stringify(payload),
|
|
426
|
+
signal: req.signal
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
const integration = { fetch: integrationFetch };
|
|
430
|
+
|
|
431
|
+
//#endregion
|
|
432
|
+
export { auth, ds, integration, workflow };
|