@softr/sdk 0.0.11 → 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.
- package/dist/assertions.js +68 -0
- package/dist/auth/config.js +27 -0
- package/dist/auth/context.d.ts +18 -0
- package/dist/auth/isomorphic.d.ts +73 -0
- package/dist/auth/isomorphic.js +113 -0
- package/dist/auth/methods/password.d.ts +22 -0
- package/dist/auth/methods/password.js +51 -0
- package/dist/auth/methods/signup.d.ts +37 -0
- package/dist/auth/methods/signup.js +89 -0
- package/dist/auth/methods/utils.d.ts +15 -0
- package/dist/auth/methods/utils.js +13 -0
- package/dist/auth/permissions.d.ts +17 -0
- package/dist/auth/permissions.js +13 -0
- package/dist/auth/platform.js +138 -0
- package/dist/auth/server.d.ts +17 -0
- package/dist/auth/server.js +17 -0
- package/dist/auth/session.js +167 -0
- package/dist/{user-D23hwTsf.d.ts → auth/user.d.ts} +1 -1
- package/dist/client/timezone.d.ts +4 -0
- package/dist/client/timezone.js +11 -0
- package/dist/client.d.ts +1 -4
- package/dist/client.js +1 -9
- package/dist/cookies.js +47 -0
- package/dist/core/datasource.d.ts +21 -0
- package/dist/core/datasource.js +196 -0
- package/dist/core/integration.d.ts +7 -0
- package/dist/core/integration.js +32 -0
- package/dist/core/query.d.ts +354 -0
- package/dist/core/query.js +528 -0
- package/dist/core/workflow.d.ts +7 -0
- package/dist/core/workflow.js +19 -0
- package/dist/index.d.ts +8 -685
- package/dist/index.js +4 -1019
- package/dist/routes/discover.d.ts +9 -0
- package/dist/routes/discover.js +198 -0
- package/dist/routes/manifest.d.ts +17 -0
- package/dist/routes/manifest.js +148 -0
- package/dist/routes/mem-fs.js +71 -0
- package/dist/routes/visibility.d.ts +142 -0
- package/dist/routes/visibility.js +125 -0
- package/dist/server.d.ts +5 -84
- package/dist/server.js +5 -194
- package/dist/types.d.ts +105 -0
- package/dist/vite.d.ts +1 -21
- package/dist/vite.js +2 -405
- package/package.json +4 -4
- package/dist/session-GUEI96C8.js +0 -360
package/dist/index.d.ts
CHANGED
|
@@ -1,685 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type
|
|
9
|
-
interface Filter {
|
|
10
|
-
subject: string;
|
|
11
|
-
operator: FilterOperator;
|
|
12
|
-
value?: unknown;
|
|
13
|
-
type: ConditionFieldType;
|
|
14
|
-
}
|
|
15
|
-
type ConstructableFilter = Filter & {
|
|
16
|
-
[INTERNAL_KIND]: "FILTER";
|
|
17
|
-
};
|
|
18
|
-
type ConstructableFilterGroup = {
|
|
19
|
-
logicalOperator: LogicalOperator;
|
|
20
|
-
filters: Array<ConstructableFilter | ConstructableFilterGroup>;
|
|
21
|
-
[INTERNAL_KIND]: "LOGICAL_GROUP";
|
|
22
|
-
};
|
|
23
|
-
interface SortingOptionItem {
|
|
24
|
-
sortingField: string;
|
|
25
|
-
sortType: "ASC" | "DESC";
|
|
26
|
-
}
|
|
27
|
-
type ConstructableOrderBy = SortingOptionItem & {
|
|
28
|
-
[INTERNAL_KIND]: "ORDER_BY";
|
|
29
|
-
};
|
|
30
|
-
type AnyConstructable = ConstructableFilter | ConstructableFilterGroup;
|
|
31
|
-
declare const INTERNAL_KIND: unique symbol;
|
|
32
|
-
/**
|
|
33
|
-
* Query builder for filter queries. This exist to alleviate the (LLM?) mental overhead. API filter schema is a bit
|
|
34
|
-
* verbose and confusing, even when dealing with very basic queries. So to fall into the pit of success, aim here
|
|
35
|
-
* is to simplify filtering as much as possible.
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* single filter
|
|
39
|
-
* ```tsx
|
|
40
|
-
* const query = q.text("title").contains("hello");
|
|
41
|
-
*
|
|
42
|
-
* const json = buildFilterCriteria(query);
|
|
43
|
-
* // result
|
|
44
|
-
* {
|
|
45
|
-
* "filterCriteria": {
|
|
46
|
-
* "filterConditionGroup": {
|
|
47
|
-
* "logicalOperator": "AND"
|
|
48
|
-
* "filterGroups": [{
|
|
49
|
-
* "logicalOperator": "AND",
|
|
50
|
-
* "filters": [{
|
|
51
|
-
* "subject": "title",
|
|
52
|
-
* "type": "TEXT",
|
|
53
|
-
* "operator": "CONTAINS",
|
|
54
|
-
* "value": "hello"
|
|
55
|
-
* }],
|
|
56
|
-
* }]
|
|
57
|
-
* }
|
|
58
|
-
* }
|
|
59
|
-
* }
|
|
60
|
-
*
|
|
61
|
-
* ```
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* combining multiple filters
|
|
65
|
-
* ```tsx
|
|
66
|
-
* const query = q.and(
|
|
67
|
-
* q.text("title").contains("hello"),
|
|
68
|
-
* q.number("views").is(100),
|
|
69
|
-
* q.or(
|
|
70
|
-
* q.text("author").is("John"),
|
|
71
|
-
* q.boolean("isPublished").is(true)
|
|
72
|
-
* )
|
|
73
|
-
* );
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
declare const q: {
|
|
77
|
-
select<T extends Record<string, string>>(mapping: T): T;
|
|
78
|
-
and(...filters: AnyConstructable[]): ConstructableFilterGroup;
|
|
79
|
-
or(...filters: AnyConstructable[]): ConstructableFilterGroup;
|
|
80
|
-
text(subject: string): {
|
|
81
|
-
is(value: string): {
|
|
82
|
-
operator: "IS";
|
|
83
|
-
value: string;
|
|
84
|
-
subject: string;
|
|
85
|
-
type: "TEXT";
|
|
86
|
-
[INTERNAL_KIND]: "FILTER";
|
|
87
|
-
};
|
|
88
|
-
isNot(value: string): {
|
|
89
|
-
operator: "IS_NOT";
|
|
90
|
-
value: string;
|
|
91
|
-
subject: string;
|
|
92
|
-
type: "TEXT";
|
|
93
|
-
[INTERNAL_KIND]: "FILTER";
|
|
94
|
-
};
|
|
95
|
-
contains(value: string): {
|
|
96
|
-
operator: "CONTAINS";
|
|
97
|
-
value: string;
|
|
98
|
-
subject: string;
|
|
99
|
-
type: "TEXT";
|
|
100
|
-
[INTERNAL_KIND]: "FILTER";
|
|
101
|
-
};
|
|
102
|
-
isOneOf(value: string[]): {
|
|
103
|
-
operator: "IS_ONE_OF";
|
|
104
|
-
value: string[];
|
|
105
|
-
subject: string;
|
|
106
|
-
type: "TEXT";
|
|
107
|
-
[INTERNAL_KIND]: "FILTER";
|
|
108
|
-
};
|
|
109
|
-
isNoneOf(value: string[]): {
|
|
110
|
-
operator: "IS_NONE_OF";
|
|
111
|
-
value: string[];
|
|
112
|
-
subject: string;
|
|
113
|
-
type: "TEXT";
|
|
114
|
-
[INTERNAL_KIND]: "FILTER";
|
|
115
|
-
};
|
|
116
|
-
startsWith(value: string): {
|
|
117
|
-
operator: "STARTS_WITH";
|
|
118
|
-
value: string;
|
|
119
|
-
subject: string;
|
|
120
|
-
type: "TEXT";
|
|
121
|
-
[INTERNAL_KIND]: "FILTER";
|
|
122
|
-
};
|
|
123
|
-
endsWith(value: string): {
|
|
124
|
-
operator: "ENDS_WITH";
|
|
125
|
-
value: string;
|
|
126
|
-
subject: string;
|
|
127
|
-
type: "TEXT";
|
|
128
|
-
[INTERNAL_KIND]: "FILTER";
|
|
129
|
-
};
|
|
130
|
-
hasAllOf(value: string[]): {
|
|
131
|
-
operator: "HAS_ALL_OF";
|
|
132
|
-
value: string[];
|
|
133
|
-
subject: string;
|
|
134
|
-
type: "TEXT";
|
|
135
|
-
[INTERNAL_KIND]: "FILTER";
|
|
136
|
-
};
|
|
137
|
-
isEmpty(): {
|
|
138
|
-
operator: "IS_EMPTY";
|
|
139
|
-
subject: string;
|
|
140
|
-
type: "TEXT";
|
|
141
|
-
[INTERNAL_KIND]: "FILTER";
|
|
142
|
-
};
|
|
143
|
-
isNotEmpty(): {
|
|
144
|
-
operator: "IS_NOT_EMPTY";
|
|
145
|
-
subject: string;
|
|
146
|
-
type: "TEXT";
|
|
147
|
-
[INTERNAL_KIND]: "FILTER";
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
boolean(subject: string): {
|
|
151
|
-
is(value: boolean): {
|
|
152
|
-
operator: "IS";
|
|
153
|
-
value: boolean;
|
|
154
|
-
subject: string;
|
|
155
|
-
type: "BOOLEAN";
|
|
156
|
-
[INTERNAL_KIND]: "FILTER";
|
|
157
|
-
};
|
|
158
|
-
isNot(value: boolean): {
|
|
159
|
-
operator: "IS_NOT";
|
|
160
|
-
value: boolean;
|
|
161
|
-
subject: string;
|
|
162
|
-
type: "BOOLEAN";
|
|
163
|
-
[INTERNAL_KIND]: "FILTER";
|
|
164
|
-
};
|
|
165
|
-
isEmpty(): {
|
|
166
|
-
operator: "IS_EMPTY";
|
|
167
|
-
subject: string;
|
|
168
|
-
type: "BOOLEAN";
|
|
169
|
-
[INTERNAL_KIND]: "FILTER";
|
|
170
|
-
};
|
|
171
|
-
isNotEmpty(): {
|
|
172
|
-
operator: "IS_NOT_EMPTY";
|
|
173
|
-
subject: string;
|
|
174
|
-
type: "BOOLEAN";
|
|
175
|
-
[INTERNAL_KIND]: "FILTER";
|
|
176
|
-
};
|
|
177
|
-
};
|
|
178
|
-
number(subject: string): {
|
|
179
|
-
is(value: number): {
|
|
180
|
-
operator: "IS";
|
|
181
|
-
value: string;
|
|
182
|
-
subject: string;
|
|
183
|
-
type: "NUMERIC";
|
|
184
|
-
[INTERNAL_KIND]: "FILTER";
|
|
185
|
-
};
|
|
186
|
-
isNot(value: number): {
|
|
187
|
-
operator: "IS_NOT";
|
|
188
|
-
value: string;
|
|
189
|
-
subject: string;
|
|
190
|
-
type: "NUMERIC";
|
|
191
|
-
[INTERNAL_KIND]: "FILTER";
|
|
192
|
-
};
|
|
193
|
-
gt(value: number): {
|
|
194
|
-
operator: "GT";
|
|
195
|
-
value: string;
|
|
196
|
-
subject: string;
|
|
197
|
-
type: "NUMERIC";
|
|
198
|
-
[INTERNAL_KIND]: "FILTER";
|
|
199
|
-
};
|
|
200
|
-
gte(value: number): {
|
|
201
|
-
operator: "GTE";
|
|
202
|
-
value: string;
|
|
203
|
-
subject: string;
|
|
204
|
-
type: "NUMERIC";
|
|
205
|
-
[INTERNAL_KIND]: "FILTER";
|
|
206
|
-
};
|
|
207
|
-
lt(value: number): {
|
|
208
|
-
operator: "LT";
|
|
209
|
-
value: string;
|
|
210
|
-
subject: string;
|
|
211
|
-
type: "NUMERIC";
|
|
212
|
-
[INTERNAL_KIND]: "FILTER";
|
|
213
|
-
};
|
|
214
|
-
lte(value: number): {
|
|
215
|
-
operator: "LTE";
|
|
216
|
-
value: string;
|
|
217
|
-
subject: string;
|
|
218
|
-
type: "NUMERIC";
|
|
219
|
-
[INTERNAL_KIND]: "FILTER";
|
|
220
|
-
};
|
|
221
|
-
between(start: number, end: number): {
|
|
222
|
-
operator: "BETWEEN";
|
|
223
|
-
value: string[];
|
|
224
|
-
subject: string;
|
|
225
|
-
type: "NUMERIC";
|
|
226
|
-
[INTERNAL_KIND]: "FILTER";
|
|
227
|
-
};
|
|
228
|
-
isEmpty(): {
|
|
229
|
-
operator: "IS_EMPTY";
|
|
230
|
-
subject: string;
|
|
231
|
-
type: "NUMERIC";
|
|
232
|
-
[INTERNAL_KIND]: "FILTER";
|
|
233
|
-
};
|
|
234
|
-
isNotEmpty(): {
|
|
235
|
-
operator: "IS_NOT_EMPTY";
|
|
236
|
-
subject: string;
|
|
237
|
-
type: "NUMERIC";
|
|
238
|
-
[INTERNAL_KIND]: "FILTER";
|
|
239
|
-
};
|
|
240
|
-
};
|
|
241
|
-
array(subject: string): {
|
|
242
|
-
is(value: string[]): {
|
|
243
|
-
operator: "IS";
|
|
244
|
-
value: string[];
|
|
245
|
-
subject: string;
|
|
246
|
-
type: "ARRAY";
|
|
247
|
-
[INTERNAL_KIND]: "FILTER";
|
|
248
|
-
};
|
|
249
|
-
isOneOf(value: string[]): {
|
|
250
|
-
operator: "IS_ONE_OF";
|
|
251
|
-
value: string[];
|
|
252
|
-
subject: string;
|
|
253
|
-
type: "ARRAY";
|
|
254
|
-
[INTERNAL_KIND]: "FILTER";
|
|
255
|
-
};
|
|
256
|
-
isNoneOf(value: string[]): {
|
|
257
|
-
operator: "IS_NONE_OF";
|
|
258
|
-
value: string[];
|
|
259
|
-
subject: string;
|
|
260
|
-
type: "ARRAY";
|
|
261
|
-
[INTERNAL_KIND]: "FILTER";
|
|
262
|
-
};
|
|
263
|
-
hasAllOf(value: string[]): {
|
|
264
|
-
operator: "HAS_ALL_OF";
|
|
265
|
-
value: string[];
|
|
266
|
-
subject: string;
|
|
267
|
-
type: "ARRAY";
|
|
268
|
-
[INTERNAL_KIND]: "FILTER";
|
|
269
|
-
};
|
|
270
|
-
isEmpty(): {
|
|
271
|
-
operator: "IS_EMPTY";
|
|
272
|
-
subject: string;
|
|
273
|
-
type: "ARRAY";
|
|
274
|
-
[INTERNAL_KIND]: "FILTER";
|
|
275
|
-
};
|
|
276
|
-
isNotEmpty(): {
|
|
277
|
-
operator: "IS_NOT_EMPTY";
|
|
278
|
-
subject: string;
|
|
279
|
-
type: "ARRAY";
|
|
280
|
-
[INTERNAL_KIND]: "FILTER";
|
|
281
|
-
};
|
|
282
|
-
};
|
|
283
|
-
date(subject: string): {
|
|
284
|
-
is(value: string): {
|
|
285
|
-
operator: "IS";
|
|
286
|
-
value: string;
|
|
287
|
-
subject: string;
|
|
288
|
-
type: "DATE";
|
|
289
|
-
[INTERNAL_KIND]: "FILTER";
|
|
290
|
-
};
|
|
291
|
-
isNot(value: string): {
|
|
292
|
-
operator: "IS_NOT";
|
|
293
|
-
value: string;
|
|
294
|
-
subject: string;
|
|
295
|
-
type: "DATE";
|
|
296
|
-
[INTERNAL_KIND]: "FILTER";
|
|
297
|
-
};
|
|
298
|
-
gt(value: string): {
|
|
299
|
-
operator: "GT";
|
|
300
|
-
value: string;
|
|
301
|
-
subject: string;
|
|
302
|
-
type: "DATE";
|
|
303
|
-
[INTERNAL_KIND]: "FILTER";
|
|
304
|
-
};
|
|
305
|
-
gte(value: string): {
|
|
306
|
-
operator: "GTE";
|
|
307
|
-
value: string;
|
|
308
|
-
subject: string;
|
|
309
|
-
type: "DATE";
|
|
310
|
-
[INTERNAL_KIND]: "FILTER";
|
|
311
|
-
};
|
|
312
|
-
lt(value: string): {
|
|
313
|
-
operator: "LT";
|
|
314
|
-
value: string;
|
|
315
|
-
subject: string;
|
|
316
|
-
type: "DATE";
|
|
317
|
-
[INTERNAL_KIND]: "FILTER";
|
|
318
|
-
};
|
|
319
|
-
lte(value: string): {
|
|
320
|
-
operator: "LTE";
|
|
321
|
-
value: string;
|
|
322
|
-
subject: string;
|
|
323
|
-
type: "DATE";
|
|
324
|
-
[INTERNAL_KIND]: "FILTER";
|
|
325
|
-
};
|
|
326
|
-
between(start: string, end: string): {
|
|
327
|
-
operator: "BETWEEN";
|
|
328
|
-
value: string[];
|
|
329
|
-
subject: string;
|
|
330
|
-
type: "DATE";
|
|
331
|
-
[INTERNAL_KIND]: "FILTER";
|
|
332
|
-
};
|
|
333
|
-
isNotBetween(start: string, end: string): {
|
|
334
|
-
operator: "IS_NOT_BETWEEN";
|
|
335
|
-
value: string[];
|
|
336
|
-
subject: string;
|
|
337
|
-
type: "DATE";
|
|
338
|
-
[INTERNAL_KIND]: "FILTER";
|
|
339
|
-
};
|
|
340
|
-
isEmpty(): {
|
|
341
|
-
operator: "IS_EMPTY";
|
|
342
|
-
subject: string;
|
|
343
|
-
type: "DATE";
|
|
344
|
-
[INTERNAL_KIND]: "FILTER";
|
|
345
|
-
};
|
|
346
|
-
isNotEmpty(): {
|
|
347
|
-
operator: "IS_NOT_EMPTY";
|
|
348
|
-
subject: string;
|
|
349
|
-
type: "DATE";
|
|
350
|
-
[INTERNAL_KIND]: "FILTER";
|
|
351
|
-
};
|
|
352
|
-
};
|
|
353
|
-
asc(subject: string): ConstructableOrderBy;
|
|
354
|
-
desc(subject: string): ConstructableOrderBy;
|
|
355
|
-
};
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region src/routes/visibility.d.ts
|
|
358
|
-
/**
|
|
359
|
-
* Who may see a route.
|
|
360
|
-
*
|
|
361
|
-
* - `ALL_USERS` — everyone, signed in or not.
|
|
362
|
-
* - `NON_LOGGED_IN_USERS` — signed-out visitors only.
|
|
363
|
-
* - `LOGGED_IN_USERS` — signed-in visitors; with `userGroupIds`, only members of
|
|
364
|
-
* at least one of those groups.
|
|
365
|
-
*/
|
|
366
|
-
type RouteVisibility = {
|
|
367
|
-
userGroup: "ALL_USERS";
|
|
368
|
-
} | {
|
|
369
|
-
userGroup: "NON_LOGGED_IN_USERS";
|
|
370
|
-
} | {
|
|
371
|
-
userGroup: "LOGGED_IN_USERS";
|
|
372
|
-
userGroupIds?: Array<SoftrUserGroupId>;
|
|
373
|
-
};
|
|
374
|
-
/** The route context the root route publishes: the visitor, or `null` when signed out. */
|
|
375
|
-
type SoftrContext = {
|
|
376
|
-
user: User | null;
|
|
377
|
-
};
|
|
378
|
-
/**
|
|
379
|
-
* Why a visitor was denied.
|
|
380
|
-
*
|
|
381
|
-
* - `unauthenticated` — the route needs a signed-in visitor and there is none.
|
|
382
|
-
* - `forbidden` — signed in, but in none of the groups the route names.
|
|
383
|
-
* - `alreadySignedIn` — the route is for signed-out visitors only.
|
|
384
|
-
*/
|
|
385
|
-
declare const ACCESS_REASONS: readonly ["unauthenticated", "forbidden", "alreadySignedIn"];
|
|
386
|
-
type AccessReason = (typeof ACCESS_REASONS)[number];
|
|
387
|
-
/**
|
|
388
|
-
* What a guard does when it refuses a visitor: redirect to a path, or throw an
|
|
389
|
-
* {@link AccessError} for the route's `errorComponent` to render. A bare string
|
|
390
|
-
* is shorthand for redirecting there.
|
|
391
|
-
*/
|
|
392
|
-
type AccessBehaviour = string | {
|
|
393
|
-
strategy: "redirect";
|
|
394
|
-
to: string;
|
|
395
|
-
} | {
|
|
396
|
-
strategy: "throw";
|
|
397
|
-
};
|
|
398
|
-
/** Per-reason overrides of the default {@link AccessBehaviour}. */
|
|
399
|
-
type GuardOverrides = Partial<Record<AccessReason, AccessBehaviour>>;
|
|
400
|
-
/** The result of {@link VisibilityHandle.check}: passed, or denied with a reason. */
|
|
401
|
-
type AccessCheck = {
|
|
402
|
-
ok: true;
|
|
403
|
-
} | {
|
|
404
|
-
ok: false;
|
|
405
|
-
reason: AccessReason;
|
|
406
|
-
};
|
|
407
|
-
/**
|
|
408
|
-
* The access error a guard throws. It is plain data, not an `Error` subclass, so
|
|
409
|
-
* take it as `unknown` in an `errorComponent` and narrow it with
|
|
410
|
-
* {@link isAccessError}. It carries the reason and nothing else: the error is
|
|
411
|
-
* serialized into the page, so it never names the groups the route wanted.
|
|
412
|
-
*
|
|
413
|
-
* @example
|
|
414
|
-
* errorComponent: ({ error }: { error: unknown }) =>
|
|
415
|
-
* isAccessError(error) ? <NoAccess /> : <AppError />
|
|
416
|
-
*/
|
|
417
|
-
type AccessError = {
|
|
418
|
-
type: "access_error";
|
|
419
|
-
reason: AccessReason;
|
|
420
|
-
};
|
|
421
|
-
/**
|
|
422
|
-
* True for any access error thrown by a guard, whatever its reason.
|
|
423
|
-
*
|
|
424
|
-
* An access error arrives as `unknown` — hydrated from the page, or thrown by
|
|
425
|
-
* anything else at all — so every field is checked before it is narrowed.
|
|
426
|
-
*/
|
|
427
|
-
declare function isAccessError(error: unknown): error is AccessError;
|
|
428
|
-
/** True for an access error thrown because nobody was signed in. */
|
|
429
|
-
declare function isUnauthenticatedError(error: unknown): error is AccessError;
|
|
430
|
-
/** True for an access error thrown because the visitor was in none of the groups. */
|
|
431
|
-
declare function isForbiddenError(error: unknown): error is AccessError;
|
|
432
|
-
/** True for an access error thrown because a signed-out-only route saw a user. */
|
|
433
|
-
declare function isAlreadySignedInError(error: unknown): error is AccessError;
|
|
434
|
-
type Narrowed<R extends RouteVisibility> = R extends {
|
|
435
|
-
userGroup: "LOGGED_IN_USERS";
|
|
436
|
-
} ? SoftrContext & {
|
|
437
|
-
user: User;
|
|
438
|
-
} : R extends {
|
|
439
|
-
userGroup: "NON_LOGGED_IN_USERS";
|
|
440
|
-
} ? SoftrContext & {
|
|
441
|
-
user: null;
|
|
442
|
-
} : SoftrContext;
|
|
443
|
-
/** The four ways to apply a rule, returned by {@link defineVisibility}. */
|
|
444
|
-
type VisibilityHandle<R extends RouteVisibility = RouteVisibility> = {
|
|
445
|
-
/**
|
|
446
|
-
* A `beforeLoad` handler that denies a visitor who fails the rule.
|
|
447
|
-
*
|
|
448
|
-
* By default an unauthenticated visitor is redirected to `/login`, an already
|
|
449
|
-
* signed-in one to `/`, and a forbidden one gets an {@link AccessError} thrown
|
|
450
|
-
* in place, for the route's `errorComponent` to render. Pass `overrides` to
|
|
451
|
-
* change what any one reason does.
|
|
452
|
-
*
|
|
453
|
-
* @example
|
|
454
|
-
* beforeLoad: visibility.guard({ unauthenticated: "/sign-in" })
|
|
455
|
-
*/
|
|
456
|
-
guard(overrides?: GuardOverrides): (opts: {
|
|
457
|
-
context: SoftrContext;
|
|
458
|
-
}) => void;
|
|
459
|
-
/**
|
|
460
|
-
* Throws the same access error or redirect `guard()` would, for code that
|
|
461
|
-
* needs to run its own checks after the rule.
|
|
462
|
-
*
|
|
463
|
-
* @example
|
|
464
|
-
* beforeLoad: ({ context }) => {
|
|
465
|
-
* visibility.assert(context)
|
|
466
|
-
* if (context.user.trialExpired) throw redirect({ to: "/renew" })
|
|
467
|
-
* }
|
|
468
|
-
*/
|
|
469
|
-
assert(context: SoftrContext): void;
|
|
470
|
-
/**
|
|
471
|
-
* Whether the visitor passes the rule. Narrows `context.user` where the rule
|
|
472
|
-
* allows it.
|
|
473
|
-
*/
|
|
474
|
-
isAuthorized(context: SoftrContext): context is Narrowed<R>;
|
|
475
|
-
/** The decision and, when a visitor is refused, the reason. Throws nothing. */
|
|
476
|
-
check(context: SoftrContext): AccessCheck;
|
|
477
|
-
};
|
|
478
|
-
/**
|
|
479
|
-
* Declares who may see a route, and returns the handle that enforces it.
|
|
480
|
-
*
|
|
481
|
-
* One call per route file, at module scope: the build reads these declarations
|
|
482
|
-
* to publish the app's route visibility, so the rule must be a literal.
|
|
483
|
-
*
|
|
484
|
-
* @example
|
|
485
|
-
* const visibility = defineVisibility({ userGroup: "LOGGED_IN_USERS" })
|
|
486
|
-
*
|
|
487
|
-
* export const Route = createFileRoute("/about")({
|
|
488
|
-
* beforeLoad: visibility.guard(),
|
|
489
|
-
* component: About,
|
|
490
|
-
* })
|
|
491
|
-
*/
|
|
492
|
-
declare function defineVisibility<const R extends RouteVisibility>(rule: R): VisibilityHandle<R>;
|
|
493
|
-
//#endregion
|
|
494
|
-
//#region src/types.d.ts
|
|
495
|
-
interface SoftrUser {
|
|
496
|
-
id: string;
|
|
497
|
-
email: string;
|
|
498
|
-
name: string;
|
|
499
|
-
userGroupIds: Array<SoftrUserGroupId>;
|
|
500
|
-
}
|
|
501
|
-
interface DatasourcePermissions {
|
|
502
|
-
read: boolean;
|
|
503
|
-
create: boolean;
|
|
504
|
-
update: boolean;
|
|
505
|
-
delete: boolean;
|
|
506
|
-
}
|
|
507
|
-
interface SoftrPermissions {
|
|
508
|
-
datasources: Record<string, DatasourcePermissions>;
|
|
509
|
-
workflows: Record<string, boolean>;
|
|
510
|
-
}
|
|
511
|
-
interface SoftrMe {
|
|
512
|
-
user: SoftrUser | null;
|
|
513
|
-
permissions: SoftrPermissions;
|
|
514
|
-
}
|
|
515
|
-
type GetByIdOptions = {
|
|
516
|
-
id: string;
|
|
517
|
-
where?: never;
|
|
518
|
-
timeZone?: string;
|
|
519
|
-
};
|
|
520
|
-
type GetByWhereOptions = {
|
|
521
|
-
id?: never;
|
|
522
|
-
where: AnyConstructable;
|
|
523
|
-
timeZone?: string;
|
|
524
|
-
};
|
|
525
|
-
type GetOptions = GetByIdOptions | GetByWhereOptions;
|
|
526
|
-
interface ListOptions {
|
|
527
|
-
/**
|
|
528
|
-
* Maps human-readable aliases to Softr field IDs.
|
|
529
|
-
* When provided, returned fields are keyed by alias instead of raw field ID.
|
|
530
|
-
*/
|
|
531
|
-
select?: Record<string, string>;
|
|
532
|
-
where?: AnyConstructable;
|
|
533
|
-
orderBy?: ConstructableOrderBy | ConstructableOrderBy[];
|
|
534
|
-
/**
|
|
535
|
-
* Number of records to return per page. Defaults to 20, max 100.
|
|
536
|
-
*/
|
|
537
|
-
limit?: number;
|
|
538
|
-
/**
|
|
539
|
-
* Offset to start from. Pass the `nextOffset` from a previous result to paginate.
|
|
540
|
-
* Omit or pass `null` to start from the beginning.
|
|
541
|
-
*/
|
|
542
|
-
offset?: number | null;
|
|
543
|
-
/** Override the timezone for this request. */
|
|
544
|
-
timeZone?: string;
|
|
545
|
-
}
|
|
546
|
-
interface ListResult<T = SoftrRecord> {
|
|
547
|
-
records: T[];
|
|
548
|
-
total: number;
|
|
549
|
-
/** Offset to pass as `offset` in the next call, or `null` when there are no more pages. */
|
|
550
|
-
nextOffset: number | null;
|
|
551
|
-
}
|
|
552
|
-
interface SoftrRecord {
|
|
553
|
-
id: string;
|
|
554
|
-
fields: Record<string, unknown>;
|
|
555
|
-
}
|
|
556
|
-
type AggregationFunction = 'SUM' | 'AVG' | 'MAX' | 'MIN' | 'COUNT' | 'DISTINCT';
|
|
557
|
-
interface MetricOptions {
|
|
558
|
-
select?: Record<string, string>;
|
|
559
|
-
where?: AnyConstructable;
|
|
560
|
-
aggregation: AggregationFunction;
|
|
561
|
-
/** Field alias (resolved via select) or raw field ID. Not required for COUNT. */
|
|
562
|
-
field?: string;
|
|
563
|
-
/** Override the timezone for this request. */
|
|
564
|
-
timeZone?: string;
|
|
565
|
-
}
|
|
566
|
-
interface MetricResult {
|
|
567
|
-
value: number | null;
|
|
568
|
-
executionTimestamp: Date;
|
|
569
|
-
}
|
|
570
|
-
interface ChartDataOptions {
|
|
571
|
-
select?: Record<string, string>;
|
|
572
|
-
where?: AnyConstructable;
|
|
573
|
-
/** Field alias (resolved via select) or raw field ID. */
|
|
574
|
-
groupBy: string | string[];
|
|
575
|
-
metrics: Record<string, {
|
|
576
|
-
field?: string;
|
|
577
|
-
aggregation: AggregationFunction;
|
|
578
|
-
}>;
|
|
579
|
-
orderBy?: ConstructableOrderBy;
|
|
580
|
-
/** Override the timezone for this request. */
|
|
581
|
-
timeZone?: string;
|
|
582
|
-
}
|
|
583
|
-
interface ChartDataResult {
|
|
584
|
-
data: Record<string, unknown>[];
|
|
585
|
-
executionTimestamp: Date;
|
|
586
|
-
}
|
|
587
|
-
interface CreateOptions {
|
|
588
|
-
fields: Record<string, unknown>;
|
|
589
|
-
}
|
|
590
|
-
interface UpdateOptions {
|
|
591
|
-
id: string;
|
|
592
|
-
fields: Record<string, unknown>;
|
|
593
|
-
}
|
|
594
|
-
interface DatasourceAPI {
|
|
595
|
-
list(options?: ListOptions): Promise<ListResult>;
|
|
596
|
-
get(options: GetOptions): Promise<SoftrRecord | null>;
|
|
597
|
-
create(options: CreateOptions): Promise<SoftrRecord>;
|
|
598
|
-
update(options: UpdateOptions): Promise<SoftrRecord>;
|
|
599
|
-
delete(id: string): Promise<void>;
|
|
600
|
-
metric(options: MetricOptions): Promise<MetricResult>;
|
|
601
|
-
chartData(options: ChartDataOptions): Promise<ChartDataResult>;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Proxy fetch for a configured integration (e.g. Google Calendar).
|
|
605
|
-
* Behaves like the native `fetch` API — requests are forwarded through
|
|
606
|
-
* Softr's proxy, which handles authentication with the third-party service.
|
|
607
|
-
*
|
|
608
|
-
* ⚠️ Caveats (same as the vibe block's `useProxyFetch`):
|
|
609
|
-
* - Body must be a string — FormData and other binary types are not supported.
|
|
610
|
-
* - Multi-value headers are flattened.
|
|
611
|
-
*/
|
|
612
|
-
interface IntegrationAPI {
|
|
613
|
-
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
614
|
-
}
|
|
615
|
-
interface WorkflowAPI {
|
|
616
|
-
trigger(payload?: Record<string, unknown>): Promise<void>;
|
|
617
|
-
}
|
|
618
|
-
interface AuthAPI {
|
|
619
|
-
/** Sign in with email and password. Clears the cached me() result. */
|
|
620
|
-
login(credentials: {
|
|
621
|
-
email: string;
|
|
622
|
-
password: string;
|
|
623
|
-
}): Promise<void>;
|
|
624
|
-
/** Sign out the current user. Clears the cached me() result. */
|
|
625
|
-
logout(): Promise<void>;
|
|
626
|
-
}
|
|
627
|
-
interface SoftrSDK {
|
|
628
|
-
/**
|
|
629
|
-
* Fetch the current user and their permissions from /me.
|
|
630
|
-
* Cached for the lifetime of the instance — create a new instance per request on the server.
|
|
631
|
-
*/
|
|
632
|
-
me(): Promise<SoftrMe>;
|
|
633
|
-
auth: AuthAPI;
|
|
634
|
-
datasource(id: string): DatasourceAPI;
|
|
635
|
-
integration(id: string): IntegrationAPI;
|
|
636
|
-
workflow(id: string): WorkflowAPI;
|
|
637
|
-
}
|
|
638
|
-
//#endregion
|
|
639
|
-
//#region src/auth/isomorphic.d.ts
|
|
640
|
-
/**
|
|
641
|
-
* Resolves the Softr visitor for every request, so that `getSoftrUser` and the
|
|
642
|
-
* route guards have someone to check.
|
|
643
|
-
*
|
|
644
|
-
* Register it once, as a global request middleware in the app's `src/start.ts`.
|
|
645
|
-
* It touches nothing but the visitor.
|
|
646
|
-
*
|
|
647
|
-
* @example
|
|
648
|
-
* export const startInstance = createStart(() => ({
|
|
649
|
-
* requestMiddleware: [softrAuthMiddleware()],
|
|
650
|
-
* }))
|
|
651
|
-
*/
|
|
652
|
-
declare function softrAuthMiddleware(): _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, {
|
|
653
|
-
user: User | null;
|
|
654
|
-
}>;
|
|
655
|
-
/**
|
|
656
|
-
* Returns the signed-in visitor, or `null` when nobody is signed in.
|
|
657
|
-
*
|
|
658
|
-
* Await it in the root route's `beforeLoad` to publish the visitor as route
|
|
659
|
-
* context, which every `defineVisibility` guard then reads. It requires
|
|
660
|
-
* {@link softrAuthMiddleware} to be registered.
|
|
661
|
-
*
|
|
662
|
-
* @example
|
|
663
|
-
* export const Route = createRootRouteWithContext<SoftrContext>()({
|
|
664
|
-
* beforeLoad: async () => ({ user: await getSoftrUser() }),
|
|
665
|
-
* })
|
|
666
|
-
*/
|
|
667
|
-
declare const getSoftrUser: _tanstack_react_start0.OptionalFetcher<undefined, undefined, Promise<User | null>>;
|
|
668
|
-
//#endregion
|
|
669
|
-
//#region src/core/middleware.d.ts
|
|
670
|
-
/**
|
|
671
|
-
* TanStack Start middleware. Injects a per-request Softr SDK instance with
|
|
672
|
-
* cookies forwarded automatically. The base URL is read from VITE_SOFTR_BASE_URL.
|
|
673
|
-
*
|
|
674
|
-
* @example
|
|
675
|
-
* import { withSDK } from '@softr/sdk'
|
|
676
|
-
*
|
|
677
|
-
* export const getProjects = createServerFn()
|
|
678
|
-
* .middleware([withSDK])
|
|
679
|
-
* .handler(({ context }) => context.sdk.datasource('ds_projects').list())
|
|
680
|
-
*/
|
|
681
|
-
declare const withSDK: _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, {
|
|
682
|
-
sdk: SoftrSDK;
|
|
683
|
-
}>;
|
|
684
|
-
//#endregion
|
|
685
|
-
export { type AccessBehaviour, type AccessCheck, type AccessError, type AccessReason, type AggregationFunction, type AuthAPI, type ChartDataOptions, type ChartDataResult, type CreateOptions, type DatasourceAPI, type DatasourcePermissions, type GetOptions, type IntegrationAPI, type ListOptions, type ListResult, type MetricOptions, type MetricResult, type RouteVisibility, type SoftrContext, type SoftrMe, type SoftrPermissions, type SoftrRecord, type SoftrSDK, type SoftrUser, type SoftrUserGroupId, type SoftrUserGroups, type UpdateOptions, type User, type VisibilityHandle, type WorkflowAPI, defineVisibility, getSoftrUser, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError, q, softrAuthMiddleware, withSDK };
|
|
1
|
+
import { q } from "./core/query.js";
|
|
2
|
+
import { SoftrUserGroupId, SoftrUserGroups, User } from "./auth/user.js";
|
|
3
|
+
import { AggregationFunction, ChartDataOptions, ChartDataResult, CreateOptions, DatasourcePermissions, GetOptions, ListOptions, ListResult, MetricOptions, MetricResult, SoftrMe, SoftrPermissions, SoftrRecord, SoftrUser, UpdateOptions } from "./types.js";
|
|
4
|
+
import { Permissions } from "./auth/permissions.js";
|
|
5
|
+
import { SoftrContext } from "./auth/context.js";
|
|
6
|
+
import { AccessBehaviour, AccessCheck, AccessError, AccessReason, RouteVisibility, VisibilityHandle, defineVisibility, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError } from "./routes/visibility.js";
|
|
7
|
+
import { getSoftrContext, initialSoftrContext, softrAuthMiddleware, useCurrentUser, usePermissions } from "./auth/isomorphic.js";
|
|
8
|
+
export { type AccessBehaviour, type AccessCheck, type AccessError, type AccessReason, type AggregationFunction, type ChartDataOptions, type ChartDataResult, type CreateOptions, type DatasourcePermissions, type GetOptions, type ListOptions, type ListResult, type MetricOptions, type MetricResult, type Permissions, type RouteVisibility, type SoftrContext, type SoftrMe, type SoftrPermissions, type SoftrRecord, type SoftrUser, type SoftrUserGroupId, type SoftrUserGroups, type UpdateOptions, type User, type VisibilityHandle, defineVisibility, getSoftrContext, initialSoftrContext, isAccessError, isAlreadySignedInError, isForbiddenError, isUnauthenticatedError, q, softrAuthMiddleware, useCurrentUser, usePermissions };
|