toiljs 0.0.104 → 0.0.106

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.
@@ -63,6 +63,15 @@ const REACT_INTERNAL = new Set([
63
63
  'then', // so a thenable check never tokenizes
64
64
  ]);
65
65
 
66
+ /**
67
+ * Reserved `emails/*.tsx` module names (by PascalCase basename) that OVERRIDE a
68
+ * built-in auth email instead of becoming a generic `Emails.<Name>.send(...)`
69
+ * entry. When one is present, the auth pipeline (src/compiler/auth-emails.ts)
70
+ * bakes it into `_auth_emails.ts` in place of the default; here we just make sure
71
+ * it does NOT also surface as an app-callable `Emails.*` template.
72
+ */
73
+ export const RESERVED_AUTH_EMAIL_NAMES = new Set(['AuthConfirm', 'AuthReset', 'Auth2fa']);
74
+
66
75
  const TOKEN_RE = /\{\{\s*([A-Za-z_$][\w$]*)\s*\}\}/g;
67
76
 
68
77
  function extractTokens(s: string): string[] {
@@ -240,7 +249,7 @@ export function toPascal(base: string): string {
240
249
 
241
250
  /** Server source dir (where the generated module must live to be compiled): the
242
251
  * dir of the first toilconfig entry, else `<root>/server`. */
243
- function serverDir(root: string): string {
252
+ export function serverDir(root: string): string {
244
253
  try {
245
254
  const cfg = JSON.parse(fs.readFileSync(path.join(root, 'toilconfig.json'), 'utf8')) as {
246
255
  entries?: unknown;
@@ -344,6 +353,10 @@ export async function renderEmails(cfg: ResolvedToilConfig): Promise<void> {
344
353
  const rendered: RenderedEmail[] = [];
345
354
  try {
346
355
  for (const file of files) {
356
+ // Reserved auth-override templates (emails/auth-confirm.tsx, …) are
357
+ // consumed by the auth pipeline, not surfaced as generic `Emails.*`.
358
+ if (RESERVED_AUTH_EMAIL_NAMES.has(toPascal(path.basename(file).replace(/\.(tsx|jsx)$/, ''))))
359
+ continue;
347
360
  try {
348
361
  const r = await renderEmailFile(
349
362
  server,
@@ -14,6 +14,7 @@ import type { RunningBackend } from 'toiljs/backend';
14
14
 
15
15
  import { loadConfig, type ResolvedToilConfig } from './config.js';
16
16
  import { renderEmails } from './emails.js';
17
+ import { AUTH_EMAILS_GENERATED_BASENAME, renderAuthEmails } from './auth-emails.js';
17
18
  import { generate, TOIL_SERVER_ENV_DTS } from './generate.js';
18
19
  import { prerenderStaticParams } from './ssg.js';
19
20
  import {
@@ -179,6 +180,20 @@ function serverImportsAuth(root: string, files: string[]): boolean {
179
180
  return false;
180
181
  }
181
182
 
183
+ /**
184
+ * Whether the built-in auth surface is on for this project: the `server.auth` config flag OR the
185
+ * escape-hatch `import 'toiljs/server/auth'` in a server entry. This is the SAME predicate
186
+ * `buildServer` uses to decide whether to inject `AuthController` (see `authOn` there); the email
187
+ * pipeline reuses it so `_auth_emails.ts` is generated exactly when the controller that calls
188
+ * `AuthEmail.*` is compiled in (a mismatch would be a missing-symbol compile error). Client-only
189
+ * projects (no `toilconfig.json`) are never auth-on.
190
+ */
191
+ function serverAuthEnabled(root: string, configAuth: boolean): boolean {
192
+ if (configAuth) return true;
193
+ if (!fs.existsSync(path.join(root, 'toilconfig.json'))) return false;
194
+ return serverImportsAuth(root, serverEntryFiles(root));
195
+ }
196
+
182
197
  /**
183
198
  * Builds the toilscript server target (which also regenerates `shared/server.ts` via
184
199
  * `--rpcModule`) when the project has one, signalled by a `toilconfig.json` at the root. This
@@ -581,6 +596,7 @@ function watchServer(cfg: ResolvedToilConfig, watcher: ViteDevServer['watcher'])
581
596
  // Recompile emails/*.tsx -> the generated module before the server build,
582
597
  // so editing an email template hot-reloads like any other server change.
583
598
  renderEmails(cfg)
599
+ .then(() => renderAuthEmails(cfg, serverAuthEnabled(root, cfg.auth)))
584
600
  .then(() => buildServer(root, cfg.auth))
585
601
  .then(() => process.stdout.write(pc.green(' ✓ ') + pc.dim('server rebuilt') + '\n'))
586
602
  .catch((e: unknown) =>
@@ -599,9 +615,10 @@ function watchServer(cfg: ResolvedToilConfig, watcher: ViteDevServer['watcher'])
599
615
  const isServerSource = (file: string): boolean =>
600
616
  file.endsWith('.ts') &&
601
617
  !file.endsWith('.d.ts') &&
602
- // `_emails.ts` is GENERATED by renderEmails on every rebuild; reacting to
618
+ // `_emails.ts` / `_auth_emails.ts` are GENERATED on every rebuild; reacting to
603
619
  // our own output would loop forever (rebuild -> write -> rebuild -> ...).
604
620
  path.basename(file) !== '_emails.ts' &&
621
+ path.basename(file) !== AUTH_EMAILS_GENERATED_BASENAME &&
605
622
  dirs.some((dir) => file === dir || file.startsWith(dir + path.sep));
606
623
  const isEmailSource = (file: string): boolean =>
607
624
  /\.(tsx|jsx)$/.test(file) && (file === emailsDir || file.startsWith(emailsDir + path.sep));
@@ -863,6 +880,9 @@ export async function dev(opts: ToilCommandOptions = {}): Promise<ViteDevServer>
863
880
  if (hasServer) process.stdout.write(pc.dim(' building the server (toilscript)…') + '\n');
864
881
  // Compile emails/*.tsx -> generated server module BEFORE toilscript builds it in.
865
882
  await renderEmails(cfg);
883
+ // Built-in auth: (re)generate `<server>/_auth_emails.ts` (defaults + any emails/auth-*.tsx
884
+ // overrides) so the injected AuthController's `AuthEmail.*` senders compile in.
885
+ await renderAuthEmails(cfg, serverAuthEnabled(cfg.root, cfg.auth));
866
886
  // Generate the client codegen first so the SSR slots pre-pass can load the route graph, then
867
887
  // emit the server-importable `<server>/_ssr/<name>.slots.ts` BEFORE the server build so its
868
888
  // `render` can import them. Dev reuses the prior build's shell (or the template) for the HASH;
@@ -988,6 +1008,9 @@ export async function build(opts: ToilCommandOptions = {}): Promise<void> {
988
1008
  process.stdout.write(pc.dim(' building the server (toilscript)…') + '\n');
989
1009
  // Compile emails/*.tsx -> generated server module BEFORE toilscript builds it in.
990
1010
  await renderEmails(cfg);
1011
+ // Built-in auth: (re)generate `<server>/_auth_emails.ts` (defaults + any emails/auth-*.tsx
1012
+ // overrides) so the injected AuthController's `AuthEmail.*` senders compile in.
1013
+ await renderAuthEmails(cfg, serverAuthEnabled(cfg.root, cfg.auth));
991
1014
  // Generate the client codegen (`.toil/globals.ts`, `.toil/index.html`, …) NOW — before the
992
1015
  // server build — so the SSR slots pre-pass below can load the route/layout module graph and
993
1016
  // render the opted-in routes.