@softr/sdk 0.0.23 → 0.0.25
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 +1 -7
- package/dist/auth/methods/authenticator.d.ts +80 -0
- package/dist/auth/methods/authenticator.js +175 -0
- package/dist/auth/methods/code.d.ts +40 -0
- package/dist/auth/methods/code.js +74 -0
- package/dist/auth/methods/magicLink.d.ts +24 -0
- package/dist/auth/methods/magicLink.js +53 -0
- package/dist/auth/methods/password.d.ts +19 -5
- package/dist/auth/methods/password.js +36 -15
- package/dist/auth/methods/signup.d.ts +22 -14
- package/dist/auth/methods/signup.js +48 -54
- package/dist/auth/methods/social.d.ts +35 -0
- package/dist/auth/methods/social.js +58 -0
- package/dist/auth/methods/utils.d.ts +1 -1
- package/dist/auth/platform.js +185 -7
- package/dist/auth/server.d.ts +15 -0
- package/dist/auth/server.js +16 -1
- package/dist/auth/session.js +39 -20
- package/dist/core/datasource.d.ts +3 -3
- package/dist/core/datasource.js +17 -17
- package/dist/core/integration.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +3 -3
- package/dist/vite.d.ts +2 -9
- package/dist/vite.js +3 -68
- package/package.json +1 -6
- package/skills/softr-sdk/SKILL.md +3 -3
- package/skills/softr-sdk/auth/SKILL.md +222 -36
- package/skills/softr-sdk/current-user/SKILL.md +1 -1
- package/skills/softr-sdk/data-mutations/SKILL.md +2 -2
- package/skills/softr-sdk/reading-records/SKILL.md +3 -3
- package/skills/softr-sdk/routes-and-visibility/SKILL.md +5 -5
- package/dist/preview-identity/preview-identity.js +0 -121
- package/dist/routes/discover.d.ts +0 -14
- package/dist/routes/discover.js +0 -305
- package/dist/routes/manifest.d.ts +0 -24
- package/dist/routes/manifest.js +0 -168
- package/dist/routes/mem-fs.js +0 -71
package/dist/routes/manifest.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { crawlRoutes, extractDatasources, extractVisibility } from "./discover.js";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { inferFullPath } from "@tanstack/router-generator";
|
|
5
|
-
|
|
6
|
-
//#region src/routes/manifest.ts
|
|
7
|
-
var ManifestError = class extends Error {
|
|
8
|
-
detail;
|
|
9
|
-
constructor(detail) {
|
|
10
|
-
super(detail.message);
|
|
11
|
-
this.name = "ManifestError";
|
|
12
|
-
this.detail = detail;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
/** Returns the manifest as the exact text to write. Throws on a declaration it cannot read. */
|
|
16
|
-
async function generateRoutesManifest(root) {
|
|
17
|
-
const crawl = await crawlRoutes({ root });
|
|
18
|
-
const routeFiles = new Set([crawl.rootRouteNode.filePath]);
|
|
19
|
-
for (const node of crawl.routeNodes) routeFiles.add(node.filePath);
|
|
20
|
-
for (const pieces of Object.values(crawl.routePiecesByPath)) if (pieces.lazy) routeFiles.add(pieces.lazy.filePath);
|
|
21
|
-
const sources = /* @__PURE__ */ new Map();
|
|
22
|
-
for (const relative of routeFiles) {
|
|
23
|
-
const absolute = path.resolve(root, crawl.routesDirectory, relative);
|
|
24
|
-
const source = await readIfPresent(absolute);
|
|
25
|
-
if (source !== null) sources.set(absolute, source);
|
|
26
|
-
}
|
|
27
|
-
const manifest = buildManifest({
|
|
28
|
-
crawl,
|
|
29
|
-
root,
|
|
30
|
-
sources
|
|
31
|
-
});
|
|
32
|
-
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
33
|
-
}
|
|
34
|
-
function buildManifest(opts) {
|
|
35
|
-
const routesDirectory = opts.crawl.routesDirectory;
|
|
36
|
-
const datasources = [];
|
|
37
|
-
const toNode = (node) => {
|
|
38
|
-
const projectRelative = toProjectRelative(opts.root, routesDirectory, node.filePath);
|
|
39
|
-
const routePath = node.routePath;
|
|
40
|
-
if (routePath === void 0) throw new Error(`the route crawl produced a node with no route path: ${projectRelative}`);
|
|
41
|
-
let declared = visibilityOf(opts, node.filePath);
|
|
42
|
-
datasources.push(...datasourceEntriesOf(opts, node.filePath, routePath));
|
|
43
|
-
const lazyPiece = opts.crawl.routePiecesByPath[routePath]?.lazy;
|
|
44
|
-
if (lazyPiece && lazyPiece.filePath !== node.filePath) {
|
|
45
|
-
const lazyDeclared = visibilityOf(opts, lazyPiece.filePath);
|
|
46
|
-
if (lazyDeclared !== null && declared !== null) throw new ManifestError({
|
|
47
|
-
code: "duplicate-declaration",
|
|
48
|
-
message: `${routePath} declares visibility in both ${projectRelative} and ${lazyDeclared.filePath}; a route has exactly one rule`,
|
|
49
|
-
filePath: lazyDeclared.filePath,
|
|
50
|
-
line: lazyDeclared.line,
|
|
51
|
-
column: lazyDeclared.column
|
|
52
|
-
});
|
|
53
|
-
if (lazyDeclared !== null) declared = lazyDeclared;
|
|
54
|
-
datasources.push(...datasourceEntriesOf(opts, lazyPiece.filePath, routePath));
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
routePath,
|
|
58
|
-
filePath: projectRelative,
|
|
59
|
-
...node._fsRouteType ? { _fsRouteType: node._fsRouteType } : {},
|
|
60
|
-
inferFullPath: inferFullPath(node) ?? null,
|
|
61
|
-
createFileRouteProps: [...node.createFileRouteProps ?? []].sort(),
|
|
62
|
-
visibility: declared?.value ?? null,
|
|
63
|
-
children: (node.children ?? []).map(toNode)
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
const rootNode = opts.crawl.rootRouteNode;
|
|
67
|
-
const rootRelative = toProjectRelative(opts.root, routesDirectory, rootNode.filePath);
|
|
68
|
-
const rootDeclared = visibilityOf(opts, rootNode.filePath);
|
|
69
|
-
if (rootDeclared !== null) throw new ManifestError({
|
|
70
|
-
code: "root-declaration",
|
|
71
|
-
message: "the root route cannot carry a visibility rule: it would gate sign-in with no way back in. Move this declaration to the routes you want gated.",
|
|
72
|
-
filePath: rootRelative,
|
|
73
|
-
line: rootDeclared.line,
|
|
74
|
-
column: rootDeclared.column
|
|
75
|
-
});
|
|
76
|
-
datasources.push(...datasourceEntriesOf(opts, rootNode.filePath, ROOT_ROUTE_ID));
|
|
77
|
-
return {
|
|
78
|
-
root: {
|
|
79
|
-
routePath: ROOT_ROUTE_ID,
|
|
80
|
-
filePath: rootRelative,
|
|
81
|
-
inferFullPath: inferFullPath(rootNode) ?? null,
|
|
82
|
-
createFileRouteProps: [...rootNode.createFileRouteProps ?? []].sort(),
|
|
83
|
-
visibility: null,
|
|
84
|
-
children: opts.crawl.routeTree.map(toNode)
|
|
85
|
-
},
|
|
86
|
-
datasources
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* `rootRouteId` from `@tanstack/router-core`, which is what a consumer matches against — not the
|
|
91
|
-
* generator's `rootPathId`, which is the base name of `__root.tsx` and names a file, not a route.
|
|
92
|
-
*/
|
|
93
|
-
const ROOT_ROUTE_ID = "__root__";
|
|
94
|
-
/** The crawl's paths are relative to the routes directory; the manifest's are project-relative. */
|
|
95
|
-
function toProjectRelative(root, routesDirectory, filePath) {
|
|
96
|
-
const absolute = path.resolve(root, routesDirectory, filePath);
|
|
97
|
-
return path.relative(root, absolute).split(path.sep).join("/");
|
|
98
|
-
}
|
|
99
|
-
const USER_GROUPS = [
|
|
100
|
-
"ALL_USERS",
|
|
101
|
-
"NON_LOGGED_IN_USERS",
|
|
102
|
-
"LOGGED_IN_USERS"
|
|
103
|
-
];
|
|
104
|
-
function checkVisibilityShape(declared) {
|
|
105
|
-
const reject = (message) => {
|
|
106
|
-
throw new ManifestError({
|
|
107
|
-
code: "invalid-visibility",
|
|
108
|
-
message: `${declared.filePath}: ${message}`,
|
|
109
|
-
filePath: declared.filePath,
|
|
110
|
-
line: declared.line,
|
|
111
|
-
column: declared.column
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
const visibility = declared.value;
|
|
115
|
-
if (typeof visibility !== "object" || Array.isArray(visibility)) reject(`the visibility rule must be an object literal like { userGroup: 'ALL_USERS' }, not ${JSON.stringify(visibility)}`);
|
|
116
|
-
for (const key of Object.keys(visibility)) {
|
|
117
|
-
if (key === "userGroup" || key === "userGroupIds") continue;
|
|
118
|
-
reject(`"${key}" is not part of a visibility rule; a rule has userGroup and, under LOGGED_IN_USERS, userGroupIds. Check the spelling.`);
|
|
119
|
-
}
|
|
120
|
-
const userGroup = visibility["userGroup"];
|
|
121
|
-
if (typeof userGroup !== "string" || !USER_GROUPS.includes(userGroup)) reject(`userGroup must be one of ${USER_GROUPS.join(", ")}, not ${JSON.stringify(userGroup)}. A rule the build cannot read is a route with no rule at all.`);
|
|
122
|
-
if (!("userGroupIds" in visibility)) return;
|
|
123
|
-
if (userGroup !== "LOGGED_IN_USERS") reject(`userGroupIds only means anything under LOGGED_IN_USERS, not under ${userGroup}`);
|
|
124
|
-
const ids = visibility["userGroupIds"];
|
|
125
|
-
if (!Array.isArray(ids) || ids.some((id) => typeof id !== "string")) reject(`userGroupIds must be an array of group id strings, not ${JSON.stringify(ids)}. Drop the key entirely to mean "any logged-in user".`);
|
|
126
|
-
}
|
|
127
|
-
function visibilityOf(opts, filePath) {
|
|
128
|
-
const projectRelative = toProjectRelative(opts.root, opts.crawl.routesDirectory, filePath);
|
|
129
|
-
const source = opts.sources.get(path.resolve(opts.root, opts.crawl.routesDirectory, filePath));
|
|
130
|
-
if (source === void 0) return null;
|
|
131
|
-
const result = extractVisibility(source, projectRelative);
|
|
132
|
-
if (!result.ok) throw new ManifestError(result.error);
|
|
133
|
-
if (result.visibility === null) return null;
|
|
134
|
-
const declared = {
|
|
135
|
-
...result.visibility,
|
|
136
|
-
filePath: projectRelative
|
|
137
|
-
};
|
|
138
|
-
checkVisibilityShape(declared);
|
|
139
|
-
return declared;
|
|
140
|
-
}
|
|
141
|
-
function datasourceEntriesOf(opts, filePath, routePath) {
|
|
142
|
-
const projectRelative = toProjectRelative(opts.root, opts.crawl.routesDirectory, filePath);
|
|
143
|
-
const source = opts.sources.get(path.resolve(opts.root, opts.crawl.routesDirectory, filePath));
|
|
144
|
-
if (source === void 0) return [];
|
|
145
|
-
const result = extractDatasources(source, projectRelative);
|
|
146
|
-
if (!result.ok) throw new ManifestError(result.error);
|
|
147
|
-
return result.datasources.map(({ id, methods }) => ({
|
|
148
|
-
id,
|
|
149
|
-
methods,
|
|
150
|
-
filename: projectRelative,
|
|
151
|
-
route: routePath
|
|
152
|
-
}));
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Only ENOENT becomes `null`. The caller reads `null` as "nothing declared here", so swallowing any
|
|
156
|
-
* other read error would turn an unreadable declaration into an ungated route.
|
|
157
|
-
*/
|
|
158
|
-
async function readIfPresent(filePath) {
|
|
159
|
-
try {
|
|
160
|
-
return await readFile(filePath, "utf8");
|
|
161
|
-
} catch (error) {
|
|
162
|
-
if (error.code === "ENOENT") return null;
|
|
163
|
-
throw error;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
//#endregion
|
|
168
|
-
export { ManifestError, generateRoutesManifest };
|
package/dist/routes/mem-fs.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import * as nodeFs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
//#region src/routes/mem-fs.ts
|
|
5
|
-
/**
|
|
6
|
-
* Reads through to disk and swallows every write. Driving the generator without this rewrites the
|
|
7
|
-
* app's route sources and strips Start's `Register` block from its routeTree.gen.ts.
|
|
8
|
-
*/
|
|
9
|
-
function createReadOnlyFs() {
|
|
10
|
-
const writes = /* @__PURE__ */ new Map();
|
|
11
|
-
return {
|
|
12
|
-
async stat(filePath) {
|
|
13
|
-
const stat = await statOrNull(path.resolve(filePath));
|
|
14
|
-
if (stat === null) return {
|
|
15
|
-
mtimeMs: SYNTHETIC_MTIME,
|
|
16
|
-
mode: 420,
|
|
17
|
-
uid: 0,
|
|
18
|
-
gid: 0
|
|
19
|
-
};
|
|
20
|
-
return {
|
|
21
|
-
mtimeMs: stat.mtimeMs,
|
|
22
|
-
mode: Number(stat.mode),
|
|
23
|
-
uid: Number(stat.uid),
|
|
24
|
-
gid: Number(stat.gid)
|
|
25
|
-
};
|
|
26
|
-
},
|
|
27
|
-
async rename(oldPath, newPath) {
|
|
28
|
-
const from = path.resolve(oldPath);
|
|
29
|
-
const content = writes.get(from);
|
|
30
|
-
if (content !== void 0) {
|
|
31
|
-
writes.delete(from);
|
|
32
|
-
writes.set(path.resolve(newPath), content);
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
async writeFile(filePath, content) {
|
|
36
|
-
writes.set(path.resolve(filePath), content);
|
|
37
|
-
},
|
|
38
|
-
async readFile(filePath) {
|
|
39
|
-
const resolved = path.resolve(filePath);
|
|
40
|
-
const pending = writes.get(resolved);
|
|
41
|
-
const stat = await statOrNull(resolved);
|
|
42
|
-
if (pending !== void 0) return {
|
|
43
|
-
stat: { mtimeMs: stat?.mtimeMs ?? SYNTHETIC_MTIME },
|
|
44
|
-
fileContent: pending
|
|
45
|
-
};
|
|
46
|
-
if (stat === null) return "file-not-existing";
|
|
47
|
-
try {
|
|
48
|
-
const fileContent = await nodeFs.readFile(resolved, "utf8");
|
|
49
|
-
return {
|
|
50
|
-
stat: { mtimeMs: stat.mtimeMs },
|
|
51
|
-
fileContent
|
|
52
|
-
};
|
|
53
|
-
} catch {
|
|
54
|
-
return "file-not-existing";
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
async chmod() {},
|
|
58
|
-
async chown() {}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
const SYNTHETIC_MTIME = 1n;
|
|
62
|
-
async function statOrNull(filePath) {
|
|
63
|
-
try {
|
|
64
|
-
return await nodeFs.stat(filePath, { bigint: true });
|
|
65
|
-
} catch {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
//#endregion
|
|
71
|
-
export { createReadOnlyFs };
|