Commit 46e20e6
feat(types,server): [YW-139] DataSource.config typed field + SetDataSourceConfig wiring (#139)
## Summary
- Adds `ConnectorConfig` to `@dashframe/types`: structured public-safe
config blob where credential fields (`hasApiKey`, `hasConnectionString`)
are boolean presence flags, never raw `SecretRef` values or plaintext.
Non-credential connector settings pass through as-is.
- `rowToDataSource` converts the internal `DataSourceConfig` (SecretRef
slots) to `ConnectorConfig`: credential slots are redacted to booleans;
non-credential keys are passed through verbatim BUT any value that is a
well-formed `SecretRef` (`secret:<uuid>`) is also stripped regardless of
key name — sink guarded by value shape, not provenance.
- `SetDataSourceConfig` gains an optional `extra:
Record<string,unknown>` field for non-credential connector settings
(e.g. `database`, `schema`, `host`). Sink guard rejects any attempt to
pass `"apiKey"` or `"connectionString"` via `extra` — callers must use
the typed credential fields.
- UI components and tests migrated from `dataSource.hasApiKey` to
`dataSource.config.hasApiKey`.
Tracked internally as YW-139.
## Test plan
- [ ] `turbo typecheck` — 44 tasks, 0 failures
- [ ] `@dashframe/server` tests — 222 pass (219 existing + 3 new)
- `SetDataSourceConfig sink guard: extra.apiKey throws and leaves config
unchanged`
- `SetDataSourceConfig sink guard: extra.connectionString throws and
leaves config unchanged`
- `SetDataSourceConfig extra: non-credential settings round-trip through
config`
- [ ] `@dashframe/app` tests — 510 pass (all existing)
- [ ] vault-control-plane AC3 test extended: `config.apiKey` is absent
from the read DTO even when `hasApiKey` is true (SecretRef redaction
verified)
- [ ] CI green
## Findings triaged to LATER
- **OOD-1** — Legacy `updateDataSource` coexistence. The `utils.ts`
header calls it a "transition window" which collides with the
no-backward-compat memory. TRIGGER: before any new connector (PostgreSQL
or similar) adds a caller, cut `updateDataSource` — it has no sink guard
and no `extra` path.
- **OOD-2** — `CreateDataSource` lacks `extra` parameter;
`SetDataSourceConfig` has it. TRIGGER: when the first connector needing
creation-time non-credential settings is defined, add `extra` (+ same
sink guard) to `CreateDataSource` for symmetry.
- **OOD-3** — `ConnectorConfig` index signature `[key: string]:
unknown`. TRIGGER: when the 3rd connector lands, revisit as a
discriminated union per Rule of Three.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR introduces `ConnectorConfig` as a typed public-safe DTO for the
`DataSource.config` field, nesting credential presence flags
(`hasApiKey`, `hasConnectionString`) and pass-through non-credential
settings there instead of at the top level. It also wires an `extra`
parameter into `SetDataSourceConfig` with a sink guard that blocks
`"apiKey"`/`"connectionString"` from being smuggled in.
- **New `ConnectorConfig` type** (`packages/types/src/data-sources.ts`):
replaces flat `hasApiKey`/`hasConnectionString` on `DataSource` with a
structured `config` blob; credential fields are boolean presence flags,
extra non-credential keys pass through under an open index signature.
- **`rowToDataSource` redaction loop** (`app-artifacts.ts`): iterates
stored config, drops credential slots by key name and drops any
SecretRef-shaped value by value shape, then spreads remaining keys into
the DTO after the vault-computed booleans.
- **`SetDataSourceConfig extra` field** (`commands.ts`): accepts
non-credential connector settings (e.g. `database`, `schema`) and merges
them into the stored config; sink guard rejects
`"apiKey"`/`"connectionString"` in `extra`, directing callers to use the
typed credential fields.
</details>
<details><summary><h3>Confidence Score: 4/5</h3></summary>
Safe to merge with the understanding that the previously-flagged
spoofing path in the sink guard remains open.
The core redaction logic in `rowToDataSource` and the `extra` sink guard
in `SetDataSourceConfig` are well-structured, and all UI callsites are
consistently migrated. However, the existing unresolved finding from a
prior review (callers can pass `extra: { hasApiKey: true }`, which
`Object.assign` writes into stored config and then the `...otherKeys`
spread in `rowToDataSource` surfaces as a spoofed `config.hasApiKey:
true` in the DTO, overriding the vault-computed boolean) is still
present in this diff and has not been addressed.
`apps/server/src/functions/commands.ts` (sink guard) and
`apps/server/src/functions/app-artifacts.ts` (`rowToDataSource` spread
order) together form the unresolved spoofing path flagged in the prior
review.
</details>
<details><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| packages/types/src/data-sources.ts | Adds `ConnectorConfig` type with
`hasApiKey`, `hasConnectionString`, and an open index signature;
replaces flat `hasApiKey`/`hasConnectionString` on `DataSource` with
`config: ConnectorConfig`. |
| apps/server/src/functions/app-artifacts.ts | Adds `otherKeys` loop in
`rowToDataSource` to pass through non-credential, non-SecretRef config
keys; spreads them after the vault-computed booleans, which means stored
`hasApiKey`/`hasConnectionString` keys in `otherKeys` win over the
vault-derived values. |
| apps/server/src/functions/commands.ts | Adds `extra: jsonb.optional()`
to `SetDataSourceConfig`; sink guard blocks
`"apiKey"`/`"connectionString"` keys but not
`"hasApiKey"`/`"hasConnectionString"`, and guard runs after
`applyCredentialField` vault writes (both previously flagged). |
| apps/server/src/functions/commands.test.ts | Adds three new tests for
`SetDataSourceConfig`: sink-guard rejection for `extra.apiKey`,
sink-guard rejection for `extra.connectionString`, and round-trip of
non-credential extra keys. |
| apps/server/src/functions/vault-control-plane.test.ts | Migrates all
assertions from `ds.hasApiKey` to `ds.config.hasApiKey` and adds a new
assertion verifying the SecretRef is absent from the public DTO (AC3
extension). |
|
packages/app/src/app/data-sources/[sourceId]/_components/DataSourcePageContent.test.tsx
| Updates test fixture from unsafe `as DataSource` cast to type-checked
`satisfies DataSource` with correct `config` shape and `createdAt`. |
| packages/app/src/components/data-sources/DataSourceControls.tsx |
Mechanical migration of `dataSource.hasApiKey` →
`dataSource.config.hasApiKey` at three call sites. |
| packages/app/src/components/data-sources/DataSourceDisplay.tsx |
Mechanical migration of `dataSource.hasApiKey` →
`dataSource.config.hasApiKey` at three guard sites. |
| packages/types/src/index.ts | Adds `ConnectorConfig` to the public
package exports. One-line change, correct. |
</details>
</details>
<details><summary><h3>Sequence Diagram</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as UI Component
participant CMD as SetDataSourceConfig
participant Vault as SecretVault
participant DB as Database
participant DTO as rowToDataSource
UI->>CMD: "{ id, apiKey?, connectionString?, extra? }"
CMD->>CMD: applyCredentialField(apiKey) → SecretRef
CMD->>Vault: vault.store(apiKey plaintext)
Vault-->>CMD: SecretRef
CMD->>CMD: sink guard: reject if extra has apiKey/connectionString
CMD->>CMD: Object.assign(config, extra)
CMD->>DB: UPDATE data_sources SET config
DB-->>CMD: ok
UI->>DTO: getDataSource(id)
DTO->>DB: SELECT config FROM data_sources
DB-->>DTO: "{ apiKey: SecretRef, database: analytics, ... }"
DTO->>Vault: vault.has(SecretRef) → boolean
Vault-->>DTO: hasApiKey true/false
DTO->>DTO: otherKeys loop: skip apiKey, connectionString, SecretRef values
DTO-->>UI: "{ config: { hasApiKey, hasConnectionString, database, ... } }"
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as UI Component
participant CMD as SetDataSourceConfig
participant Vault as SecretVault
participant DB as Database
participant DTO as rowToDataSource
UI->>CMD: "{ id, apiKey?, connectionString?, extra? }"
CMD->>CMD: applyCredentialField(apiKey) → SecretRef
CMD->>Vault: vault.store(apiKey plaintext)
Vault-->>CMD: SecretRef
CMD->>CMD: sink guard: reject if extra has apiKey/connectionString
CMD->>CMD: Object.assign(config, extra)
CMD->>DB: UPDATE data_sources SET config
DB-->>CMD: ok
UI->>DTO: getDataSource(id)
DTO->>DB: SELECT config FROM data_sources
DB-->>DTO: "{ apiKey: SecretRef, database: analytics, ... }"
DTO->>Vault: vault.has(SecretRef) → boolean
Vault-->>DTO: hasApiKey true/false
DTO->>DTO: otherKeys loop: skip apiKey, connectionString, SecretRef values
DTO-->>UI: "{ config: { hasApiKey, hasConnectionString, database, ... } }"
```
</a>
</details>
<!-- greptile_failed_comments -->
<details><summary><h3>Comments Outside Diff (1)</h3></summary>
1. `apps/server/src/functions/commands.ts`, line 355-380
([link](https://github.com/youhaowei/dashframe/blob/e596efaf5a417bd9d01cf005badd6a228128a79b/apps/server/src/functions/commands.ts#L355-L380))
<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **Sink guard runs after vault writes — unnecessary
vault-ref orphaning on rejection**
`applyCredentialField` is called before the `extra` sink guard. If a
caller supplies both a non-empty `apiKey` and `extra: { apiKey: "x" }`,
the vault write for `apiKey` completes (and a new `SecretRef` is
generated) before the guard throws and aborts the DB update. The
orphaned ref is benign per the deferred-cleanup design, but the guard
should be hoisted above the `applyCredentialField` calls so rejections
fail before touching the vault at all.
<details><summary>Prompt To Fix With AI</summary>
`````markdown
This is a comment left during a code review.
Path: apps/server/src/functions/commands.ts
Line: 355-380
Comment:
**Sink guard runs after vault writes — unnecessary vault-ref orphaning
on rejection**
`applyCredentialField` is called before the `extra` sink guard. If a
caller supplies both a non-empty `apiKey` and `extra: { apiKey: "x" }`,
the vault write for `apiKey` completes (and a new `SecretRef` is
generated) before the guard throws and aborts the DB update. The
orphaned ref is benign per the deferred-cleanup design, but the guard
should be hoisted above the `applyCredentialField` calls so rejections
fail before touching the vault at all.
How can I resolve this? If you propose a fix, please make it concise.
`````
</details>
Note: If this suggestion doesn't match your team's coding style, reply
to this and let me know. I'll remember it for next time!
<a
href="https://app.greptile.com/ide/claude-code?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20apps%2Fserver%2Fsrc%2Ffunctions%2Fcommands.ts%0ALine%3A%20355-380%0A%0AComment%3A%0A**Sink%20guard%20runs%20after%20vault%20writes%20%E2%80%94%20unnecessary%20vault-ref%20orphaning%20on%20rejection**%0A%0A%60applyCredentialField%60%20is%20called%20before%20the%20%60extra%60%20sink%20guard.%20If%20a%20caller%20supplies%20both%20a%20non-empty%20%60apiKey%60%20and%20%60extra%3A%20%7B%20apiKey%3A%20%22x%22%20%7D%60%2C%20the%20vault%20write%20for%20%60apiKey%60%20completes%20%28and%20a%20new%20%60SecretRef%60%20is%20generated%29%20before%20the%20guard%20throws%20and%20aborts%20the%20DB%20update.%20The%20orphaned%20ref%20is%20benign%20per%20the%20deferred-cleanup%20design%2C%20but%20the%20guard%20should%20be%20hoisted%20above%20the%20%60applyCredentialField%60%20calls%20so%20rejections%20fail%20before%20touching%20the%20vault%20at%20all.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=youhaowei%2Fdashframe&pr=139&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaudeDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"><img
alt="Fix in Claude Code"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInClaude.svg?v=3"
height="20"></picture></a> <a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22youhaowei%2Fdashframe%22%20on%20the%20existing%20branch%20%22charixandra%2Fyw-139-datasourceconfig-typed-field-setdatasourceconfig-wiring%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22charixandra%2Fyw-139-datasourceconfig-typed-field-setdatasourceconfig-wiring%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20apps%2Fserver%2Fsrc%2Ffunctions%2Fcommands.ts%0ALine%3A%20355-380%0A%0AComment%3A%0A**Sink%20guard%20runs%20after%20vault%20writes%20%E2%80%94%20unnecessary%20vault-ref%20orphaning%20on%20rejection**%0A%0A%60applyCredentialField%60%20is%20called%20before%20the%20%60extra%60%20sink%20guard.%20If%20a%20caller%20supplies%20both%20a%20non-empty%20%60apiKey%60%20and%20%60extra%3A%20%7B%20apiKey%3A%20%22x%22%20%7D%60%2C%20the%20vault%20write%20for%20%60apiKey%60%20completes%20%28and%20a%20new%20%60SecretRef%60%20is%20generated%29%20before%20the%20guard%20throws%20and%20aborts%20the%20DB%20update.%20The%20orphaned%20ref%20is%20benign%20per%20the%20deferred-cleanup%20design%2C%20but%20the%20guard%20should%20be%20hoisted%20above%20the%20%60applyCredentialField%60%20calls%20so%20rejections%20fail%20before%20touching%20the%20vault%20at%20all.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=youhaowei%2Fdashframe&pr=139&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=3"
height="20"></picture></a> <a
href="https://app.greptile.com/api/ide/cursor?prompt=This%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20apps%2Fserver%2Fsrc%2Ffunctions%2Fcommands.ts%0ALine%3A%20355-380%0A%0AComment%3A%0A**Sink%20guard%20runs%20after%20vault%20writes%20%E2%80%94%20unnecessary%20vault-ref%20orphaning%20on%20rejection**%0A%0A%60applyCredentialField%60%20is%20called%20before%20the%20%60extra%60%20sink%20guard.%20If%20a%20caller%20supplies%20both%20a%20non-empty%20%60apiKey%60%20and%20%60extra%3A%20%7B%20apiKey%3A%20%22x%22%20%7D%60%2C%20the%20vault%20write%20for%20%60apiKey%60%20completes%20%28and%20a%20new%20%60SecretRef%60%20is%20generated%29%20before%20the%20guard%20throws%20and%20aborts%20the%20DB%20update.%20The%20orphaned%20ref%20is%20benign%20per%20the%20deferred-cleanup%20design%2C%20but%20the%20guard%20should%20be%20hoisted%20above%20the%20%60applyCredentialField%60%20calls%20so%20rejections%20fail%20before%20touching%20the%20vault%20at%20all.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&pr=139&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCursorDark.svg?v=3"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCursor.svg?v=3"><img
alt="Fix in Cursor"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCursor.svg?v=3"
height="20"></picture></a>
</details>
<!-- /greptile_failed_comments -->
<sub>Reviews (3): Last reviewed commit: ["fix(server): harden
SetDataSourceConfig
..."](1aac070)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=38073036)</sub>
<!-- /greptile_comment -->
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent f3e8660 commit 46e20e6
9 files changed
Lines changed: 171 additions & 33 deletions
File tree
- apps/server/src/functions
- packages
- app/src
- app/data-sources/[sourceId]/_components
- components/data-sources
- types/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
256 | 256 | | |
257 | 257 | | |
258 | 258 | | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
259 | 273 | | |
260 | 274 | | |
261 | 275 | | |
262 | 276 | | |
263 | | - | |
264 | | - | |
| 277 | + | |
265 | 278 | | |
266 | 279 | | |
267 | 280 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
632 | 632 | | |
633 | 633 | | |
634 | 634 | | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
635 | 706 | | |
636 | 707 | | |
637 | 708 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
320 | 320 | | |
321 | 321 | | |
322 | 322 | | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
323 | 327 | | |
324 | 328 | | |
325 | 329 | | |
326 | 330 | | |
327 | 331 | | |
328 | 332 | | |
| 333 | + | |
329 | 334 | | |
330 | 335 | | |
331 | 336 | | |
332 | | - | |
| 337 | + | |
333 | 338 | | |
334 | 339 | | |
335 | 340 | | |
| |||
363 | 368 | | |
364 | 369 | | |
365 | 370 | | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
366 | 381 | | |
367 | 382 | | |
368 | 383 | | |
| |||
1889 | 1904 | | |
1890 | 1905 | | |
1891 | 1906 | | |
| 1907 | + | |
| 1908 | + | |
1892 | 1909 | | |
1893 | 1910 | | |
1894 | 1911 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
174 | 174 | | |
175 | 175 | | |
176 | 176 | | |
177 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
178 | 180 | | |
179 | 181 | | |
180 | 182 | | |
| |||
256 | 258 | | |
257 | 259 | | |
258 | 260 | | |
259 | | - | |
260 | | - | |
261 | | - | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
262 | 269 | | |
263 | 270 | | |
264 | 271 | | |
| |||
269 | 276 | | |
270 | 277 | | |
271 | 278 | | |
272 | | - | |
273 | | - | |
274 | | - | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
275 | 284 | | |
276 | 285 | | |
277 | 286 | | |
| |||
285 | 294 | | |
286 | 295 | | |
287 | 296 | | |
288 | | - | |
289 | | - | |
| 297 | + | |
| 298 | + | |
290 | 299 | | |
291 | 300 | | |
292 | 301 | | |
| |||
306 | 315 | | |
307 | 316 | | |
308 | 317 | | |
309 | | - | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
310 | 322 | | |
311 | 323 | | |
312 | | - | |
313 | | - | |
| 324 | + | |
| 325 | + | |
314 | 326 | | |
315 | 327 | | |
316 | 328 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
194 | | - | |
195 | | - | |
196 | | - | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
| |||
Lines changed: 9 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
212 | | - | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
213 | 217 | | |
214 | 218 | | |
215 | 219 | | |
| |||
325 | 329 | | |
326 | 330 | | |
327 | 331 | | |
328 | | - | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
329 | 335 | | |
330 | 336 | | |
331 | | - | |
| 337 | + | |
332 | 338 | | |
333 | 339 | | |
334 | 340 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
372 | 372 | | |
373 | 373 | | |
374 | 374 | | |
375 | | - | |
| 375 | + | |
376 | 376 | | |
377 | 377 | | |
378 | 378 | | |
| |||
426 | 426 | | |
427 | 427 | | |
428 | 428 | | |
429 | | - | |
| 429 | + | |
430 | 430 | | |
431 | 431 | | |
432 | 432 | | |
| |||
480 | 480 | | |
481 | 481 | | |
482 | 482 | | |
483 | | - | |
| 483 | + | |
484 | 484 | | |
485 | 485 | | |
486 | 486 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
8 | 27 | | |
9 | 28 | | |
10 | 29 | | |
11 | 30 | | |
12 | 31 | | |
13 | | - | |
14 | | - | |
| 32 | + | |
| 33 | + | |
15 | 34 | | |
16 | 35 | | |
17 | 36 | | |
18 | 37 | | |
19 | 38 | | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
27 | 45 | | |
28 | 46 | | |
29 | 47 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| 47 | + | |
47 | 48 | | |
48 | 49 | | |
49 | 50 | | |
| |||
0 commit comments