@softr/sdk 0.0.12 → 0.0.13

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.
Files changed (47) hide show
  1. package/dist/assertions.js +68 -0
  2. package/dist/auth/config.js +27 -0
  3. package/dist/auth/context.d.ts +18 -0
  4. package/dist/auth/isomorphic.d.ts +73 -0
  5. package/dist/auth/isomorphic.js +113 -0
  6. package/dist/auth/methods/password.d.ts +22 -0
  7. package/dist/auth/methods/password.js +51 -0
  8. package/dist/auth/methods/signup.d.ts +37 -0
  9. package/dist/auth/methods/signup.js +89 -0
  10. package/dist/auth/methods/utils.d.ts +15 -0
  11. package/dist/auth/methods/utils.js +13 -0
  12. package/dist/auth/permissions.d.ts +17 -0
  13. package/dist/auth/permissions.js +13 -0
  14. package/dist/auth/platform.js +138 -0
  15. package/dist/auth/server.d.ts +17 -0
  16. package/dist/auth/server.js +17 -0
  17. package/dist/auth/session.js +167 -0
  18. package/dist/auth/user.d.ts +28 -0
  19. package/dist/client/timezone.d.ts +4 -0
  20. package/dist/client/timezone.js +11 -0
  21. package/dist/client.d.ts +1 -4
  22. package/dist/client.js +1 -9
  23. package/dist/cookies.js +47 -0
  24. package/dist/core/datasource.d.ts +21 -0
  25. package/dist/core/datasource.js +196 -0
  26. package/dist/core/integration.d.ts +7 -0
  27. package/dist/core/integration.js +32 -0
  28. package/dist/{types-n-Sir_Y2.d.ts → core/query.d.ts} +1 -129
  29. package/dist/core/query.js +528 -0
  30. package/dist/core/workflow.d.ts +7 -0
  31. package/dist/core/workflow.js +19 -0
  32. package/dist/index.d.ts +8 -172
  33. package/dist/index.js +4 -176
  34. package/dist/routes/discover.d.ts +9 -0
  35. package/dist/routes/discover.js +198 -0
  36. package/dist/routes/manifest.d.ts +17 -0
  37. package/dist/routes/manifest.js +148 -0
  38. package/dist/routes/mem-fs.js +71 -0
  39. package/dist/routes/visibility.d.ts +142 -0
  40. package/dist/routes/visibility.js +125 -0
  41. package/dist/server.d.ts +4 -113
  42. package/dist/server.js +4 -429
  43. package/dist/types.d.ts +105 -0
  44. package/dist/vite.d.ts +1 -21
  45. package/dist/vite.js +2 -405
  46. package/package.json +4 -4
  47. package/dist/session-kTqxT5_K.js +0 -891
@@ -0,0 +1,32 @@
1
+ import { readSessionToken } from "../auth/session.js";
2
+
3
+ //#region src/core/integration.ts
4
+ const BASE_URL = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
5
+ async function integrationFetch(integrationId, input, init) {
6
+ const req = new Request(input, init);
7
+ if (req.signal.aborted) throw req.signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
8
+ const reqHeaders = {};
9
+ new Headers(req.headers).forEach((value, key) => {
10
+ reqHeaders[key] = value;
11
+ });
12
+ const payload = {
13
+ method: req.method,
14
+ url: req.url,
15
+ headers: reqHeaders
16
+ };
17
+ const method = req.method.toUpperCase();
18
+ if (method !== "GET" && method !== "HEAD" && req.body !== null) payload.body = await req.clone().text();
19
+ return fetch(`${BASE_URL()}/api/integrations/${integrationId}/proxy`, {
20
+ method: "POST",
21
+ headers: {
22
+ "Content-Type": "application/json",
23
+ "Authorization": `Bearer ${readSessionToken()}`
24
+ },
25
+ body: JSON.stringify(payload),
26
+ signal: req.signal
27
+ });
28
+ }
29
+ const integration = { fetch: integrationFetch };
30
+
31
+ //#endregion
32
+ export { integration };
@@ -351,132 +351,4 @@ declare const q: {
351
351
  desc(subject: string): ConstructableOrderBy;
352
352
  };
353
353
  //#endregion
354
- //#region src/auth/user.d.ts
355
- /**
356
- * Declare this interface in your app to narrow every group id the SDK takes and
357
- * returns. Without a declaration, a group id is a plain `string`.
358
- *
359
- * @example
360
- * declare module "@softr/sdk" {
361
- * interface SoftrUserGroups {
362
- * ids:
363
- * | "b1f2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
364
- * | "f9e8d7c6-5b4a-4938-8271-605f4e3d2c1b"
365
- * }
366
- * }
367
- */
368
- interface SoftrUserGroups {}
369
- /** A Softr user group id, narrowed to your own ids if you declare {@link SoftrUserGroups}. */
370
- type SoftrUserGroupId = SoftrUserGroups extends {
371
- ids: infer Id extends string;
372
- } ? Id : string;
373
- /** The signed-in visitor. */
374
- type User = {
375
- id: string;
376
- email: string;
377
- name: string;
378
- userGroupIds: Array<SoftrUserGroupId>;
379
- };
380
- //#endregion
381
- //#region src/types.d.ts
382
- interface SoftrUser {
383
- id: string;
384
- email: string;
385
- name: string;
386
- userGroupIds: Array<SoftrUserGroupId>;
387
- }
388
- interface DatasourcePermissions {
389
- read: boolean;
390
- create: boolean;
391
- update: boolean;
392
- delete: boolean;
393
- }
394
- interface SoftrPermissions {
395
- datasources: Record<string, DatasourcePermissions>;
396
- workflows: Record<string, boolean>;
397
- }
398
- interface SoftrMe {
399
- user: SoftrUser | null;
400
- permissions: SoftrPermissions;
401
- }
402
- type GetByIdOptions = {
403
- id: string;
404
- where?: never;
405
- timeZone?: string;
406
- };
407
- type GetByWhereOptions = {
408
- id?: never;
409
- where: AnyConstructable;
410
- timeZone?: string;
411
- };
412
- type GetOptions = GetByIdOptions | GetByWhereOptions;
413
- interface ListOptions {
414
- /**
415
- * Maps human-readable aliases to Softr field IDs.
416
- * When provided, returned fields are keyed by alias instead of raw field ID.
417
- */
418
- select?: Record<string, string>;
419
- where?: AnyConstructable;
420
- orderBy?: ConstructableOrderBy | ConstructableOrderBy[];
421
- /**
422
- * Number of records to return per page. Defaults to 20, max 100.
423
- */
424
- limit?: number;
425
- /**
426
- * Offset to start from. Pass the `nextOffset` from a previous result to paginate.
427
- * Omit or pass `null` to start from the beginning.
428
- */
429
- offset?: number | null;
430
- /** Override the timezone for this request. */
431
- timeZone?: string;
432
- }
433
- interface ListResult<T = SoftrRecord> {
434
- records: T[];
435
- total: number;
436
- /** Offset to pass as `offset` in the next call, or `null` when there are no more pages. */
437
- nextOffset: number | null;
438
- }
439
- interface SoftrRecord {
440
- id: string;
441
- fields: Record<string, unknown>;
442
- }
443
- type AggregationFunction = 'SUM' | 'AVG' | 'MAX' | 'MIN' | 'COUNT' | 'DISTINCT';
444
- interface MetricOptions {
445
- select?: Record<string, string>;
446
- where?: AnyConstructable;
447
- aggregation: AggregationFunction;
448
- /** Field alias (resolved via select) or raw field ID. Not required for COUNT. */
449
- field?: string;
450
- /** Override the timezone for this request. */
451
- timeZone?: string;
452
- }
453
- interface MetricResult {
454
- value: number | null;
455
- executionTimestamp: Date;
456
- }
457
- interface ChartDataOptions {
458
- select?: Record<string, string>;
459
- where?: AnyConstructable;
460
- /** Field alias (resolved via select) or raw field ID. */
461
- groupBy: string | string[];
462
- metrics: Record<string, {
463
- field?: string;
464
- aggregation: AggregationFunction;
465
- }>;
466
- orderBy?: ConstructableOrderBy;
467
- /** Override the timezone for this request. */
468
- timeZone?: string;
469
- }
470
- interface ChartDataResult {
471
- data: Record<string, unknown>[];
472
- executionTimestamp: Date;
473
- }
474
- interface CreateOptions {
475
- fields: Record<string, unknown>;
476
- }
477
- interface UpdateOptions {
478
- id: string;
479
- fields: Record<string, unknown>;
480
- }
481
- //#endregion
482
- export { SoftrUserGroups as _, DatasourcePermissions as a, ListResult as c, SoftrMe as d, SoftrPermissions as f, SoftrUserGroupId as g, UpdateOptions as h, CreateOptions as i, MetricOptions as l, SoftrUser as m, ChartDataOptions as n, GetOptions as o, SoftrRecord as p, ChartDataResult as r, ListOptions as s, AggregationFunction as t, MetricResult as u, User as v, q as y };
354
+ export { AnyConstructable, ConstructableOrderBy, q };
@@ -0,0 +1,528 @@
1
+ //#region src/core/query.ts
2
+ const INTERNAL_KIND = Symbol("KIND");
3
+ /**
4
+ * Query builder for filter queries. This exist to alleviate the (LLM?) mental overhead. API filter schema is a bit
5
+ * verbose and confusing, even when dealing with very basic queries. So to fall into the pit of success, aim here
6
+ * is to simplify filtering as much as possible.
7
+ *
8
+ * @example
9
+ * single filter
10
+ * ```tsx
11
+ * const query = q.text("title").contains("hello");
12
+ *
13
+ * const json = buildFilterCriteria(query);
14
+ * // result
15
+ * {
16
+ * "filterCriteria": {
17
+ * "filterConditionGroup": {
18
+ * "logicalOperator": "AND"
19
+ * "filterGroups": [{
20
+ * "logicalOperator": "AND",
21
+ * "filters": [{
22
+ * "subject": "title",
23
+ * "type": "TEXT",
24
+ * "operator": "CONTAINS",
25
+ * "value": "hello"
26
+ * }],
27
+ * }]
28
+ * }
29
+ * }
30
+ * }
31
+ *
32
+ * ```
33
+ *
34
+ * @example
35
+ * combining multiple filters
36
+ * ```tsx
37
+ * const query = q.and(
38
+ * q.text("title").contains("hello"),
39
+ * q.number("views").is(100),
40
+ * q.or(
41
+ * q.text("author").is("John"),
42
+ * q.boolean("isPublished").is(true)
43
+ * )
44
+ * );
45
+ * ```
46
+ */
47
+ const q = {
48
+ select(mapping) {
49
+ return mapping;
50
+ },
51
+ and(...filters) {
52
+ return {
53
+ logicalOperator: "AND",
54
+ filters,
55
+ [INTERNAL_KIND]: "LOGICAL_GROUP"
56
+ };
57
+ },
58
+ or(...filters) {
59
+ return {
60
+ logicalOperator: "OR",
61
+ filters,
62
+ [INTERNAL_KIND]: "LOGICAL_GROUP"
63
+ };
64
+ },
65
+ text(subject) {
66
+ const filter = {
67
+ subject,
68
+ type: "TEXT",
69
+ [INTERNAL_KIND]: "FILTER"
70
+ };
71
+ return {
72
+ is(value) {
73
+ return {
74
+ ...filter,
75
+ operator: "IS",
76
+ value
77
+ };
78
+ },
79
+ isNot(value) {
80
+ return {
81
+ ...filter,
82
+ operator: "IS_NOT",
83
+ value
84
+ };
85
+ },
86
+ contains(value) {
87
+ return {
88
+ ...filter,
89
+ operator: "CONTAINS",
90
+ value
91
+ };
92
+ },
93
+ isOneOf(value) {
94
+ return {
95
+ ...filter,
96
+ operator: "IS_ONE_OF",
97
+ value
98
+ };
99
+ },
100
+ isNoneOf(value) {
101
+ return {
102
+ ...filter,
103
+ operator: "IS_NONE_OF",
104
+ value
105
+ };
106
+ },
107
+ startsWith(value) {
108
+ return {
109
+ ...filter,
110
+ operator: "STARTS_WITH",
111
+ value
112
+ };
113
+ },
114
+ endsWith(value) {
115
+ return {
116
+ ...filter,
117
+ operator: "ENDS_WITH",
118
+ value
119
+ };
120
+ },
121
+ hasAllOf(value) {
122
+ return {
123
+ ...filter,
124
+ operator: "HAS_ALL_OF",
125
+ value
126
+ };
127
+ },
128
+ isEmpty() {
129
+ return {
130
+ ...filter,
131
+ operator: "IS_EMPTY"
132
+ };
133
+ },
134
+ isNotEmpty() {
135
+ return {
136
+ ...filter,
137
+ operator: "IS_NOT_EMPTY"
138
+ };
139
+ }
140
+ };
141
+ },
142
+ boolean(subject) {
143
+ const filter = {
144
+ subject,
145
+ type: "BOOLEAN",
146
+ [INTERNAL_KIND]: "FILTER"
147
+ };
148
+ return {
149
+ is(value) {
150
+ return {
151
+ ...filter,
152
+ operator: "IS",
153
+ value
154
+ };
155
+ },
156
+ isNot(value) {
157
+ return {
158
+ ...filter,
159
+ operator: "IS_NOT",
160
+ value
161
+ };
162
+ },
163
+ isEmpty() {
164
+ return {
165
+ ...filter,
166
+ operator: "IS_EMPTY"
167
+ };
168
+ },
169
+ isNotEmpty() {
170
+ return {
171
+ ...filter,
172
+ operator: "IS_NOT_EMPTY"
173
+ };
174
+ }
175
+ };
176
+ },
177
+ number(subject) {
178
+ const filter = {
179
+ subject,
180
+ type: "NUMERIC",
181
+ [INTERNAL_KIND]: "FILTER"
182
+ };
183
+ return {
184
+ is(value) {
185
+ return {
186
+ ...filter,
187
+ operator: "IS",
188
+ value: value.toString()
189
+ };
190
+ },
191
+ isNot(value) {
192
+ return {
193
+ ...filter,
194
+ operator: "IS_NOT",
195
+ value: value.toString()
196
+ };
197
+ },
198
+ gt(value) {
199
+ return {
200
+ ...filter,
201
+ operator: "GT",
202
+ value: value.toString()
203
+ };
204
+ },
205
+ gte(value) {
206
+ return {
207
+ ...filter,
208
+ operator: "GTE",
209
+ value: value.toString()
210
+ };
211
+ },
212
+ lt(value) {
213
+ return {
214
+ ...filter,
215
+ operator: "LT",
216
+ value: value.toString()
217
+ };
218
+ },
219
+ lte(value) {
220
+ return {
221
+ ...filter,
222
+ operator: "LTE",
223
+ value: value.toString()
224
+ };
225
+ },
226
+ between(start, end) {
227
+ return {
228
+ ...filter,
229
+ operator: "BETWEEN",
230
+ value: [start.toString(), end.toString()]
231
+ };
232
+ },
233
+ isEmpty() {
234
+ return {
235
+ ...filter,
236
+ operator: "IS_EMPTY"
237
+ };
238
+ },
239
+ isNotEmpty() {
240
+ return {
241
+ ...filter,
242
+ operator: "IS_NOT_EMPTY"
243
+ };
244
+ }
245
+ };
246
+ },
247
+ array(subject) {
248
+ const filter = {
249
+ subject,
250
+ type: "ARRAY",
251
+ [INTERNAL_KIND]: "FILTER"
252
+ };
253
+ return {
254
+ is(value) {
255
+ return {
256
+ ...filter,
257
+ operator: "IS",
258
+ value
259
+ };
260
+ },
261
+ isOneOf(value) {
262
+ return {
263
+ ...filter,
264
+ operator: "IS_ONE_OF",
265
+ value
266
+ };
267
+ },
268
+ isNoneOf(value) {
269
+ return {
270
+ ...filter,
271
+ operator: "IS_NONE_OF",
272
+ value
273
+ };
274
+ },
275
+ hasAllOf(value) {
276
+ return {
277
+ ...filter,
278
+ operator: "HAS_ALL_OF",
279
+ value
280
+ };
281
+ },
282
+ isEmpty() {
283
+ return {
284
+ ...filter,
285
+ operator: "IS_EMPTY"
286
+ };
287
+ },
288
+ isNotEmpty() {
289
+ return {
290
+ ...filter,
291
+ operator: "IS_NOT_EMPTY"
292
+ };
293
+ }
294
+ };
295
+ },
296
+ date(subject) {
297
+ const filter = {
298
+ subject,
299
+ type: "DATE",
300
+ [INTERNAL_KIND]: "FILTER"
301
+ };
302
+ return {
303
+ is(value) {
304
+ return {
305
+ ...filter,
306
+ operator: "IS",
307
+ value
308
+ };
309
+ },
310
+ isNot(value) {
311
+ return {
312
+ ...filter,
313
+ operator: "IS_NOT",
314
+ value
315
+ };
316
+ },
317
+ gt(value) {
318
+ return {
319
+ ...filter,
320
+ operator: "GT",
321
+ value
322
+ };
323
+ },
324
+ gte(value) {
325
+ return {
326
+ ...filter,
327
+ operator: "GTE",
328
+ value
329
+ };
330
+ },
331
+ lt(value) {
332
+ return {
333
+ ...filter,
334
+ operator: "LT",
335
+ value
336
+ };
337
+ },
338
+ lte(value) {
339
+ return {
340
+ ...filter,
341
+ operator: "LTE",
342
+ value
343
+ };
344
+ },
345
+ between(start, end) {
346
+ return {
347
+ ...filter,
348
+ operator: "BETWEEN",
349
+ value: [start, end]
350
+ };
351
+ },
352
+ isNotBetween(start, end) {
353
+ return {
354
+ ...filter,
355
+ operator: "IS_NOT_BETWEEN",
356
+ value: [start, end]
357
+ };
358
+ },
359
+ isEmpty() {
360
+ return {
361
+ ...filter,
362
+ operator: "IS_EMPTY"
363
+ };
364
+ },
365
+ isNotEmpty() {
366
+ return {
367
+ ...filter,
368
+ operator: "IS_NOT_EMPTY"
369
+ };
370
+ }
371
+ };
372
+ },
373
+ asc(subject) {
374
+ return {
375
+ sortingField: subject,
376
+ sortType: "ASC",
377
+ [INTERNAL_KIND]: "ORDER_BY"
378
+ };
379
+ },
380
+ desc(subject) {
381
+ return {
382
+ sortingField: subject,
383
+ sortType: "DESC",
384
+ [INTERNAL_KIND]: "ORDER_BY"
385
+ };
386
+ }
387
+ };
388
+ /**
389
+ * Converts filter utility conditions to a format our backend supports
390
+ *
391
+ * @example
392
+ * ```tsx
393
+ * const query = q.text("title").contains("hello");
394
+ *
395
+ * const json = buildFilterCriteria(query);
396
+ * // result
397
+ * {
398
+ * "filterCriteria": {
399
+ * "filterConditionGroup": {
400
+ * "logicalOperator": "AND"
401
+ * "filterGroups": [{
402
+ * "logicalOperator": "AND",
403
+ * "filters": [{
404
+ * "subject": "title",
405
+ * "type": "TEXT",
406
+ * "operator": "CONTAINS",
407
+ * "value": "hello"
408
+ * }],
409
+ * }]
410
+ * }
411
+ * }
412
+ * }
413
+ *
414
+ * ```
415
+ */
416
+ function buildFilterCriteria(input) {
417
+ if (!(INTERNAL_KIND in input)) throw new Error("Filters cannot be constructed manually. Use the 'q' helper.");
418
+ if (isFilter(input)) return { filterConditionGroup: {
419
+ logicalOperator: "AND",
420
+ filterGroups: [{
421
+ logicalOperator: "AND",
422
+ filters: [stripInternalKind(input)]
423
+ }]
424
+ } };
425
+ if (isFilterGroup(input)) {
426
+ if (input.filters.length === 0) return { filterConditionGroup: {
427
+ logicalOperator: input.logicalOperator,
428
+ filterGroups: []
429
+ } };
430
+ return { filterConditionGroup: {
431
+ logicalOperator: input.logicalOperator,
432
+ filterGroups: input.filters.map((inner) => {
433
+ if (isFilter(inner)) return {
434
+ logicalOperator: "AND",
435
+ filters: [stripInternalKind(inner)]
436
+ };
437
+ if (!inner.filters.every(isFilter)) throw new Error("Cannot nest filter groups more than three levels deep.");
438
+ return {
439
+ logicalOperator: inner.logicalOperator,
440
+ filters: inner.filters.map(stripInternalKind)
441
+ };
442
+ })
443
+ } };
444
+ }
445
+ throw new Error("Unknown filter kind: " + input[INTERNAL_KIND]);
446
+ }
447
+ /**
448
+ * Converts order-by utility conditions to a format our backend supports
449
+ *
450
+ * @example
451
+ * single orderBy
452
+ * ```tsx
453
+ * const orderBy = buildOrderBy(q.asc("title"));
454
+ * // result: [{ sortingField: "title", sortType: "ASC" }]
455
+ * ```
456
+ *
457
+ * @example
458
+ * multiple orderBys
459
+ * ```tsx
460
+ * const orderBy = buildOrderBy([q.desc("createdAt"), q.asc("title")]);
461
+ * // result: [
462
+ * // { sortingField: "createdAt", sortType: "DESC" },
463
+ * // { sortingField: "title", sortType: "ASC" }
464
+ * // ]
465
+ * ```
466
+ */
467
+ function buildOrderBy(input) {
468
+ const orderBys = Array.isArray(input) ? input : [input];
469
+ if (!orderBys.every((ob) => ob[INTERNAL_KIND] === "ORDER_BY")) throw new Error("orderBy conditions cannot be constructed manually. Use the 'q' helper.");
470
+ return orderBys.map((orderBy) => ({
471
+ sortingField: orderBy.sortingField,
472
+ sortType: orderBy.sortType
473
+ }));
474
+ }
475
+ function dealiasOrderBy(orderbys, aliases) {
476
+ return orderbys.map((orderBy) => {
477
+ const subject = aliases[orderBy.sortingField];
478
+ if (!subject) throw new Error(`Could not find an alias for subject "${orderBy.sortingField}"`);
479
+ return {
480
+ ...orderBy,
481
+ sortingField: subject
482
+ };
483
+ });
484
+ }
485
+ /**
486
+ * Replaces filter subjects with their aliased values.
487
+ *
488
+ * Throws an error if any filter subject does not have a corresponding alias in the provided mapping.
489
+ *
490
+ * @example
491
+ * ```tsx
492
+ * const criteria = buildFilterCriteria(q.text("name").contains("John"));
493
+ * const aliases = { name: "abcxy123" };
494
+ * const dealiased = dealiasFilterCriteria(criteria, aliases);
495
+ * // Result: filter subject is now "abcxyz123" instead of "name"
496
+ * ```
497
+ */
498
+ function dealiasFilterCriteria(criteria, aliases) {
499
+ if (!criteria.filterConditionGroup) return criteria;
500
+ return { filterConditionGroup: {
501
+ ...criteria.filterConditionGroup,
502
+ filterGroups: criteria.filterConditionGroup.filterGroups.map((group) => ({
503
+ ...group,
504
+ filters: group.filters.map(dealiasFilter)
505
+ }))
506
+ } };
507
+ function dealiasFilter(filter) {
508
+ const subject = aliases[filter.subject];
509
+ if (!subject) throw new Error(`Could not find an alias for subject "${subject}"`);
510
+ return {
511
+ ...filter,
512
+ subject
513
+ };
514
+ }
515
+ }
516
+ function stripInternalKind(item) {
517
+ const { [INTERNAL_KIND]: _,...rest } = item;
518
+ return rest;
519
+ }
520
+ function isFilterGroup(item) {
521
+ return item[INTERNAL_KIND] === "LOGICAL_GROUP";
522
+ }
523
+ function isFilter(item) {
524
+ return item[INTERNAL_KIND] === "FILTER";
525
+ }
526
+
527
+ //#endregion
528
+ export { buildFilterCriteria, buildOrderBy, dealiasFilterCriteria, dealiasOrderBy, q };
@@ -0,0 +1,7 @@
1
+ //#region src/core/workflow.d.ts
2
+ declare function triggerWorkflow(workflowId: string, payload?: Record<string, unknown>): Promise<void>;
3
+ declare const workflow: {
4
+ trigger: typeof triggerWorkflow;
5
+ };
6
+ //#endregion
7
+ export { workflow };
@@ -0,0 +1,19 @@
1
+ import { readSessionToken } from "../auth/session.js";
2
+
3
+ //#region src/core/workflow.ts
4
+ const BASE_URL = () => (import.meta.env.VITE_SOFTR_BASE_URL ?? "").replace(/\/$/, "");
5
+ async function triggerWorkflow(workflowId, payload) {
6
+ const res = await fetch(`${BASE_URL()}/api/workflows/${workflowId}/trigger`, {
7
+ method: "POST",
8
+ headers: {
9
+ "Authorization": `Bearer ${readSessionToken()}`,
10
+ ...payload ? { "Content-Type": "application/json" } : {}
11
+ },
12
+ ...payload ? { body: JSON.stringify(payload) } : {}
13
+ });
14
+ if (!res.ok) throw new Error(`Softr workflow trigger failed: ${res.status}`);
15
+ }
16
+ const workflow = { trigger: triggerWorkflow };
17
+
18
+ //#endregion
19
+ export { workflow };