Skip to content

Commit 35d5060

Browse files
refactor(plugin-auth): move the createAuthInstance body into auth-manager-auth-instance.ts (#25224 cut 14) (#25566)
<!-- claude-projects-attribution: {"github_login":"os-sales"} --> _Requested by **Sales** · [project thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuMjbPDrsigsyqoKsV4WZQMz)_ Part of #25224 Clause-②: no Metadata-protocol: none Ruling-ref: 6348891160, 6364006498 The basis for the `Clause-②: no` line: this is a move plus one comment migration. No accept set, route, refusal, code or answer changes, and the published surface is measured unchanged: - `@objectstack/plugin-auth`'s `dist/index.d.ts` and `dist/index.d.mts` are raw byte-identical to base (0 diff lines, so the union-order normalisation has nothing to do). The positive control is the one ruling `6348891160` asks for. - Its ESM and CJS entries export the same 159 names at base and at head. `readDisableSignUpEnv`, which this cut exports in place inside the package, is not among them. The `.d.ts` bar is ruling `6348891160` item 1 (on #25222, covering this card). Ruling `6364006498` is Sales's ruling A on this card. This is the sixth cut it applies to. Cut 14 of the `auth-manager.ts` split: **the rest of `createAuthInstance`, which is its whole body**. It is the last of the three `createAuthInstance` slices the seat set (`hooks.after`, then `hooks.before`, then the rest of the method). #25224 stays open for the later cuts. This follows the amended claim `6377759458`, which amends `6376168919` on the file cut 13 left (#25548, landed note `6377004954`). The shape is #23050's method move, the one cuts 1 to 11 used; cuts 12 and 13 moved closures inside this method. Branch: `claude/project-thread-lg3wrj`, the harness-pinned branch for this session, restarted from `origin/main` after #25548 merged and rebased onto `45f996231e` when #25541 merged. It names no issue, so the card relation is this body's first line. `auth-manager.ts` goes from 7,807 to 7,122 lines. The cut is +926 / −749 over 3 files: 1,675 changed lines, under the 3,000-line line. One of the three files is a path reader outside the move, so `check-governed-merges.mjs` ran on the trial file list before the cut: NOT governed (0 of 3 paths hit the register), and `--branch HEAD` agrees. One commit: `b2bbcd6cac` `refactor(plugin-auth): move the createAuthInstance body into auth-manager-auth-instance.ts`. ## The move | moved | base lines | proof lines | tokens | members it reads | |---|---|---:|---:|---:| | the body of `createAuthInstance` | `:1690`–`:2415` | 728 | 2,616 | 45 methods, 2 fields | The lines are base `45f996231e`. The 728 proof lines are the body with its braces (`:1689`'s `{` to `:2416`'s `}`). - **What it is:** `createAuthInstance` (`:1689`, `private async`, annotated `Promise<Auth<any>>`) builds the better-auth instance. `getOrCreateAuth()` calls it once per build (`:1669`, `this.createAuthInstance().then(…)`). - **What the body does, in order** (all of it moves, with its comments): the deferred `better-auth` and `better-auth/api` imports, the plugin list and the password hasher, then one config literal (secret, origin and base path, app name, database, the `user`, `account` and `verification` model configs, the social providers, `emailAndPassword` with its reset-password and sign-up callbacks, the e-mail verification block, `session`, rate limiting and secondary storage, the plugins, the composed database hooks, the global `hooks.before` and `hooks.after` arrows that cuts 12 and 13 left in place, `onAPIError`, the trusted origins and `advanced`), the `betterAuth()` call, and the wait on `auth.$context` before the instance is returned. - **Where it goes:** a new module, `packages/plugins/plugin-auth/src/auth-manager-auth-instance.ts` (861 lines). The body becomes the body of `export async function createAuthInstance(this: AuthInstanceHost): Promise<Auth<any>>`, re-indented two spaces (one level) and otherwise unedited. The module header gives the reasoning, in the form the thirteen earlier `auth-manager-*.ts` modules use. - **What stays:** `createAuthInstance` keeps its place, its docblock and its `private` modifier. Its body is now: ```ts private createAuthInstance(): Promise<Auth<any>> { // [#25224 cut 14] The body moved to `auth-manager-auth-instance.ts` (see `AuthInstanceHost`). const readConfig = () => this.config; const readIdpLocale = () => this.idpLocale; const host: AuthInstanceHost = { assertAccountNotLocked: (...a) => this.assertAccountNotLocked(...a), // … one closure per method, alphabetical, 45 in all, and: get config() { return readConfig(); }, get idpLocale() { return readIdpLocale(); }, }; return createAuthInstance.call(host); } ``` ## The seat's bars **Body.** - The body is the same TypeScript token sequence at base and in the module function: 728 lines, 2,616 tokens. Every line is the base line minus exactly two spaces. The method takes no parameters, and the base method, the stub and the function carry the same return annotation, `Promise<Auth<any>>`. - **`async` moves from the method to the function.** The stub is not `async`, and it returns `createAuthInstance.call(host)`, the function's own promise, unchanged. `getOrCreateAuth()` chains `.then(…)` on that promise exactly as before. The two reader closures, the host literal and the `.call` cannot throw before the promise exists, and a throw inside the body is still a rejection of it. - **No `arguments`, `new.target` or `super`** (0 of each), and no bare `this`: the body's only `this` uses are member reads `this.X`. Every method read is a direct call, and the body writes no member. No `this` sits inside a non-arrow function, so every callback the body hands better-auth reads the same receiver the body does. **Receiver.** - The body's `this` was the `AuthManager` instance. It is now the host. - `AuthInstanceHost` names exactly the 47 members the body reads, no more, each typed as the class member (`AuthManager['x']`). - 45 are methods, so each goes as a late-bound closure, `(...a) => this.x(...a)`. The method runs on the manager and is looked up when the body calls it, so a spy or double set on the manager is still the one the body reaches, including from the callbacks better-auth runs long after the function returns. - Two are fields, and both go as getters over a reader closure, `readonly` on the interface; the body writes neither: - `config`, which the class reassigns after construction (`setRuntimeBaseUrl`, `:3975`, writes it at `:3987`; `applyConfigPatch`, `:3998`, at `:4068`); - `idpLocale` (`:4167`, `private readonly`, an `IdpLocaleSync`), which is not reassigned, as every field this series carries goes (the same pair `composeDatabaseHooks`' stub hands its body as getters, `:7030`). - **Function-valued reads, disclosed** (the way #25516 disclosed `resolveKernelService`): the body calls `this.idpLocale.stage(data, ctx)` once (`:1839`), and `this.config.logger?.info?.(m, meta)` once (`:1843`, inside the `logInfo` arrow it hands on). Each receiver is the object the getter returns, the manager's current one, so each is looked up and called on the same object, at the same moment, with the same `this`, as before. - `hasExistingUserFor` and `isBootstrapCreation` read private statics. They stay in the class, per ruling A, and the body reaches them as members. The body reads no `AuthManager.X`, so the module imports the class as a type only. **The two hook arrows.** `hooks.before` and `hooks.after` move with the literal, unedited. Each builds its own host from `this`, which is now this host: each of their closures calls this host's closure, which calls the manager's method, and their `config` getters read this host's getter, which reads the manager's field. So they reach the same member, at the same moment, as before. Their imports (`globalBeforeHook`, `globalAfterHook` and the two host types) move to the new module with them. **One top-level helper, exported in place.** The body reads one top-level declaration of `auth-manager.ts`: `readDisableSignUpEnv` (`:384`, once). Per ruling `6364006498` (A), it gets `export` in place, in this cut, the first whose body reads it, and the module imports it by value from `./auth-manager.js`. The binding proof checks that the head declaration is the base one with `export ` in front and nothing else changed, and that the base and head reads resolve to it. `src/index.ts` names its `auth-manager.ts` exports one by one and does not name it, so nothing is published. **Host lifetime.** The host is built once per call of `createAuthInstance`, which `getOrCreateAuth()` makes once per build. This is what every method stub in this series does. Nothing the body reads is captured early: the closures look each method up on the manager at call time, and the getters read the fields when the body, or a callback it handed better-auth, reads them. **Readers.** The decision letters are read on the merge base and on the head below: 8 drop, as expected, and one entry judgment is disclosed. Tenant census and symbol-anchor output are byte-identical at both ends, and the full plugin-auth suite passes at both ends. The one path reader whose text names where the moved lines live is migrated in this commit. ## Imports and evaluation order Ten imported values leave `auth-manager.ts`, because the body was their last reader there: - `PLATFORM_IDP_PROVIDER_ID` and `refuseImplicitAccountLink` (the `implicit-account-linking.js` block keeps `type LinkingAuthContext`); - `readEnvWithDeprecation` (the `@objectstack/types` block keeps its other names); - the whole `account-invitation-marker.js` line (`readAccountInvitation`, `settleImportResetDelivery`) and the whole `client-address-vendor.js` line (`vendorClientAddressOptions`); - `AUTH_USER_CONFIG`, `AUTH_SESSION_CONFIG`, `AUTH_ACCOUNT_CONFIG` and `AUTH_VERIFICATION_CONFIG` (the `auth-schema-config.js` block keeps its other names). The cut 12 and cut 13 import lines (`globalAfterHook`, `globalBeforeHook` and the two host types) and their comments are replaced by one comment and one line: `import { createAuthInstance, type AuthInstanceHost } from './auth-manager-auth-instance.js'`. `audiencePermitsSelfRegistration`, `resolveEmailVerificationRequirement`, `isPlaceholderEmail` and the `better-auth` types have other readers, so both files import them. esbuild drops a type-only import, so a module whose last value import leaves `auth-manager.ts` can now be evaluated later. The order was measured rather than argued: - **The ES modules, at run time.** A loader hook logged each ES module as its body ran while `dist/index.mjs` loaded, at base and at head. 171 modules evaluate at both, and the first 117 are the same set at both. One block moves: the 17 modules `@better-auth/core/context` loads (16 files of `@better-auth/core`'s `context`, `async_hooks`, `error`, `db`, `env` and `utils` directories, and `better-call`'s `error`) ran first at base and now run after the 100 others in that set (`zod`'s v4 modules, `@objectstack/spec`'s `security`, `api` and `data` entries, `pg-connection-string` and `@objectstack/types`). They follow the bundle's first `@better-auth/core/context` import, which is `account-invitation-marker.ts`'s at both, and that module's segment now sits later in the bundle (line 196 at base, 477 at head). From position 118 on, the order is identical. Their top levels are constants, classes and function declarations, plus `defineErrorCodes`, `createLogger()` and the `env` proxy; the only load-time reads are of `process.env` (`NODE_ENV`, `TEST`, the default logger's colour depth), and the `better-auth:global` slot is touched only when a function is called. None of the 100 writes `process.env` or that slot. The bundle's own body runs last, after all 170, at both. - **The CommonJS entry.** A `Module._load` log for `dist/index.js` gives 127 first loads at both, the same apart from `@better-auth/core/dist/context/index.mjs`, which now loads last instead of eighth from last. - **plugin-auth's own modules.** A walk of the bundle's top level and its eager `init_*` calls finds three that run later: `implicit-account-linking.ts` (one place), `client-address-vendor.ts` and `account-invitation-marker.ts`, whose value imports left `auth-manager.ts` with the body. Their top levels are string constants, one arrow constant (`authContextOf`), and two `defineRequestState(() => null)` calls, each of which makes its own frozen key object and touches no shared state until it is read inside a request. No importer reads any of their bindings at load time: all 14 references in the 6 importing files are inside functions. - The new module's own top level is imports, one interface and one function declaration. Its value import of `auth-manager.ts`, for `readDisableSignUpEnv`, and `auth-manager.ts`'s import of it form a cycle with nothing read at load time. ## The decision-letter layer: −8, as expected `check-adr-anchors`, measured on the merge base and on the head. The gate exits 0 at both. | point | anchored files | citations | files | decision letters | |---|---:|---:|---:|---:| | merge base `45f996231e` | 84 | 52,280 | 6,688 | 1,946 | | head `b2bbcd6cac` | 84 | 52,280 | 6,689 | 1,938 | - The eight letters are in the body's comments: ADR-0131 D7 (`:2000`, `:2114`), ADR-0069 D4 (`:2142`), ADR-0069 D2 (`:2190`, `:2214`), ADR-0093 D2 (`:2222`) and ADR-0135 D6 (`:2347`, `:2351`). They leave `auth-manager.ts`, which is anchored, for a module that is not. Their citations still resolve, so the citation count does not move. - **One judgment, disclosed: no entry is owed for ADR-0093 D2.** The letter at `:2222` is in the comment on the `databaseHooks: this.composeDatabaseHooks(this.config.databaseHooks)` wiring, which says D2 makes the database-hook seam the single owner of the user-lifecycle invariants. The `auth-manager.ts` entry's D2 paragraph describes `settleMembership`, which stays, and its two seams (`user.create.after` and `session.create.before`), which are database hooks that cut 4 moved to `auth-manager-database-hooks.ts` with their own entry. It does not describe the wiring line, and no other entry names it. The ADR-0108 paragraph (the organization roles map) is not in the body. So, per the seat's bar, no entry is added for the new module. If the seat reads the wiring as part of the D2 mechanism, the remedy is an entry for the new module carrying the D2 paragraph verbatim, cut 4's precedent, in this PR. ## Path readers One reader outside the move names where the moved lines live, and it follows the body in this commit: - **`auth-email-locale.test.ts`**: the two population comments (the docblock at `:861` and the in-test note at `:1126`, head numbering) that name the files the five `sendTemplate` sites live in now name `auth-manager-auth-instance.ts` (the body of `createAuthInstance`) among them. No assertion, count or pattern changes. Read, and not edited: - **`api-error-code.pin.test.ts`**: the body carries no `new APIError(` site, so `authManagerFiles` is not owed the new module. Its sum stays 30, as at base. - **`scripts/check-dispatcher-error-vocabulary.mjs`**: the body has no `new APIError(` or `APIError.from(` site and no live member, so nothing in the gate moves. It exits 0 at both, 56 sites found and 56 classified at both, and only its scanned-file count moves (3,430 → 3,431). `--self-test` is among the derived gates below. - **The tenant-audit census.** No census site moves: the body has no engine write. `check-tenant-audit-census` exits 0 at both with no `--write`, with byte-identical output. Its `--json` document has 238 sites at both and 0 per-site differences with line numbers ignored. 2 sites are in `auth-manager.ts` at both (each 685 lines earlier at head, the cut's net), 0 are in the new module, and 0 are unresolved or unledgered. Only `scannedSources` (751 → 752) and `measuredAt` move, so neither census document is edited. - **`scripts/measure-durability-swallow-family.mjs`** (a measurement, not a gate): 77 members and 84 quiet rows at both, identical with line numbers ignored (one member's write line, in `observeFirstMemberships`, which stays, moves 5,177 → 4,492). `files` moves 3,480 → 3,481, and `tryStatements` (3,645) is the same. **One statistic moves, and I traced it:** `droppedNotAwaited` goes 233 → 234 (`delete` 149 → 150). It counts write-named calls that are not awaited inside a `try` block and the same-file helpers that block calls, walked by name, each name once, at most four levels deep. The `try` in `linkingContext` (base `:4355`) walks `getOrCreateAuth`, then `createAuthInstance`. At base the walk entered the body and reached `isOperatorProvisioning` at depth 4, so `prunePendingOperatorProvisioning` sat at depth 5, past the limit. At head the walk enters the stub, whose host literal lists the members alphabetically, and reaches `isOperatorProvisioning` at depth 3. So `prunePendingOperatorProvisioning` (`:4923`, which stays) is now walked, and its `this.pendingOperatorProvisioning.delete(key)` is counted. That call is a synchronous `Map` delete, not a write, and the code is unchanged. A logged copy of the instrument, run on the base and head trees and then removed, shows this is the only dropped call that differs (233 at base, 234 at head). Membership and the quiet rows, which are what the measurement reports, do not move. - **`check-auth-mount-ledger.mjs`** reads only the `basePath` declaration in `auth-manager.ts`, which stays. **`auth-manager-base-path.test.ts`** reads `auth-manager.ts` for code lines carrying `'/api/v1/auth'`; the body has one only in a comment (`:1814`). - **The plugin-factory scans** in `better-auth-schema-parity.test.ts` and `managed-extension-fields.test.ts` match `const { X } = await import('better-auth/plugins…' | '@better-auth/…')`. The body's two dynamic imports are `better-auth` and `better-auth/api`, neither a factory. At head the scanned shape matches 16 times in `auth-manager.ts`, as at base, and 0 times in the module. Both suites pass at head. - **`rate-limit-storage-isolation.test.ts`** walks the import graph from `rate-limit-storage.ts`, which reaches neither file. It passes at head. - **Prose** elsewhere that names `auth-manager.ts` for code now in the module (for example the `NODE_ENV`-gated trusted-origins substitution named in `packages/cli/test/serve-node-env-production-default.e2e.test.ts`) reads no file and is not edited, as cuts 12 and 13 left the prose that names the before-hook. - **Every symbol anchor into the file.** Before the cut, every `auth-manager.ts#symbol` anchor in the tracked tree outside changelogs was mapped with `symbolSegmentResolution` from `scripts/symbol-anchors.mjs`. There are 29, and all 29 are `declaration`-class at base, at base with the body blanked, and at head. Five of their symbols occur as a token on a line of the body: `secondaryStorage` (ADR-0127 `:114`), `composeDatabaseHooks` (the access-security checklist area `:2419`), `isBootstrapCreation` (identity-auth `:1810`), `readDisableSignUpEnv` (identity-auth `:1901`) and `requireEmailVerification` (identity-auth `:2004`). Each resolves to its declaration, which stays, at all three readings; `readDisableSignUpEnv`'s declaration (`:384`) gains only `export`. ## Proof Builds and suites ran through `os-verify-lock`, and every exit code was captured before any pipe. Base `45f996231e`. A full `turbo run build` ran first. Then `plugin-auth` was built and its suite run at base, and built and run again at head, on the same dependency dists. **1. The moved text.** - **Token identity:** the base method body and the module function body are the same TypeScript token sequence (scanner tokens, kind and text, trivia skipped, each template literal re-scanned at its substitutions as the parser does): 728 lines and 2,616 tokens, each line the base line minus two spaces. - **The stub's shape**, checked by the same run: not `async`, the same docblock, modifiers, parameters and return annotation as the base method, the two reader closures, one host literal whose keys are exactly `AuthInstanceHost`'s, alphabetical, whose 45 method values are each `(...a) => this.<key>(...a)` and whose `config` and `idpLocale` are getters over the readers, then `return createAuthInstance.call(host)`, and nothing else. The interface types every member `AuthManager['x']`, and exactly the two getter fields are `readonly`. - **Binding identity:** a second proof walks all 672 identifiers of the body at base and in the module, in order, and resolves each with the TypeScript checker (the module's `./auth-manager.js` resolved to the head file, where the in-place export lives). All 672 resolve the same way at both ends: - 402 to a declaration inside the body, the same declaring identifier by position; - 108 to receiver members (`AuthManager` at base, `AuthInstanceHost` at head); - 19 to imports with the same specifier and imported name, `readDisableSignUpEnv` among them; - 14 to the same declaration in `auth-manager.ts`: seven `AuthManagerOptions` members read through `this.config` (`databaseHooks`, `emailService`, `logger` and its `info`, `rateLimit`, `rateLimitStorage` and `secondaryStorage`); - 129 to no declaration: globals and property names on untyped values. None resolves to an unexported top-level declaration of `auth-manager.ts` or to a top-level declaration of the module. - **Negative controls:** each proof reads the module text, and each control changes it in memory only; the file is untouched. - Token proof: `betterAuth(` changed to `betterAuth?.(` fails the token and line checks, and the run exits 1. - Binding proof: the module's `placeholder-email` import pointed at another specifier gives 1 difference, and the run exits 1. The same import shadowed by a module-level `const` gives 1 difference and reports the module top-level read, and exits 1. Run without being told about the in-place export, it reports the base read of an unexported helper, and exits 1. - **An independent reading:** `git diff --color-moved=plain --color-moved-ws=allow-indentation-change 45f9962 b2bbcd6` over the two source files marks 734 of the 744 deleted lines and 768 of the 920 added lines as moved. - The 10 unmoved deletions are two import-name lines (`refuseImplicitAccountLink,`, `readEnvWithDeprecation,`), the six comment lines above the cut 12 and cut 13 import lines, `function readDisableSignUpEnv(): boolean | undefined {` (now with `export`) and `private async createAuthInstance(): Promise<Auth<any>> {` (now without `async`). - The other added lines are the module header, its import lines, the host interface and its docblock, the function signature and docblock, the stub's comment, readers, host literal and `return`, and the new import comment and line. **2. `.d.ts` and exports (ruling `6348891160` items 1 and 2).** | file | base and head | raw diff lines | |---|---|---:| | `dist/index.d.ts` raw | `1b3a48357d137155de33104277667a922aab62df73b418b03894c56faaacd0ba` | 0 | | `dist/index.d.ts` normalised | `cee7303ccdfe72794efd588c85b628419d4253d730b5a0c5a3f1cdb8dddb4443` | | | `dist/index.d.mts` raw | `b5e8dc982b634f0a5108b1b533626a68767f2da5a56f72dba801059b149e2872` | 0 | | `dist/index.d.mts` normalised | `562d0a4ce656f97aeb937541482cdf531b61d7c75a005918784bf0a52d032dfc` | | - The normaliser, verbatim (the ruling's one-liner): `node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum`. - The raw files are byte-identical, so no union-order swap occurs: items 1(b) and 1(d) hold with nothing to account for. - **Positive control:** the head `dist/index.d.ts` with one private member made public (`private createAuthInstance;` → `createAuthInstance;`, line 1712, a one-line change) hashes raw `35b18682171cd394898c9e56bc8d5272ccf20aeff0d1966fc568cb5e566a08df` and normalised `e69c1b0157b45e48bbc16bd64eb939abf9be33ccb31553485df93ef05aac6fc3`. Both differ from the readings above. - **Export lists:** ESM `dist/index.mjs` and CJS `dist/index.js` each have 159 names at base and at head, the same list (the sha256 of the sorted names is `3abb126f5babb701…` on all four). `readDisableSignUpEnv`, `createAuthInstance` and `AuthInstanceHost` are not among them, and `dist/index.d.ts` names neither `readDisableSignUpEnv` nor `AuthInstanceHost`. - **The bundle:** the same 18 files in `dist/` at both, plus the two `.build-input-hash` stamps the build writes from its inputs. Only `index.js`, `index.mjs` and their two `.map` files differ, as a move of code inside the bundle must. `tsup` bundles the new module into the root entry (`splitting: false`). **3. Tests and lint.** - `pnpm exec vitest run --maxWorkers=3` in `packages/plugins/plugin-auth`: base `Test Files 191 passed (191)`, `Tests 3620 passed | 10 skipped (3630)`, exit 0. Head: the same counts, exit 0. - `pnpm --filter @objectstack/plugin-auth typecheck` (both `tsc` projects and `check:test-typecheck`): exit 0. `pnpm --filter @objectstack/runtime typecheck`: exit 0. - `eslint` over the 3 files: exit 0. **4. The censuses, the measurement and the anchors, at base and at head.** - The tenant-audit census, as above: byte-identical gate output, 238 sites at both, 0 per-site differences line-blind, 0 unresolved and 0 unledgered at both. - The durability measurement, as above, with its one moved statistic traced. - These checkers were run by hand at base and at head, because `dispatch-gates` does not derive the ADR one. All six exit 0 at both. Five print byte-identical output at both (`cmp` clean): - `check-adr-symbol-anchors`: 2,384 anchors across 142 records, 466 symbol (440 declaration, 26 literal); - `check-scripts-symbol-anchors`: 4,070 anchors; - `check-spec-docblock-symbol-anchors`: 5,076 anchors; - `check-system-context-census`: 149 elevation read sites; - `check-platform-checklist`: 16 areas, 329 items. The sixth, `check-adr-anchors`, differs only in the file count and the decision letters, as in the table above. **5. Gates.** - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives 60 commands for the 3 paths. All 60 ran at head after the full build, and all 60 exited 0. - `--ran` over the record with each exit code: 60 derived, 60 run, 0 NOT-MEASURED, a derived zero. `--tier`: no path-derived mandate. - `check-governed-merges.mjs`: on the trial file list before the cut and `--branch HEAD` after the commit, both read NOT governed (0 of 3 paths hit the register), 1,675 changed lines. - **Docs drift** (`node scripts/docs-audit/affected-docs.mjs --json 45f9962`, exit 0): 8 pages, all name matches of names the moved code carries (the `OS_CORS_ORIGIN` and `CORS_ORIGIN` literals, `isAuthGateActive` and `resolveActor` as host members, and `sys_oauth_resource` in a comment). None names `auth-manager.ts`, and the code that reads those names is unchanged, so no doc edit is owed. 3 of them are release notes (17.3, 18.0, 18.1), owned by the release, and not edited. - **Serial constraints** (in the claim, and re-read at 00:52Z before this PR): 11 PRs are open, and none touches `auth-manager.ts`, the new module's path, `auth-email-locale.test.ts` or a reader named above. One opened after the claim touches `plugin-auth`: #25563 edits `auth-manager-database-secret.ts` and `auth-manager.test.ts`, neither a file of this cut, and reads no source by path; `resolveAuthSecret`, which the body calls, is reached through a late-bound closure, so a change to it lands the same way at both. The Version Packages PR #24876 touches `plugin-auth`'s `package.json`, its `CHANGELOG.md` and changesets only. #25541, which the cut 13 claim named, merged as this base; its hunks in the file are outside the body. `origin/main` has moved 6 merges past this base, to `041a120b61`; none touches `plugin-auth`, `scripts/adr-anchors/` or a reader named above. ## Changeset None: `skip-changeset`, per ruling `6348891160` item 4. The published declarations and export lists are unchanged, and the bundle's bytes move only because code moved inside it. --- _Generated by [Claude Code](https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr)_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1361a5a commit 35d5060

3 files changed

Lines changed: 926 additions & 749 deletions

File tree

‎packages/plugins/plugin-auth/src/auth-email-locale.test.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -858,8 +858,9 @@ describe("#14641 — an invitation reads the INVITEE's own sys_user.locale", ()
858858
*
859859
* ⚠️ POPULATION of the class claim these blocks close, stated rather than
860860
* implied: the auth mail surface is the five `sendTemplate` call sites in
861-
* `auth-manager.ts` and `auth-manager-email-sms-delivery.ts` (the body of the
862-
* change-email notice) — `IEmailService` declares exactly two delivering
861+
* `auth-manager.ts`, `auth-manager-auth-instance.ts` (the body of
862+
* `createAuthInstance`) and `auth-manager-email-sms-delivery.ts` (the body of
863+
* the change-email notice) — `IEmailService` declares exactly two delivering
863864
* members (`send`, `sendTemplate`), plugin-auth's only `.send(` calls are the
864865
* SMS service's, and no other file under `plugin-auth/src` calls either.
865866
* Those five are the same five `driveAllFive` above drives and `TEMPLATES`
@@ -1122,9 +1123,9 @@ describe('#15106 — the CLASS claim: all five auth sends read the recipient col
11221123
});
11231124

11241125
it('every one of the five sends is written in the stored language of its own recipient', async () => {
1125-
// ⚠️ POPULATION: the five `sendTemplate` sites in `auth-manager.ts` and
1126-
// `auth-manager-email-sms-delivery.ts` — the same five `driveAllFive`
1127-
// drives and `TEMPLATES` names, and the whole of
1126+
// ⚠️ POPULATION: the five `sendTemplate` sites in `auth-manager.ts`,
1127+
// `auth-manager-auth-instance.ts` and `auth-manager-email-sms-delivery.ts`
1128+
// — the same five `driveAllFive` drives and `TEMPLATES` names, and the whole of
11281129
// plugin-auth's mail surface (see this section's header). This is the pin
11291130
// that closes the class; the per-send pins above only cover one member.
11301131
//

0 commit comments

Comments
 (0)