|
| 1 | +# Development Data Store Plan (`@salesforce/mrt-utilities`) |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Add a pseudo local data-store implementation for development mode so local runtimes do not fail when DynamoDB-backed MRT data store is unavailable. |
| 6 | + |
| 7 | +This behavior should be activated through the existing package export condition: |
| 8 | + |
| 9 | +- `@salesforce/mrt-utilities/data-store` + `--conditions development` |
| 10 | + |
| 11 | +## Key Requirement |
| 12 | + |
| 13 | +The pseudo local implementation must read default entry values from environment variables (as implied by the provided prototype): |
| 14 | + |
| 15 | +- `MRT_DATA_STORE_DEFAULTS` (JSON object map of key -> value object) |
| 16 | +- `MRT_DATA_STORE_WARN_ON_MISSING` (`"false"` disables warnings; default is warning enabled) |
| 17 | + |
| 18 | +## Current State |
| 19 | + |
| 20 | +- `./data-store` already has a `development` export condition in `package.json`, but it currently points to `src`. |
| 21 | +- Desired update: point `development` to a built `dist` pseudo-local data-store output. |
| 22 | +- Current `DataStore` implementation is DynamoDB-based and throws `DataStoreUnavailableError` when required MRT environment variables are missing. |
| 23 | +- Existing tests primarily validate production/DynamoDB behavior. |
| 24 | + |
| 25 | +## Proposed Design |
| 26 | + |
| 27 | +## 1) Split data-store implementations |
| 28 | + |
| 29 | +Create two implementation modules: |
| 30 | + |
| 31 | +- **Production implementation** (existing behavior) |
| 32 | + - DynamoDB-backed |
| 33 | + - Preserves existing errors: |
| 34 | + - `DataStoreUnavailableError` |
| 35 | + - `DataStoreNotFoundError` |
| 36 | + - `DataStoreServiceError` |
| 37 | +- **Development implementation** (new behavior) |
| 38 | + - No AWS dependency |
| 39 | + - Uses local defaults from env var JSON |
| 40 | + - Warns once per missing key (configurable) |
| 41 | + - Uses strict parity with production semantics by default for missing keys (throws not-found) |
| 42 | + - Optional lenient mode can be introduced as explicit opt-in for `{}` fallback during local experimentation |
| 43 | + |
| 44 | +## 2) Preserve stable public API |
| 45 | + |
| 46 | +Keep consumer import surface unchanged: |
| 47 | + |
| 48 | +- `DataStore.getDataStore()` |
| 49 | +- `DataStore#isDataStoreAvailable()` |
| 50 | +- `DataStore#getEntry(key)` |
| 51 | +- Existing error classes remain exported |
| 52 | + |
| 53 | +This allows existing projects to adopt dev behavior without refactoring imports. |
| 54 | + |
| 55 | +## 3) Route development exports |
| 56 | + |
| 57 | +Use conditional exports to load the development implementation for local dev from built artifacts: |
| 58 | + |
| 59 | +- `development` -> built dev pseudo-local data-store module in `dist` |
| 60 | +- `import` / `require` -> production built outputs in `dist` |
| 61 | + |
| 62 | +## 4) Environment variable behavior in dev store |
| 63 | + |
| 64 | +### `MRT_DATA_STORE_DEFAULTS` |
| 65 | + |
| 66 | +- Parse as JSON object. |
| 67 | +- Expected shape: |
| 68 | + - `{ "<entry-key>": { ...objectValue } }` |
| 69 | +- On invalid JSON: |
| 70 | + - fall back to empty defaults |
| 71 | + - warn once with clear message |
| 72 | + |
| 73 | +### `MRT_DATA_STORE_WARN_ON_MISSING` |
| 74 | + |
| 75 | +- If unset: warnings enabled |
| 76 | +- If set to `"false"` (case-insensitive): disable missing-key warnings |
| 77 | +- Any other value: warnings enabled |
| 78 | + |
| 79 | +### Missing key semantics (dev mode) |
| 80 | + |
| 81 | +- If key exists in parsed defaults and value is object: return that value. |
| 82 | +- If key missing or invalid value type: |
| 83 | + - by default, throw `DataStoreNotFoundError` (production parity) |
| 84 | + - optionally warn once for that key before throwing |
| 85 | + - optional future opt-in lenient mode may return `{}` instead (must be off by default) |
| 86 | + |
| 87 | +## 5) Tests |
| 88 | + |
| 89 | +Add/adjust tests to cover both modes: |
| 90 | + |
| 91 | +- **Production tests** |
| 92 | + - Keep current behavior assertions unchanged. |
| 93 | +- **Development tests** |
| 94 | + - Reads defaults from `MRT_DATA_STORE_DEFAULTS` |
| 95 | + - Throws `DataStoreNotFoundError` when key is absent (default behavior) |
| 96 | + - Warns once per missing key when warnings enabled |
| 97 | + - Does not warn when `MRT_DATA_STORE_WARN_ON_MISSING=false` |
| 98 | + - Handles invalid JSON safely |
| 99 | + - (If lenient mode is added) returns `{}` only when explicitly enabled |
| 100 | + |
| 101 | +## 6) Documentation updates |
| 102 | + |
| 103 | +Update `packages/mrt-utilities/README.md` (or docs page if preferred) with: |
| 104 | + |
| 105 | +- How to enable dev behavior (`node --conditions development`) |
| 106 | +- Env var configuration examples for default data-store values |
| 107 | +- Differences between dev and production data-store semantics |
| 108 | + |
| 109 | +## Implementation Steps |
| 110 | + |
| 111 | +1. Add a new dev data-store module in `src/data-store/`. |
| 112 | +2. Move/keep current DynamoDB implementation as production module. |
| 113 | +3. Ensure build output emits both implementations to `dist` (esm/cjs + types). |
| 114 | +4. Update `package.json` exports so `development` resolves to the built dev pseudo-local module in `dist` (not `src`), while `import`/`require` continue resolving to production built outputs. |
| 115 | +5. Add development-focused tests. |
| 116 | +6. Run validation: |
| 117 | + - `pnpm --filter @salesforce/mrt-utilities run test:agent` |
| 118 | + - `pnpm --filter @salesforce/mrt-utilities run lint:agent` |
| 119 | + - `pnpm --filter @salesforce/mrt-utilities run typecheck:agent` |
| 120 | +7. Add a changeset for `@salesforce/mrt-utilities` if this is considered user-facing behavior. |
| 121 | + |
| 122 | +## Risks / Notes |
| 123 | + |
| 124 | +- Strict production parity in dev is the default to avoid masking missing-key issues. |
| 125 | +- Any lenient `{}` fallback behavior must be explicit opt-in and clearly documented. |
| 126 | +- Existing export stripping behavior is already understood and is not changed by this plan. |
| 127 | + |
| 128 | +## Acceptance Criteria |
| 129 | + |
| 130 | +- Local development using `--conditions development` no longer fails due to missing DynamoDB/MRT runtime vars. |
| 131 | +- Dev data-store entries are sourced from `MRT_DATA_STORE_DEFAULTS`. |
| 132 | +- Missing-key behavior is predictable and configurable via `MRT_DATA_STORE_WARN_ON_MISSING`. |
| 133 | +- Production behavior and API remain backward-compatible. |
| 134 | +- No breaking public interface changes: existing import paths, exported symbols, and type surface for `@salesforce/mrt-utilities` and `@salesforce/mrt-utilities/data-store` remain intact (except correcting the `development` export target to built `dist` output). |
| 135 | +- Default dev missing-key semantics match production (`DataStoreNotFoundError`), with no implicit `{}` fallback. |
0 commit comments