Repository navigation
Commit f66c440
Fixes #22398
Clause-②: yes (widening)
## What this changes
Eight `plugin-auth` doors read the session through better-auth
in-process by a route other than `auth.api.getSession`, so the
cookie-conditional rule from #22258 (`inProcessSessionReadInput`,
`@objectstack/types`) did not reach them. Each read renewed a session
older than `updateAge` and staged the renewed cookie on a response the
door threw away: the split session. The same rule now applies at every
one of those reads, spelled for its call shape:
- **Handler re-dispatches** (a `/get-session` lookup whose JSON is all
the door keeps, or a bridge's forward to a better-auth route whose
status and body are all it keeps): a new helper,
`in-process-redispatch.ts`, adds `disableRefresh=true` to the
re-dispatched URL when the caller's headers carry a session cookie.
better-auth 1.7.3 reads it on both kinds of re-dispatch: `/get-session`
declares it (`getSessionQuerySchema`, coerced), and `getSessionFromCtx`
(used by `sessionMiddleware` and by `AuthManager`'s own before-hooks)
spreads the route's `ctx.query` into its read; none of the re-dispatched
routes declares a query schema that would strip it.
- **In-process vendor endpoint calls** (`addMember`, `setPassword`,
`createOAuthClient`): each spreads
`inProcessSessionReadInput(request.headers)` in place of `headers:
request.headers`, so a cookie request hands `query: { disableRefresh:
true }`, which `getSessionFromCtx` passes into the endpoint's session
read. None of the three endpoints declares a query schema.
Cookie request: no in-process read renews, no cookie is set. Bearer-only
request: unchanged, still renews to `now + expiresIn`, still no cookie.
`inProcessSessionReadInput`'s semantics are untouched (no
`packages/types` change); `carriesSessionCookie` is reused for the URL
helper.
Sites changed (line numbers at this head):
| Site | Door(s) | Spelling before | Now |
|---|---|---|---|
| `register-sso-provider.ts:64` | `/admin/sso/register`,
`/admin/sso/register-saml` | `handle(new Request(sessionUrl, …))`
(`/get-session`) | `inProcessRedispatchUrl(sessionUrl, h)` |
| `register-sso-provider.ts:210` | `/admin/sso/register` | inner
`/sso/register` (OIDC) | `inProcessRedispatchUrl(innerUrl, headers)` |
| `register-sso-provider.ts:308` | `/admin/sso/register-saml` | inner
`/sso/register` (SAML) | same |
| `register-sso-provider.ts:413` |
`/admin/sso/request-domain-verification` | inner route |
`inProcessRedispatchUrl(rw.innerUrl, headers)` |
| `register-sso-provider.ts:465` | `/admin/sso/verify-domain` | inner
route | same |
| `send-verification-email.ts:66` | `/send-verification-email` (no email
in body) | `/get-session` re-dispatch |
`inProcessRedispatchUrl(sessionUrl, h)` |
| `send-verification-email.ts:135` | `/send-verification-email` | inner
route | `inProcessRedispatchUrl(sendUrl, headers)` |
| `organization-add-member.ts:176` | `/organization/add-member` |
`authApi.addMember({ body, headers })` |
`...inProcessSessionReadInput(request.headers)` |
| `set-initial-password.ts:76` | `/set-initial-password` |
`authApi.setPassword({ body, headers })` | same |
| `auth-plugin.ts:3173` | `/sys-oauth-application/register` |
`authApi.createOAuthClient({ body, headers })` | same |
The four SSO bridges and the send-verification wrapper are the shared
helpers the cloud auth proxy also mounts, so both mount points carry the
rule. `SetPasswordCapableApi.setPassword` (exported) gains an optional
`query` member; the `AddMemberCapableApi` shape (not exported from the
entry) gains the same.
Also corrects PR #22367's H5 table, as the card says: the
`/admin/sso/register` split was not `gateAdmin`'s alone (its
`/get-session` re-dispatch and the inner `/sso/register` read renewed
too).
## The `packages/**` enumeration
Census over every non-test source under `packages/**` (7,970 files;
`*.test.*`, `*.spec.*`, `__tests__/`, `test(s)/` and `*-test-support.ts`
excluded; tests are not doors), by TypeScript AST at this head:
- **A** — a method call on ANY receiver whose text contains `api`
case-insensitively (`authApi.`, `api.`, `auth.api.`, `(authApi as
any).`, `(await m.getApi()).`) with an argument naming `headers`: **18**
hits.
- **B** — a call whose callee is named `handle`, `handleRequest` or
`handler` on any receiver (the better-auth universal-handler
re-dispatch): **57** hits, 19 of them better-auth.
- **C** (control) — any call to a method named `getSession`, whatever
the receiver and argument spelling: **40** hits.
- **Control for A's receiver filter** — every call whose argument is an
object literal with a `headers` member on a receiver NOT containing
`api`: `fetch`/`fetchImpl`/`resilientFetch` (network clients),
`resolveAuthzContext` (takes an injected `getSession`, rows below), zod
`object`/`strictObject` schema builders, the verify harness's HTTP
`api(` helper, and other non-auth helpers. No in-process better-auth
call outside A.
Verdicts: **converted (#22258)** (already carries
`inProcessSessionReadInput`, PR #22367 / PR #22396); **fixed here**
(this PR); **not renewing** (with the reason); or **not better-auth**.
| # | Hit (file:line) | Spelling | Verdict |
|---|---|---|---|
| A1 | `plugin-auth/src/auth-plugin.ts:3173` |
`authApi.createOAuthClient({ …headers })` | **fixed here** |
| A2 | `plugin-auth/src/organization-add-member.ts:176` |
`authApi.addMember({ …headers })` | **fixed here** |
| A3 | `plugin-auth/src/set-initial-password.ts:76` |
`authApi.setPassword({ …headers })` | **fixed here** |
| A4–A7 | `plugin-auth/src/auth-plugin.ts:2465`, `:2528`, `:2595`,
`:2913` | `authApi.getSession(inProcessSessionReadInput(…))` | converted
(#22258) |
| A8 | `plugin-auth/src/list-user-invitations-verification.ts:195` |
`APIError.fromStatus('BAD_REQUEST', { message: '…headers…' })` | not a
better-auth call (receiver `APIError`, `headers` is inside a message
string) |
| A9 | `cloud-connection/src/cloud-connection-plugin.ts:209` |
`api.getSession(inProcessSessionReadInput(rawReq.headers))` | converted
(#22258) |
| A10 | `cloud-connection/src/marketplace-install-local-plugin.ts:2624`
| `api.getSession(inProcessSessionReadInput(…))` | converted (#22258) |
| A11 | `plugin-hono-server/src/current-user-endpoints.ts:412` | same |
converted (#22258) |
| A12 | `plugin-webhooks/src/webhook-outbox-plugin.ts:483` | same |
converted (#22258) |
| A13 | `rest/src/rest-server.ts:3224` | same | converted (#22258) |
| A14–A15 | `runtime/src/http-dispatcher.ts:1365`, `:1445` | same |
converted (#22258) |
| A16 | `runtime/src/security/resolve-session-principal.ts:57` | same |
converted (#22258) |
| A17 | `services/service-datasource/src/admin-routes.ts:212` | same |
converted (#22258) |
| A18 | `services/service-storage/src/storage-service-plugin.ts:844` |
same | converted (#22258) |
| B1 | `plugin-auth/src/register-sso-provider.ts:64` | `handle(new
Request(…/get-session))` | **fixed here** |
| B2–B3 | `plugin-auth/src/register-sso-provider.ts:216`, `:313` |
`handle(innerReq)` (inner `/sso/register`, OIDC and SAML) | **fixed
here** (the `innerReq` URL, `:210` / `:308`) |
| B4–B5 | `plugin-auth/src/register-sso-provider.ts:413`, `:465` |
`handle(new Request(rw.innerUrl, …))` | **fixed here** |
| B6 | `plugin-auth/src/send-verification-email.ts:66` | `handle(new
Request(…/get-session))` | **fixed here** |
| B7 | `plugin-auth/src/send-verification-email.ts:141` |
`handle(innerReq)` | **fixed here** (the `innerReq` URL, `:135`) |
| B8–B12 | `plugin-auth/src/auth-plugin.ts:2567`, `:3059`, `:3085`,
`:3102`, `:3226` | `(req) => this.authManager!.handleRequest(req)`
passed to a bridge | not renewing: the handler a bridge re-dispatches
through; every request it receives is one of B1–B7 |
| B13–B14 | `plugin-auth/src/auth-plugin.ts:2861`
(`/admin/remove-user`), `:2937` (`/admin/has-permission`, delegated) |
`return await this.authManager!.handleRequest(c.req.raw)` | not renewing
behind the cookie: the vendor's Response is returned verbatim, so a
renewal's `Set-Cookie` reaches the browser |
| B15 | `plugin-auth/src/auth-plugin.ts:3265` | catch-all
`handleRequest(c.req.raw)` | not renewing behind the cookie: the
browser's own request, Response returned |
| B16 | `plugin-auth/src/auth-plugin.ts:3545` | OIDC discovery-document
`handler(req)` | not renewing: no session read |
| B17 | `plugin-auth/src/auth-manager.ts:5957` | `auth.handler(request)`
| the universal handler itself (`AuthManager.handleRequest`); whoever
calls it owns the Response (rows above) |
| B18 | `adapters/hono/src/index.ts:640` |
`authService.handleRequest(c.req.raw)` | not renewing behind the cookie:
forwards the browser's own request and returns `response.headers` |
| B19 | `runtime/src/domains/auth.ts:138` |
`authService.handleRequest(context.request)` | not renewing behind the
cookie: the dispatcher's auth domain answers with that Response |
| B20–B57 | 38 hits in `cli/bin`, `client`, `core` (hook dispatch,
memory job), `mcp` (transport), `objectql` (hooks), `plugin-hono-server`
(`adapter.ts:688`, `current-user-endpoints.ts:749`), `plugin-security`,
`qa/http-conformance`, `runtime` (route/liveness/domain handlers,
artifact jobs, instrumentation), `service-automation`,
`service-cluster(-redis)`, `service-job`, `service-queue`,
`service-realtime`, `service-settings`, `trigger-api` | job / queue /
hook / pubsub / route handlers | not better-auth |
| C | `cloud-connection/…/marketplace-install-local-plugin.ts:2794`,
`plugin-sharing/src/sharing-plugin.ts:941`,
`rest/src/rest-server.ts:3037`,
`runtime/src/security/resolve-execution-context.ts:165`,
`services/service-settings/src/settings-service-plugin.ts:300` |
`api.getSession(inProcessSessionReadInput(h))` (argument not spelled
`headers`, so A does not see them) | converted (#22258) |
| C | `core/src/security/resolve-authz-context.ts:401`,
`services/service-storage/src/storage-service-plugin.ts:1058` |
`input.getSession(headers)` / `getSession(headers)` | wrappers: the
function they call is a converted (#22258) reader (A18, and the injected
readers in the row above; `mcp/src/plugin.ts:172` injects none) |
| C | `drivers/driver-mongodb/src/mongodb-driver.ts` (13 hits),
`services/service-storage/src/metadata-store.ts:667`,
`storage-routes.ts:958`, `:1066`, `:1106`, `:1211` |
`this.getSession(options)` / `store.getSession(uploadId)` | not
better-auth (MongoDB client sessions, upload sessions) |
Related spelling, not a call with request headers:
`getSessionFromCtx(ctx)` at `plugin-auth/src/auth-manager.ts:2053` and
`:7111` (before-hooks) and `list-user-invitations-verification.ts:180`
(an endpoint) read inside the request's own better-auth pipeline, so a
renewal's `Set-Cookie` merges into that pipeline's Response; on a
re-dispatch from B1–B7 its `ctx.query` carries the rule (ablation L2
below runs exactly that hook read at `:7111`).
**Other lanes: none.** Every hit outside `plugin-auth` is either
converted (#22258) or not better-auth, so no card is owed from this PR.
## Pins and ablations
`src/in-process-session-renewal.pin.test.ts` (the #22258
real-better-auth harness: a real `AuthManager` on better-auth 1.7.3 over
the shared in-memory engine, the real `registerAuthRoutes` on Hono, a
session aged to `now + expiresIn − updateAge − 60 s`, `sys_session` read
off the engine) gains 9 door shapes × 2 cases. The fixture now turns on
SSO with domain verification, the OIDC provider and email verification,
marks the admin's address verified and seeds one org-less SSO provider
owned by the member; nothing reaches the network.
Each door's answer proves its last in-process read ran:
| Door | Answer (both cases) | By cookie | Bearer only | Ablation leg
(old call put back) | Ablation result |
|---|---|---|---|---|---|
| `/admin/sso/register` | 403 `SSO_REGISTER_FAILED` (the inner ADR-0135
D6 hook resolved the actor, then refused it) | 0 s, no cookie | +renewed
to now + expiresIn, no cookie | L1 `/get-session` re-dispatch; L2 inner
OIDC `/sso/register` | L1: this door and register-saml red; L2: this
door red |
| `/admin/sso/register-saml` | 403 `SAML_REGISTER_FAILED` | 0 s, no
cookie | renewed, no cookie | L1; L3 inner SAML `/sso/register` | L3:
this door red |
| `/admin/sso/request-domain-verification` | 403 (`checkProviderAccess`,
after `sessionMiddleware`) | 0 s, no cookie | renewed, no cookie | L4
inner route | this door red |
| `/admin/sso/verify-domain` | 403 | 0 s, no cookie | renewed, no cookie
| L5 inner route | this door red |
| `/send-verification-email` `{}` | 400 `EMAIL_ALREADY_VERIFIED` (needs
the session's user; the email came from the `/get-session` re-dispatch)
| 0 s, no cookie | renewed, no cookie | L6 `/get-session` re-dispatch;
L7 inner route | L6: this door red; L7: both send-verification doors red
|
| `/send-verification-email` `{ email }` | 400 `EMAIL_ALREADY_VERIFIED`
| 0 s, no cookie | renewed, no cookie | L7 | red |
| `/organization/add-member` | 400 `ORGANIZATION_NOT_FOUND` | 0 s, no
cookie | renewed, no cookie | L8 `headers: request.headers` | red |
| `/set-initial-password` | 409 `PASSWORD_ALREADY_SET` | 0 s, no cookie
| renewed, no cookie | L9 `headers: request.headers` | red |
| `/sys-oauth-application/register` | 200 (a client minted for the
session's user) | 0 s, no cookie | renewed, no cookie | L10 `headers:
c.req.raw.headers` | red |
The `get-session` control (renews and re-issues with `Max-Age =
expiresIn`) and the #22258 precondition (a bare in-process read renews)
are unchanged in the same file.
Ablation, run at `b9b04ef93` (source-identical to the head; `feea8a863`
adds only the changeset) through `scripts/ablation-replace.mjs` in WRAP
mode (literal anchor, hit count 1 → 0, blob changed, then restored with
`git checkout HEAD` and proven blob == HEAD with `git diff HEAD` empty),
inside a driver whose own trap restored every touched file to HEAD by
absolute path and re-proved it. Predicted direction: turn red on exactly
the named door's cookie case(s), bearer controls green. Observed:
exactly that, every leg.
- L1: `2 failed | 37 passed (39)` — `POST /admin/sso/register …: the
session renewed (+86460 s) but its cookie was not re-issued`, and the
same for register-saml.
- L2, L3, L4, L5, L6, L8, L9, L10: `1 failed | 38 passed (39)`, the
named door's by-cookie case, same message (+86460 s).
- L7: `2 failed | 37 passed (39)`, both send-verification cookie cases.
- Restored blobs (all == HEAD): `register-sso-provider.ts` 7e90a28,
`send-verification-email.ts` abdc894, `organization-add-member.ts`
1242154, `set-initial-password.ts` 5904711, `auth-plugin.ts`
3235e92.
Every mutated file is imported by the pin through relative `src/`
imports, so no `dist/` leg applies.
Pin file runtime (shared box, read as a ratio): before, 21 tests (11 own
+ 10 from `impersonation-bearer-rotation.test.ts`, which the file
already imported for `createMemoryEngine`), `tests 4.66s`, `Duration
19.87s`; after, 39 tests, `tests 4.72s`, `Duration 18.66s`. No new
sibling test file is imported.
## Verification at `feea8a863`
Every reading below was taken at `feea8a863` (`git rev-parse --short
HEAD`), the head this PR opens with.
- **Build.** `turbo run build --filter='@objectstack/plugin-auth^...'
--concurrency=2`: 27/27; `pnpm --filter @objectstack/plugin-auth build`:
exit 0 (2/2 declaration files); then the full `turbo run build
--filter='!@objectstack/docs' --concurrency=2`: 72/72 (71 from the
shared cache), for the gates that read every package's `dist/`.
- **Typecheck.** `pnpm --filter @objectstack/plugin-auth typecheck`:
exit 0 (`tsc --noEmit`, the examples config, and `check:test-typecheck`:
"10 file(s) / 94 error(s) / 23 pinned signature(s) held", unchanged).
`tsc --listFilesOnly` lists the pin file and
`register-sso-provider.test.ts` under `tsconfig.test.json`, and
`in-process-redispatch.ts` under `tsconfig.json`.
- **Tests.** `pnpm --filter @objectstack/plugin-auth exec vitest run
--maxWorkers=2`: `Test Files 133 passed (133)`, `Tests 2711 passed | 10
skipped (2721)`, 18 of them this PR's. The pin file alone: `Tests 39
passed (39)`. Public surface: no new export from the package entry;
`SetPasswordCapableApi` gains an optional member, so no import-side
suite is owed.
- **Gates.** `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 68 commands from this diff; each ran
with its exit code recorded, and all 68 exit 0.
`check:dual-build-cjs-loads` first exited 3 (`PREREQUISITE NOT MET`, no
`dist/` for 39 packages) and exits 0 after the full build;
`check:dts-closure` (72 packages), `check:sourcemap-no-sources-content`
(68), `check:lean-entry-closure` and `check:published-files` were re-run
after it, all exit 0. `--ran`: "Run reconciliation — 68 derived, 68 run,
0 NOT-MEASURED, 0 UNRUN."
- **Lint, narrowed and declared.** The population, read from eslint's
own config, is the 8 changed `.ts` files (the changeset answers "File
ignored because no matching configuration was supplied"). `eslint
--no-inline-config --format json` over them: 8 linted, 0 errors, 0
warnings. `eslint.config.mjs` enables no type-aware linting (no
`parserOptions.project`, no typed rules), so this diff cannot move a
verdict on any untouched file. The repo-wide `pnpm lint` is CI's.
## Acceptance notes
- Census method: the triage's two spellings (`authApi.*` / `api.*` with
`headers`, any receiver) are covered by one case-insensitive receiver
test; a control pass over every call with a `headers` member on any
other receiver found no in-process better-auth call. `handler(`
re-dispatches are counted for every route, not only `/get-session`,
because the bridges' inner forwards (card item 3) renew the same way.
- The test `register-sso-provider.test.ts` pinned the SAML bridge's
inner URL as `…/sso/register` for a request carrying a session cookie;
it now expects `…/sso/register?disableRefresh=true`, the rule's URL.
- `organization-add-member.ts`'s `AddMemberCapableApi` and the exported
`SetPasswordCapableApi` gain an optional `query: { disableRefresh: true
}`; implementers that pass better-auth's own `auth.api` need no change
(it honours the key, measured by L8/L9).
- The branch is not merged with `origin/main`: the one commit since the
base (`3ca71b6e0`, `metadata-protocol`) touches nothing in `plugin-auth`
or `types`.
- Observed while building the fixture, not investigated further: with
email verification on and no email service wired, `POST
/api/v1/auth/send-verification-email` for an unverified user answers
`500 {"success":false}`; the "no email service is configured" reason the
AuthManager throws reaches the server log only (better-auth answers a
thrown non-API error with an empty 500 body). A misconfiguration path;
noted, not filed.
- Out of scope, reported to the seat (not fixed here): with domain
verification ON, `POST
/api/v1/auth/admin/sso/request-domain-verification` and
`/admin/sso/verify-domain` answer an unknown `providerId` with `400
DOMAIN_VERIFICATION_DISABLED` ("not enabled … set
OS_SSO_DOMAIN_VERIFICATION"). The vendor's answer is `404
{"message":"Provider not found"}`, and the bridge treats any 404 without
a `code` as "feature off" (feature off is a 404 with an empty body).
Measured in this PR's harness before the pins were written.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WYYhVJ78u7PhwFViWo1EmQ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7806a14 commit f66c440
9 files changed
Lines changed: 295 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3164 | 3164 | | |
3165 | 3165 | | |
3166 | 3166 | | |
3167 | | - | |
| 3167 | + | |
| 3168 | + | |
| 3169 | + | |
| 3170 | + | |
3168 | 3171 | | |
3169 | 3172 | | |
3170 | 3173 | | |
| |||
3173 | 3176 | | |
3174 | 3177 | | |
3175 | 3178 | | |
3176 | | - | |
| 3179 | + | |
3177 | 3180 | | |
3178 | 3181 | | |
3179 | 3182 | | |
| |||
Lines changed: 53 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
Lines changed: 169 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
41 | 77 | | |
42 | 78 | | |
43 | 79 | | |
| |||
54 | 90 | | |
55 | 91 | | |
56 | 92 | | |
| 93 | + | |
| 94 | + | |
57 | 95 | | |
58 | 96 | | |
59 | 97 | | |
| |||
141 | 179 | | |
142 | 180 | | |
143 | 181 | | |
144 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
145 | 185 | | |
146 | 186 | | |
147 | 187 | | |
| |||
169 | 209 | | |
170 | 210 | | |
171 | 211 | | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
172 | 226 | | |
173 | 227 | | |
174 | 228 | | |
| |||
263 | 317 | | |
264 | 318 | | |
265 | 319 | | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
266 | 434 | | |
267 | 435 | | |
268 | 436 | | |
| |||
Lines changed: 9 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
| 73 | + | |
73 | 74 | | |
74 | 75 | | |
75 | 76 | | |
| |||
82 | 83 | | |
83 | 84 | | |
84 | 85 | | |
| 86 | + | |
| 87 | + | |
85 | 88 | | |
86 | 89 | | |
87 | 90 | | |
| |||
165 | 168 | | |
166 | 169 | | |
167 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
168 | 176 | | |
169 | 177 | | |
170 | 178 | | |
171 | 179 | | |
172 | 180 | | |
173 | 181 | | |
174 | 182 | | |
175 | | - | |
| 183 | + | |
176 | 184 | | |
177 | 185 | | |
178 | 186 | | |
| |||
Lines changed: 5 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
138 | 138 | | |
139 | 139 | | |
140 | 140 | | |
141 | | - | |
142 | | - | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
143 | 146 | | |
144 | 147 | | |
145 | 148 | | |
| |||
0 commit comments