@robelest/convex-auth 0.0.2-preview.2 → 0.0.3-preview

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 (114) hide show
  1. package/dist/bin.cjs +467 -64
  2. package/dist/client/index.d.ts +127 -0
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +424 -1
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/component/_generated/api.d.ts +56 -1
  7. package/dist/component/_generated/api.d.ts.map +1 -1
  8. package/dist/component/_generated/api.js.map +1 -1
  9. package/dist/component/_generated/component.d.ts +141 -3
  10. package/dist/component/_generated/component.d.ts.map +1 -1
  11. package/dist/component/convex.config.d.ts.map +1 -1
  12. package/dist/component/convex.config.js +2 -0
  13. package/dist/component/convex.config.js.map +1 -1
  14. package/dist/component/index.d.ts +5 -4
  15. package/dist/component/index.d.ts.map +1 -1
  16. package/dist/component/index.js +4 -3
  17. package/dist/component/index.js.map +1 -1
  18. package/dist/component/portalBridge.d.ts +80 -0
  19. package/dist/component/portalBridge.d.ts.map +1 -0
  20. package/dist/component/portalBridge.js +102 -0
  21. package/dist/component/portalBridge.js.map +1 -0
  22. package/dist/component/public.d.ts +353 -9
  23. package/dist/component/public.d.ts.map +1 -1
  24. package/dist/component/public.js +328 -33
  25. package/dist/component/public.js.map +1 -1
  26. package/dist/component/schema.d.ts +168 -9
  27. package/dist/component/schema.d.ts.map +1 -1
  28. package/dist/component/schema.js +113 -7
  29. package/dist/component/schema.js.map +1 -1
  30. package/dist/providers/passkey.d.ts +20 -0
  31. package/dist/providers/passkey.d.ts.map +1 -0
  32. package/dist/providers/passkey.js +32 -0
  33. package/dist/providers/passkey.js.map +1 -0
  34. package/dist/providers/totp.d.ts +14 -0
  35. package/dist/providers/totp.d.ts.map +1 -0
  36. package/dist/providers/totp.js +23 -0
  37. package/dist/providers/totp.js.map +1 -0
  38. package/dist/server/convex-auth.d.ts +296 -0
  39. package/dist/server/convex-auth.d.ts.map +1 -0
  40. package/dist/server/convex-auth.js +480 -0
  41. package/dist/server/convex-auth.js.map +1 -0
  42. package/dist/server/email-templates.d.ts +18 -0
  43. package/dist/server/email-templates.d.ts.map +1 -0
  44. package/dist/server/email-templates.js +74 -0
  45. package/dist/server/email-templates.js.map +1 -0
  46. package/dist/server/implementation/apiKey.d.ts +74 -0
  47. package/dist/server/implementation/apiKey.d.ts.map +1 -0
  48. package/dist/server/implementation/apiKey.js +140 -0
  49. package/dist/server/implementation/apiKey.js.map +1 -0
  50. package/dist/server/implementation/index.d.ts +169 -7
  51. package/dist/server/implementation/index.d.ts.map +1 -1
  52. package/dist/server/implementation/index.js +220 -5
  53. package/dist/server/implementation/index.js.map +1 -1
  54. package/dist/server/implementation/passkey.d.ts +33 -0
  55. package/dist/server/implementation/passkey.d.ts.map +1 -0
  56. package/dist/server/implementation/passkey.js +450 -0
  57. package/dist/server/implementation/passkey.js.map +1 -0
  58. package/dist/server/implementation/redirects.d.ts.map +1 -1
  59. package/dist/server/implementation/redirects.js +4 -9
  60. package/dist/server/implementation/redirects.js.map +1 -1
  61. package/dist/server/implementation/signIn.d.ts +13 -0
  62. package/dist/server/implementation/signIn.d.ts.map +1 -1
  63. package/dist/server/implementation/signIn.js +29 -15
  64. package/dist/server/implementation/signIn.js.map +1 -1
  65. package/dist/server/implementation/totp.d.ts +40 -0
  66. package/dist/server/implementation/totp.d.ts.map +1 -0
  67. package/dist/server/implementation/totp.js +211 -0
  68. package/dist/server/implementation/totp.js.map +1 -0
  69. package/dist/server/index.d.ts +26 -2
  70. package/dist/server/index.d.ts.map +1 -1
  71. package/dist/server/index.js +63 -16
  72. package/dist/server/index.js.map +1 -1
  73. package/dist/server/portal-email.d.ts +19 -0
  74. package/dist/server/portal-email.d.ts.map +1 -0
  75. package/dist/server/portal-email.js +89 -0
  76. package/dist/server/portal-email.js.map +1 -0
  77. package/dist/server/provider_utils.d.ts +3 -1
  78. package/dist/server/provider_utils.d.ts.map +1 -1
  79. package/dist/server/provider_utils.js +39 -1
  80. package/dist/server/provider_utils.js.map +1 -1
  81. package/dist/server/types.d.ts +263 -4
  82. package/dist/server/types.d.ts.map +1 -1
  83. package/dist/server/version.d.ts +2 -0
  84. package/dist/server/version.d.ts.map +1 -0
  85. package/dist/server/version.js +3 -0
  86. package/dist/server/version.js.map +1 -0
  87. package/package.json +7 -3
  88. package/src/cli/index.ts +49 -7
  89. package/src/cli/portal-link.ts +112 -0
  90. package/src/cli/portal-upload.ts +411 -0
  91. package/src/cli/utils.ts +248 -0
  92. package/src/client/index.ts +489 -1
  93. package/src/component/_generated/api.ts +72 -1
  94. package/src/component/_generated/component.ts +241 -4
  95. package/src/component/convex.config.ts +3 -0
  96. package/src/component/index.ts +8 -3
  97. package/src/component/portalBridge.ts +116 -0
  98. package/src/component/public.ts +373 -37
  99. package/src/component/schema.ts +122 -7
  100. package/src/providers/passkey.ts +35 -0
  101. package/src/providers/totp.ts +26 -0
  102. package/src/server/convex-auth.ts +602 -0
  103. package/src/server/email-templates.ts +77 -0
  104. package/src/server/implementation/apiKey.ts +185 -0
  105. package/src/server/implementation/index.ts +301 -8
  106. package/src/server/implementation/passkey.ts +650 -0
  107. package/src/server/implementation/redirects.ts +4 -11
  108. package/src/server/implementation/signIn.ts +41 -13
  109. package/src/server/implementation/totp.ts +366 -0
  110. package/src/server/index.ts +98 -34
  111. package/src/server/portal-email.ts +95 -0
  112. package/src/server/provider_utils.ts +42 -1
  113. package/src/server/types.ts +285 -4
  114. package/src/server/version.ts +2 -0
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Shared CLI utilities — logging, subprocess execution, file helpers.
3
+ *
4
+ * Eliminates duplication across index.ts, portal-upload.ts, portal-link.ts.
5
+ * All output goes to stderr so stdout can be piped cleanly.
6
+ */
7
+
8
+ import chalk from "chalk";
9
+ import { execFileSync } from "child_process";
10
+ import { existsSync, readFileSync, writeFileSync } from "fs";
11
+ import { extname } from "path";
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Logging — unified output to stderr with chalk prefixes
15
+ // ---------------------------------------------------------------------------
16
+
17
+ const write = (msg: string) => process.stderr.write(msg + "\n");
18
+
19
+ export const log = {
20
+ step: (n: number, msg: string) => write(`${chalk.blue.bold(`[${n}]`)} ${chalk.bold(msg)}`),
21
+ success: (msg: string) => write(`${chalk.green("✔")} ${msg}`),
22
+ warn: (msg: string) => write(`${chalk.yellow.bold("!")} ${msg}`),
23
+ error: (msg: string, detail?: string) =>
24
+ write(`${chalk.red("✖")} ${msg}${detail ? `\n ${chalk.grey(`Error: ${detail}`)}` : ""}`),
25
+ info: (msg: string) => write(`${chalk.blue.bold("i")} ${msg}`),
26
+ blank: () => write(""),
27
+ raw: (msg: string) => write(msg),
28
+ indent: (msg: string) => write(` ${msg}`),
29
+ } as const;
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Subprocess — safe execFile with argument arrays (no shell injection)
33
+ // ---------------------------------------------------------------------------
34
+
35
+ export type DeploymentOptions = {
36
+ prod?: boolean;
37
+ adminKey?: string;
38
+ url?: string;
39
+ previewName?: string;
40
+ deploymentName?: string;
41
+ };
42
+
43
+ /** Build CLI args array for Convex deployment selection. */
44
+ export const deploymentArgs = (opts: DeploymentOptions): string[] => {
45
+ const args: string[] = [];
46
+ if (opts.adminKey) args.push("--admin-key", opts.adminKey);
47
+ if (opts.url) args.push("--url", opts.url);
48
+ else if (opts.prod) args.push("--prod");
49
+ else if (opts.previewName) args.push("--preview-name", opts.previewName);
50
+ else if (opts.deploymentName) args.push("--deployment-name", opts.deploymentName);
51
+ return args;
52
+ };
53
+
54
+ /** Run `npx convex env get <name>` and return the value. */
55
+ export const envGet = (name: string, opts: DeploymentOptions): string =>
56
+ execFileSync("npx", ["convex", "env", "get", ...deploymentArgs(opts), name], {
57
+ encoding: "utf-8",
58
+ stdio: ["pipe", "pipe", "pipe"],
59
+ }).slice(0, -1); // strip trailing newline
60
+
61
+ /** Run `npx convex env set <name> <value>`. */
62
+ export const envSet = (
63
+ name: string,
64
+ value: string,
65
+ opts: DeploymentOptions & { hideValue?: boolean },
66
+ ): void => {
67
+ execFileSync(
68
+ "npx",
69
+ ["convex", "env", "set", ...deploymentArgs(opts), "--", name, value],
70
+ { stdio: opts.hideValue ? "ignore" : "inherit" },
71
+ );
72
+ };
73
+
74
+ /**
75
+ * Run a Convex function via `npx convex run` and return parsed JSON output.
76
+ * Uses execFile with argument arrays — no shell injection.
77
+ */
78
+ export const convexRun = <T = unknown>(
79
+ functionPath: string,
80
+ args: Record<string, unknown>,
81
+ opts: { prod?: boolean } = {},
82
+ ): Promise<T> =>
83
+ new Promise((resolve, reject) => {
84
+ const { execFile } = require("child_process");
85
+ const cmdArgs = [
86
+ "convex", "run", functionPath,
87
+ JSON.stringify(args),
88
+ "--typecheck=disable",
89
+ "--codegen=disable",
90
+ ...(opts.prod ? ["--prod"] : []),
91
+ ];
92
+ execFile("npx", cmdArgs, { encoding: "utf-8" }, (error: any, stdout: string, stderr: string) => {
93
+ if (error) {
94
+ reject(new Error(`convex run ${functionPath} failed: ${stderr || stdout}`));
95
+ return;
96
+ }
97
+ try {
98
+ resolve(JSON.parse(stdout.trim()) as T);
99
+ } catch {
100
+ // If output is not JSON, return raw string as-is
101
+ resolve(stdout.trim() as T);
102
+ }
103
+ });
104
+ });
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // MIME types
108
+ // ---------------------------------------------------------------------------
109
+
110
+ const MIME_TYPES: Record<string, string> = {
111
+ ".html": "text/html; charset=utf-8",
112
+ ".js": "application/javascript; charset=utf-8",
113
+ ".mjs": "application/javascript; charset=utf-8",
114
+ ".css": "text/css; charset=utf-8",
115
+ ".json": "application/json; charset=utf-8",
116
+ ".png": "image/png",
117
+ ".jpg": "image/jpeg",
118
+ ".jpeg": "image/jpeg",
119
+ ".gif": "image/gif",
120
+ ".svg": "image/svg+xml",
121
+ ".ico": "image/x-icon",
122
+ ".webp": "image/webp",
123
+ ".woff": "font/woff",
124
+ ".woff2":"font/woff2",
125
+ ".ttf": "font/ttf",
126
+ ".txt": "text/plain; charset=utf-8",
127
+ ".map": "application/json",
128
+ ".webmanifest": "application/manifest+json",
129
+ ".xml": "application/xml",
130
+ ".br": "application/octet-stream",
131
+ ".gz": "application/gzip",
132
+ };
133
+
134
+ export const getMimeType = (path: string): string =>
135
+ MIME_TYPES[extname(path).toLowerCase()] ?? "application/octet-stream";
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // File helpers
139
+ // ---------------------------------------------------------------------------
140
+
141
+ /**
142
+ * Check for an existing non-empty source file (.ts or .js) at the given
143
+ * base path (without extension). Returns the path if found, null otherwise.
144
+ */
145
+ export const findExistingSource = (basePath: string): string | null =>
146
+ [".ts", ".js"]
147
+ .map((ext) => basePath + ext)
148
+ .find((p) => existsSync(p) && readFileSync(p, "utf-8").trim() !== "")
149
+ ?? null;
150
+
151
+ /**
152
+ * Test whether an existing file already matches a template.
153
+ * Templates use `$$` as wildcards and `;` followed by newline as flexible separators.
154
+ */
155
+ export const matchesTemplate = (existing: string, template: string): boolean =>
156
+ new RegExp(
157
+ template
158
+ .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
159
+ .replace(/\\\$\\\$/g, ".*")
160
+ .replace(/;\n/g, ";.*"),
161
+ "s",
162
+ ).test(existing);
163
+
164
+ /** Strip template markers from a source template. */
165
+ export const stripMarkers = (template: string): string =>
166
+ template.replace(/\$\$/g, "");
167
+
168
+ /**
169
+ * Higher-order function: ensure a file matches a template.
170
+ *
171
+ * - If the file doesn't exist → create it
172
+ * - If it already matches → log success
173
+ * - If it exists but doesn't match → show instructions and prompt
174
+ *
175
+ * Returns a configured function bound to the convex folder path + TS preference.
176
+ */
177
+ export const createFileEnsurer = (
178
+ convexFolderPath: string,
179
+ usesTypeScript: boolean,
180
+ promptFn: (message: string) => Promise<void>,
181
+ ) => {
182
+ const path = require("path");
183
+
184
+ return async (
185
+ baseName: string,
186
+ template: string,
187
+ description: string,
188
+ ): Promise<void> => {
189
+ const source = stripMarkers(template);
190
+ const filePath = path.join(convexFolderPath, baseName);
191
+ const existing = findExistingSource(filePath);
192
+
193
+ if (existing) {
194
+ const content = readFileSync(existing, "utf-8");
195
+ if (matchesTemplate(content, template)) {
196
+ log.success(`${chalk.bold(existing)} already configured.`);
197
+ return;
198
+ }
199
+ log.info(`${chalk.bold(existing)} needs ${description}:`);
200
+ log.raw(`\n${indentBlock(source)}\n`);
201
+ await promptFn("Ready to continue?");
202
+ return;
203
+ }
204
+
205
+ const ext = usesTypeScript ? ".ts" : ".js";
206
+ const newPath = filePath + ext;
207
+ writeFileSync(newPath, source);
208
+ log.success(`Created ${chalk.bold(newPath)}`);
209
+ };
210
+ };
211
+
212
+ /** Indent a multiline string (2 spaces, first line not indented). */
213
+ export const indentBlock = (s: string): string =>
214
+ s.replace(/^/gm, " ").slice(2);
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // Crypto helpers (for portal invite links)
218
+ // ---------------------------------------------------------------------------
219
+
220
+ export { randomBytes, createHash } from "crypto";
221
+
222
+ /** Generate a URL-safe random token (32 bytes → 43 chars base64url). */
223
+ export const generateToken = (): string =>
224
+ require("crypto").randomBytes(32).toString("base64url");
225
+
226
+ /** SHA-256 hash a string and return the hex digest. */
227
+ export const hashToken = (token: string): string =>
228
+ require("crypto").createHash("sha256").update(token).digest("hex");
229
+
230
+ // ---------------------------------------------------------------------------
231
+ // Package version
232
+ // ---------------------------------------------------------------------------
233
+
234
+ /** Read the auth package version from its own package.json. */
235
+ export const getPackageVersion = (): string => {
236
+ try {
237
+ const pkgPath = require("path").resolve(__dirname, "..", "package.json");
238
+ return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
239
+ } catch {
240
+ // Fallback: if running from dist/bin.cjs, package.json is two levels up
241
+ try {
242
+ const pkgPath = require("path").resolve(__dirname, "..", "..", "package.json");
243
+ return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
244
+ } catch {
245
+ return "unknown";
246
+ }
247
+ }
248
+ };