resplite 1.2.6 → 1.2.10
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.
- package/README.md +168 -275
- package/package.json +1 -6
- package/scripts/create-interface-smoke.js +32 -0
- package/skills/README.md +22 -0
- package/skills/resplite-command-vertical-slice/SKILL.md +134 -0
- package/skills/resplite-ft-search-workbench/SKILL.md +138 -0
- package/skills/resplite-migration-cutover-assistant/SKILL.md +138 -0
- package/spec/00-INDEX.md +37 -0
- package/spec/01-overview-and-goals.md +125 -0
- package/spec/02-protocol-and-commands.md +174 -0
- package/spec/03-data-model-ttl-transactions.md +157 -0
- package/spec/04-cache-architecture.md +171 -0
- package/spec/05-scan-admin-implementation.md +379 -0
- package/spec/06-migration-strategy-core.md +79 -0
- package/spec/07-type-lists.md +202 -0
- package/spec/08-type-sorted-sets.md +220 -0
- package/spec/{SPEC_D.md → 09-search-ft-commands.md} +3 -1
- package/spec/{SPEC_E.md → 10-blocking-commands.md} +3 -1
- package/spec/{SPEC_F.md → 11-migration-dirty-registry.md} +61 -147
- package/src/commands/object.js +17 -0
- package/src/commands/registry.js +4 -0
- package/src/commands/zrevrange.js +27 -0
- package/src/engine/engine.js +19 -0
- package/src/migration/apply-dirty.js +8 -1
- package/src/migration/index.js +5 -4
- package/src/migration/migrate-search.js +25 -6
- package/src/storage/sqlite/zsets.js +34 -0
- package/test/integration/object-idletime.test.js +51 -0
- package/test/integration/zsets.test.js +18 -0
- package/test/unit/migrate-search.test.js +50 -2
- package/spec/SPEC_A.md +0 -1171
- package/spec/SPEC_B.md +0 -426
- package/src/cli/import-from-redis.js +0 -194
- package/src/cli/resplite-dirty-tracker.js +0 -92
- package/src/cli/resplite-import.js +0 -296
- package/test/contract/import-from-redis.test.js +0 -83
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resplite-command-vertical-slice
|
|
3
|
+
description: Implements or extends a Redis-like command in RESPLite from spec to docs and tests. Use when the user says "add a command", "support a Redis option", "fix command compatibility", "implement ZRANGE behavior", or "update the compatibility matrix". Do not use for migration-only or FT-only work unless the change also affects the general command surface.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Cursor Agent
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
category: workflow-automation
|
|
9
|
+
tags: [resplite, redis-compatibility, commands, tests]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# RESPLite Command Vertical Slice
|
|
13
|
+
|
|
14
|
+
Use this skill when a task requires changing RESPLite's public command behavior end to end rather than only editing one isolated function.
|
|
15
|
+
|
|
16
|
+
## Use cases
|
|
17
|
+
|
|
18
|
+
**Use Case: Add a missing command**
|
|
19
|
+
Trigger: "implement command X", "add Redis compatibility for X", "support command Y"
|
|
20
|
+
Steps: inspect spec and current support, wire the handler, update engine or storage if needed, add tests, update docs
|
|
21
|
+
Result: a verified command slice that works through RESP and is reflected in the public docs
|
|
22
|
+
|
|
23
|
+
**Use Case: Extend a partially supported command**
|
|
24
|
+
Trigger: "support another ZRANGE option", "fix TTL edge case", "match Redis error behavior"
|
|
25
|
+
Steps: compare current implementation with intended semantics, patch the smallest layer that owns the behavior, strengthen tests, update compatibility notes
|
|
26
|
+
Result: improved compatibility without widening scope unnecessarily
|
|
27
|
+
|
|
28
|
+
**Use Case: Audit a command regression**
|
|
29
|
+
Trigger: "this command broke", "redis-cli behaves differently", "wrongtype or ERR output is wrong"
|
|
30
|
+
Steps: reproduce through tests, isolate whether the issue is parser, handler, engine, or storage, fix the owning layer, verify client-facing behavior
|
|
31
|
+
Result: the bug is fixed with regression coverage
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
|
|
35
|
+
### Step 1: Lock the compatibility target
|
|
36
|
+
|
|
37
|
+
Start by defining the exact command surface you are changing:
|
|
38
|
+
|
|
39
|
+
- command name and sub-options
|
|
40
|
+
- expected success reply shape
|
|
41
|
+
- expected error strings
|
|
42
|
+
- whether the change is Redis-standard behavior or RESPLite-specific behavior
|
|
43
|
+
|
|
44
|
+
Favor the smallest compatibility increment that solves the user's request. RESPLite is intentionally a practical subset, not a full Redis clone.
|
|
45
|
+
|
|
46
|
+
### Step 2: Review the canonical sources first
|
|
47
|
+
|
|
48
|
+
Read these files before editing:
|
|
49
|
+
|
|
50
|
+
- `README.md` for the public compatibility matrix and examples
|
|
51
|
+
- `src/commands/registry.js` for command dispatch and handler registration
|
|
52
|
+
|
|
53
|
+
Then inspect the command-specific implementation:
|
|
54
|
+
|
|
55
|
+
- `src/commands/*.js` for argument parsing and command-level behavior
|
|
56
|
+
- `src/engine/*.js` when semantics belong to the engine
|
|
57
|
+
- `src/storage/sqlite/*.js` when persistence or query behavior changes
|
|
58
|
+
- relevant tests in `test/unit`, `test/integration`, and `test/contract`
|
|
59
|
+
|
|
60
|
+
### Step 3: Choose the owning layer
|
|
61
|
+
|
|
62
|
+
Use this decision rule:
|
|
63
|
+
|
|
64
|
+
- parser or command syntax issue: fix the command handler
|
|
65
|
+
- business semantics issue: fix the engine layer
|
|
66
|
+
- persistence or query issue: fix SQLite storage helpers
|
|
67
|
+
- public support surface changed: also update `README.md` and, if needed, the spec
|
|
68
|
+
|
|
69
|
+
Avoid scattering logic across layers when one layer can own it cleanly.
|
|
70
|
+
|
|
71
|
+
### Step 4: Implement the smallest vertical slice
|
|
72
|
+
|
|
73
|
+
Typical command workflow:
|
|
74
|
+
|
|
75
|
+
1. Add or update the handler in `src/commands`
|
|
76
|
+
2. Register it in `src/commands/registry.js` if needed
|
|
77
|
+
3. Patch engine or storage behavior only where required
|
|
78
|
+
4. Preserve existing error style such as `ERR ...` and wrong-type behavior
|
|
79
|
+
5. Keep binary-safety expectations in mind when keys or values pass through buffers and SQLite
|
|
80
|
+
|
|
81
|
+
If a new command expands publicly supported behavior, update the compatibility matrix in `README.md`.
|
|
82
|
+
|
|
83
|
+
### Step 5: Prove it through the right test level
|
|
84
|
+
|
|
85
|
+
Pick the smallest test mix that proves the change:
|
|
86
|
+
|
|
87
|
+
- `test/unit/*.test.js` for pure logic, engine rules, parser behavior, or storage helpers
|
|
88
|
+
- `test/integration/*.test.js` for end-to-end RESP behavior through the server
|
|
89
|
+
- `test/contract/*.test.js` when compatibility with `redis` client or `redis-cli` is part of the user-facing promise
|
|
90
|
+
|
|
91
|
+
Prefer adding a regression test that would fail before the fix and pass after it.
|
|
92
|
+
|
|
93
|
+
### Step 6: Report the outcome clearly
|
|
94
|
+
|
|
95
|
+
When you finish, summarize:
|
|
96
|
+
|
|
97
|
+
- what compatibility surface changed
|
|
98
|
+
- which layers were touched
|
|
99
|
+
- which tests were run
|
|
100
|
+
- any remaining intentional gaps versus Redis
|
|
101
|
+
|
|
102
|
+
## RESPLite-specific checklist
|
|
103
|
+
|
|
104
|
+
- Keep scope aligned with "practical Redis compatibility", not total parity
|
|
105
|
+
- Preserve RESP2-facing behavior
|
|
106
|
+
- Use the public docs to reflect newly supported behavior
|
|
107
|
+
- Do not claim support in docs until tests back it up
|
|
108
|
+
- If the command is intentionally unsupported, return the project's clear unsupported-command behavior instead of faking partial support
|
|
109
|
+
|
|
110
|
+
## Examples
|
|
111
|
+
|
|
112
|
+
**Example 1: Add a missing command**
|
|
113
|
+
User says: "Implement a minimal `ZRANK` command."
|
|
114
|
+
Actions: review `spec/SPEC_A.md`, inspect zset handlers and storage helpers, add `src/commands/zrank.js`, register it, add unit and integration coverage, update `README.md` only if support becomes public
|
|
115
|
+
Result: one new command works end to end with verified semantics
|
|
116
|
+
|
|
117
|
+
**Example 2: Fix a compatibility edge case**
|
|
118
|
+
User says: "Make `TTL` return the right value for missing keys."
|
|
119
|
+
Actions: inspect existing TTL tests, patch the owning logic, add a regression test, verify no unrelated TTL behavior changed
|
|
120
|
+
Result: client-visible compatibility improves with minimal code churn
|
|
121
|
+
|
|
122
|
+
## Troubleshooting
|
|
123
|
+
|
|
124
|
+
**Problem: The handler exists but the command still returns unsupported**
|
|
125
|
+
Cause: `src/commands/registry.js` was not updated, or the command name casing does not match dispatch behavior.
|
|
126
|
+
Solution: register the handler in uppercase form and verify the RESP command path through an integration test.
|
|
127
|
+
|
|
128
|
+
**Problem: The command works in unit tests but not through clients**
|
|
129
|
+
Cause: only internal logic was tested; RESP parsing, argument shape, or connection handling may differ.
|
|
130
|
+
Solution: add an integration test, and add a contract test if `redis-cli` or the official `redis` client is part of the promise.
|
|
131
|
+
|
|
132
|
+
**Problem: The change feels larger than one command**
|
|
133
|
+
Cause: the request may actually be a search feature or migration flow change rather than a generic command extension.
|
|
134
|
+
Solution: switch to the more specific RESPLite skill for migration or `FT.*` work instead of forcing everything into one command slice.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resplite-ft-search-workbench
|
|
3
|
+
description: Builds or refines RESPLite `FT.*` behavior and RediSearch migration mapping on top of SQLite FTS5. Use when the user says "add FT command support", "fix FT.SEARCH", "adjust SQLite FTS5 behavior", "migrate RediSearch indices", or "work on FT.CREATE or FT.ADD semantics". Do not use for unrelated command work outside the search surface.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Cursor Agent
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
category: workflow-automation
|
|
9
|
+
tags: [resplite, search, redisearch, sqlite, fts5]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# RESPLite FT Search Workbench
|
|
13
|
+
|
|
14
|
+
Use this skill for search-specific work where RediSearch-inspired behavior must stay grounded in what maps naturally to SQLite FTS5.
|
|
15
|
+
|
|
16
|
+
## Use cases
|
|
17
|
+
|
|
18
|
+
**Use Case: Add or refine an `FT.*` command**
|
|
19
|
+
Trigger: "implement FT command", "fix FT.SEARCH output", "support another FT option"
|
|
20
|
+
Steps: inspect the FT spec, trace command handler to SQLite search helpers, patch the narrowest layer, add unit and integration coverage, update docs if public behavior changed
|
|
21
|
+
Result: search behavior improves without pretending to support the full RediSearch surface
|
|
22
|
+
|
|
23
|
+
**Use Case: Work on index storage or ranking**
|
|
24
|
+
Trigger: "change FTS5 schema", "fix BM25 ordering", "debug search index behavior"
|
|
25
|
+
Steps: inspect per-index tables and search helpers, patch FTS mapping or metadata behavior, verify with search-focused tests
|
|
26
|
+
Result: SQLite-backed search behavior remains internally consistent and externally predictable
|
|
27
|
+
|
|
28
|
+
**Use Case: Improve RediSearch migration**
|
|
29
|
+
Trigger: "migrate FT indices", "map FT.INFO attributes", "handle TAG or NUMERIC fields"
|
|
30
|
+
Steps: inspect search migration mapping, keep support boundaries explicit, warn on downgraded or skipped fields, verify with unit tests
|
|
31
|
+
Result: migration is useful and honest about current limits
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
|
|
35
|
+
### Step 1: Start with the explicit search scope
|
|
36
|
+
|
|
37
|
+
Read these first:
|
|
38
|
+
|
|
39
|
+
- `spec/SPEC_D.md`
|
|
40
|
+
- `src/storage/sqlite/search.js`
|
|
41
|
+
- `src/commands/ft-create.js`
|
|
42
|
+
- `src/commands/ft-add.js`
|
|
43
|
+
- `src/commands/ft-search.js`
|
|
44
|
+
- `src/migration/migrate-search.js` when migration is involved
|
|
45
|
+
|
|
46
|
+
Then inspect the relevant tests:
|
|
47
|
+
|
|
48
|
+
- `test/unit/search.test.js`
|
|
49
|
+
- `test/integration/search.test.js`
|
|
50
|
+
- `test/unit/ft-parser.test.js`
|
|
51
|
+
- `test/unit/migrate-search.test.js`
|
|
52
|
+
|
|
53
|
+
### Step 2: Preserve RESPLite's search philosophy
|
|
54
|
+
|
|
55
|
+
Keep these design constraints visible while you work:
|
|
56
|
+
|
|
57
|
+
- search is RediSearch-inspired, not RediSearch-complete
|
|
58
|
+
- the implementation should feel natural for SQLite FTS5
|
|
59
|
+
- unsupported behavior should be explicit rather than approximated badly
|
|
60
|
+
- public docs should not overstate feature parity
|
|
61
|
+
|
|
62
|
+
If a requested feature requires excessive gymnastics or breaks the current storage model, prefer a scoped implementation or a clear unsupported response.
|
|
63
|
+
|
|
64
|
+
### Step 3: Change the correct layer
|
|
65
|
+
|
|
66
|
+
Use this split:
|
|
67
|
+
|
|
68
|
+
- syntax and RESP command shape: `src/commands/ft-*.js`
|
|
69
|
+
- index metadata, tables, search queries, suggestions: `src/storage/sqlite/search.js`
|
|
70
|
+
- migration from a source RediSearch instance: `src/migration/migrate-search.js`
|
|
71
|
+
|
|
72
|
+
Try not to duplicate validation rules across layers unless that duplication protects a stable public contract.
|
|
73
|
+
|
|
74
|
+
### Step 4: Keep storage and public behavior aligned
|
|
75
|
+
|
|
76
|
+
When you modify index or query behavior, verify these invariants:
|
|
77
|
+
|
|
78
|
+
- index names and field names stay validated
|
|
79
|
+
- supported field types are still explicit
|
|
80
|
+
- document insert or replace behavior remains atomic
|
|
81
|
+
- search result ordering still matches the chosen ranking rules
|
|
82
|
+
- docs and migration warnings reflect the real support level
|
|
83
|
+
|
|
84
|
+
If you widen support, also update `README.md` where the FT surface is described.
|
|
85
|
+
|
|
86
|
+
### Step 5: Test the exact path you changed
|
|
87
|
+
|
|
88
|
+
Use the narrowest relevant set:
|
|
89
|
+
|
|
90
|
+
- parser tests for argument and syntax behavior
|
|
91
|
+
- search unit tests for index helpers, query validation, ranking, and suggestion storage
|
|
92
|
+
- integration tests for RESP-facing `FT.*` behavior
|
|
93
|
+
- `migrate-search` tests for RediSearch compatibility and downgrade warnings
|
|
94
|
+
|
|
95
|
+
Prefer regression tests that capture the exact failure mode instead of broad smoke coverage only.
|
|
96
|
+
|
|
97
|
+
### Step 6: Close with support boundaries
|
|
98
|
+
|
|
99
|
+
Report:
|
|
100
|
+
|
|
101
|
+
- what `FT.*` behavior changed
|
|
102
|
+
- whether the change affects runtime search, migration, or both
|
|
103
|
+
- what remains intentionally unsupported
|
|
104
|
+
- which tests prove the new behavior
|
|
105
|
+
|
|
106
|
+
## RESPLite-specific checklist
|
|
107
|
+
|
|
108
|
+
- Keep the search surface consistent with `spec/SPEC_D.md`
|
|
109
|
+
- Do not imply full RediSearch parity
|
|
110
|
+
- Preserve the SQLite-first data model
|
|
111
|
+
- Keep migration warnings informative when mapping unsupported field types
|
|
112
|
+
- Update docs when public support changes
|
|
113
|
+
|
|
114
|
+
## Examples
|
|
115
|
+
|
|
116
|
+
**Example 1: Fix `FT.SEARCH` behavior**
|
|
117
|
+
User says: "Make `FT.SEARCH` reject invalid query characters consistently."
|
|
118
|
+
Actions: inspect query validation in `src/storage/sqlite/search.js`, add a regression test in `test/unit/search.test.js`, run search integration coverage if the RESP result changes
|
|
119
|
+
Result: search input validation is stricter and reproducible
|
|
120
|
+
|
|
121
|
+
**Example 2: Improve RediSearch migration mapping**
|
|
122
|
+
User says: "Map `NUMERIC` fields into the current schema as text and emit warnings."
|
|
123
|
+
Actions: inspect `src/migration/migrate-search.js` and `test/unit/migrate-search.test.js`, preserve current support boundaries, update tests to prove the downgrade behavior
|
|
124
|
+
Result: migration becomes more practical without claiming unsupported range-query semantics
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
**Problem: The feature request sounds like full RediSearch parity**
|
|
129
|
+
Cause: the requested behavior exceeds the current SQLite-first scope.
|
|
130
|
+
Solution: narrow the request to the subset that maps naturally to FTS5, document the unsupported parts, and avoid shipping misleading compatibility claims.
|
|
131
|
+
|
|
132
|
+
**Problem: Search tests pass but migration still breaks**
|
|
133
|
+
Cause: runtime `FT.*` behavior and migration mapping are separate code paths.
|
|
134
|
+
Solution: verify both `src/storage/sqlite/search.js` and `src/migration/migrate-search.js`, then run both search and migrate-search tests.
|
|
135
|
+
|
|
136
|
+
**Problem: Delete behavior or row mapping becomes inconsistent**
|
|
137
|
+
Cause: index storage invariants were changed without preserving the doc to row mapping assumptions.
|
|
138
|
+
Solution: review the per-index tables and their relationships in `src/storage/sqlite/search.js`, then add a focused regression test before expanding the change.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resplite-migration-cutover-assistant
|
|
3
|
+
description: Guides Redis to RESPLite migration work using the programmatic migration API, dirty-key tracking, cutover, and verification. Use when the user says "migrate Redis", "dirty tracker", "cutover", "resume bulk import", "verify migration", or "move RediSearch data during migration". Do not use for generic command work that does not touch the migration flow.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
author: Cursor Agent
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
category: workflow-automation
|
|
9
|
+
tags: [resplite, migration, redis, cutover, verification]
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# RESPLite Migration Cutover Assistant
|
|
13
|
+
|
|
14
|
+
Use this skill for migration work where correctness, resumability, and cutover sequencing matter more than raw implementation speed.
|
|
15
|
+
|
|
16
|
+
## Use cases
|
|
17
|
+
|
|
18
|
+
**Use Case: Drive a Redis to RESPLite migration**
|
|
19
|
+
Trigger: "help me migrate Redis", "create migration script", "plan cutover"
|
|
20
|
+
Steps: inspect the migration API, build or adjust a single-script flow, verify preflight, bulk, dirty tracking, cutover, and verification
|
|
21
|
+
Result: a reproducible migration workflow with minimal downtime
|
|
22
|
+
|
|
23
|
+
**Use Case: Fix dirty-key tracking or resumability**
|
|
24
|
+
Trigger: "dirty tracker missed keys", "resume is broken", "migration status is wrong"
|
|
25
|
+
Steps: inspect registry and tracker logic, reproduce through tests, fix the persistent state transitions, verify cutover semantics
|
|
26
|
+
Result: the migration state machine behaves predictably across interruptions
|
|
27
|
+
|
|
28
|
+
**Use Case: Add or change RediSearch migration behavior**
|
|
29
|
+
Trigger: "migrate FT indices", "search migration", "map RediSearch fields"
|
|
30
|
+
Steps: review `migrate-search`, map fields to current FT support, verify warnings and skipped cases, test the result with fake Redis or integration coverage
|
|
31
|
+
Result: search migration stays aligned with the current FT implementation
|
|
32
|
+
|
|
33
|
+
## Instructions
|
|
34
|
+
|
|
35
|
+
### Step 1: Prefer the programmatic API
|
|
36
|
+
|
|
37
|
+
Start from `resplite/migration`, not from deleted or legacy CLI paths. The current intended entry point is `createMigration()` in `src/migration/index.js`.
|
|
38
|
+
|
|
39
|
+
Read these sources first:
|
|
40
|
+
|
|
41
|
+
- `README.md` migration section
|
|
42
|
+
- `spec/SPEC_F.md`
|
|
43
|
+
- `src/migration/index.js`
|
|
44
|
+
- `src/migration/tracker.js`
|
|
45
|
+
- `src/migration/migrate-search.js` when `FT.*` is involved
|
|
46
|
+
|
|
47
|
+
If the requested change conflicts with the documented sequence, treat the documented cutover flow as the source of truth unless the task explicitly updates docs and behavior together.
|
|
48
|
+
|
|
49
|
+
### Step 2: Keep the real cutover model intact
|
|
50
|
+
|
|
51
|
+
Model the migration as these phases:
|
|
52
|
+
|
|
53
|
+
1. `preflight()`
|
|
54
|
+
2. `enableKeyspaceNotifications()`
|
|
55
|
+
3. `startDirtyTracker()`
|
|
56
|
+
4. `bulk({ resume: true })`
|
|
57
|
+
5. pause and freeze writes to Redis
|
|
58
|
+
6. `applyDirty()`
|
|
59
|
+
7. `stopDirtyTracker()`
|
|
60
|
+
8. `migrateSearch()` if the source uses `FT.*`
|
|
61
|
+
9. `verify()`
|
|
62
|
+
10. `close()`
|
|
63
|
+
|
|
64
|
+
Do not collapse cutover into "bulk then switch" if dirty tracking or write freeze is part of the scenario.
|
|
65
|
+
|
|
66
|
+
### Step 3: Preserve resumability and persistence semantics
|
|
67
|
+
|
|
68
|
+
When editing migration internals, make sure these properties stay true:
|
|
69
|
+
|
|
70
|
+
- bulk progress checkpoints can resume after interruption
|
|
71
|
+
- dirty keys are persisted in SQLite
|
|
72
|
+
- final cutover uses the last dirty set after writes are frozen
|
|
73
|
+
- status can be read from SQLite without Redis being connected
|
|
74
|
+
|
|
75
|
+
If the source Redis has a renamed `CONFIG` command, keep `configCommand` support working across both preflight and notification setup.
|
|
76
|
+
|
|
77
|
+
### Step 4: Distinguish KV migration from search migration
|
|
78
|
+
|
|
79
|
+
Keep these boundaries clear:
|
|
80
|
+
|
|
81
|
+
- `bulk` and `applyDirty` handle strings, hashes, sets, lists, and zsets
|
|
82
|
+
- `migrateSearch()` handles RediSearch schema and document migration separately
|
|
83
|
+
- search migration is not a substitute for the dirty-key delta flow
|
|
84
|
+
|
|
85
|
+
This separation keeps the code and operator workflow predictable.
|
|
86
|
+
|
|
87
|
+
### Step 5: Verify the exact failure mode
|
|
88
|
+
|
|
89
|
+
Use the narrowest useful test set:
|
|
90
|
+
|
|
91
|
+
- `test/integration/migration-dirty-tracker.test.js` for dirty tracking and cutover behavior
|
|
92
|
+
- `test/unit/migration-registry.test.js` for persistent registry semantics
|
|
93
|
+
- `test/unit/migrate-search.test.js` for RediSearch mapping and migration edge cases
|
|
94
|
+
|
|
95
|
+
If you change the public script examples or workflow guidance, update `README.md` so the docs and implementation stay in sync.
|
|
96
|
+
|
|
97
|
+
### Step 6: Report operationally, not just structurally
|
|
98
|
+
|
|
99
|
+
When closing the task, summarize:
|
|
100
|
+
|
|
101
|
+
- what phase of the migration flow changed
|
|
102
|
+
- whether the change affects operator cutover steps
|
|
103
|
+
- what verification was run
|
|
104
|
+
- any remaining assumptions about Redis configuration, notifications, or FT availability
|
|
105
|
+
|
|
106
|
+
## RESPLite-specific checklist
|
|
107
|
+
|
|
108
|
+
- Use the single-script programmatic flow as the happy path
|
|
109
|
+
- Treat the final dirty apply after write freeze as authoritative
|
|
110
|
+
- Keep `resume: true` behavior simple and restart-safe
|
|
111
|
+
- Preserve the distinction between key migration and search migration
|
|
112
|
+
- Update docs when operator-facing behavior changes
|
|
113
|
+
|
|
114
|
+
## Examples
|
|
115
|
+
|
|
116
|
+
**Example 1: Fix cutover sequencing**
|
|
117
|
+
User says: "The migration docs and code should make the final dirty apply happen only after writes are frozen."
|
|
118
|
+
Actions: review `README.md` and `spec/SPEC_F.md`, patch the sequencing if needed, adjust tests, verify the user-facing migration script matches the intended cutover flow
|
|
119
|
+
Result: docs, code, and tests describe the same operational sequence
|
|
120
|
+
|
|
121
|
+
**Example 2: Improve search migration**
|
|
122
|
+
User says: "Map RediSearch TAG fields into the current FT implementation with warnings."
|
|
123
|
+
Actions: inspect `src/migration/migrate-search.js`, preserve the current FT scope, update unit tests around field mapping, report unsupported field types clearly
|
|
124
|
+
Result: migration becomes more helpful without pretending to support unsupported search behavior
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
**Problem: Dirty tracking appears to miss updates**
|
|
129
|
+
Cause: keyspace notifications are not enabled, the tracker was not running during bulk, or the scenario expects durable CDC semantics that Redis notifications do not provide.
|
|
130
|
+
Solution: verify `enableKeyspaceNotifications()`, keep the tracker active during bulk, and rely on the final write freeze plus `applyDirty()` for authoritative cutover.
|
|
131
|
+
|
|
132
|
+
**Problem: Bulk resume logic is confusing**
|
|
133
|
+
Cause: code or docs treat first run and resumed run as separate flows.
|
|
134
|
+
Solution: keep `resume: true` as the default simple path and make sure the same script works for both start and resume.
|
|
135
|
+
|
|
136
|
+
**Problem: Search migration is mixed into the key delta**
|
|
137
|
+
Cause: the implementation is blurring `migrateSearch()` with key replication semantics.
|
|
138
|
+
Solution: keep the keyspace migration and RediSearch migration as separate steps, then verify each with the appropriate tests.
|
package/spec/00-INDEX.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# RESPLite Specifications — Index
|
|
2
|
+
|
|
3
|
+
Specifications are split by topic. Names are specific and ordered by dependency.
|
|
4
|
+
|
|
5
|
+
## Core (RESP server v1)
|
|
6
|
+
|
|
7
|
+
| File | Content |
|
|
8
|
+
|------|--------|
|
|
9
|
+
| [01-overview-and-goals.md](01-overview-and-goals.md) | Overview, product goals, non-goals, positioning |
|
|
10
|
+
| [02-protocol-and-commands.md](02-protocol-and-commands.md) | Protocol (RESP2), command scope, semantics, SET scope |
|
|
11
|
+
| [03-data-model-ttl-transactions.md](03-data-model-ttl-transactions.md) | Data model (SQLite schema), TTL/expiration, transaction rules |
|
|
12
|
+
| [04-cache-architecture.md](04-cache-architecture.md) | Hot cache, architecture layers, internal API shape |
|
|
13
|
+
| [05-scan-admin-implementation.md](05-scan-admin-implementation.md) | SCAN, admin commands (SQLITE.INFO, CACHE.INFO), project structure, testing, acceptance, implementation order |
|
|
14
|
+
| [06-migration-strategy-core.md](06-migration-strategy-core.md) | Migration strategy from Redis (programmatic), compatibility matrix, final design rule |
|
|
15
|
+
|
|
16
|
+
## Data types (beyond base v1)
|
|
17
|
+
|
|
18
|
+
| File | Content |
|
|
19
|
+
|------|--------|
|
|
20
|
+
| [07-type-lists.md](07-type-lists.md) | Lists (LPUSH, RPUSH, LPOP, RPOP, LLEN, LRANGE, LINDEX, …) — data model and behavior |
|
|
21
|
+
| [08-type-sorted-sets.md](08-type-sorted-sets.md) | Sorted sets (ZADD, ZREM, ZCARD, ZSCORE, ZRANGE, ZRANGEBYSCORE) — data model and behavior |
|
|
22
|
+
| [09-search-ft-commands.md](09-search-ft-commands.md) | Search (FT.CREATE, FT.ADD, FT.SEARCH, FT.SUG*, …) — FTS5/BM25, schema, parser grammar |
|
|
23
|
+
| [10-blocking-commands.md](10-blocking-commands.md) | Blocking list commands (BLPOP, BRPOP) — wait model, wakeup, tests |
|
|
24
|
+
|
|
25
|
+
## Migration (dirty key registry)
|
|
26
|
+
|
|
27
|
+
| File | Content |
|
|
28
|
+
|------|--------|
|
|
29
|
+
| [11-migration-dirty-registry.md](11-migration-dirty-registry.md) | Bulk import, dirty key tracker, delta apply, search index migration, operational guidance |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Implementation status (as of review)
|
|
34
|
+
|
|
35
|
+
- **Implemented:** All commands in §02 (connection, strings, TTL, hashes, sets, SCAN, admin), plus Lists (§07), Sorted Sets (§08), FT.* (§09), BLPOP/BRPOP (§10). Migration API with bulk, dirty tracker, apply-dirty, migrateSearch (§11).
|
|
36
|
+
- **Schema:** Matches §03 and extends to list/zset/search tables per §07, §08, §09.
|
|
37
|
+
- **Specs:** SPEC_A–F have been split into the files above; content is unchanged except in Appendix F: the duplicate “F.10 Search Index Migration” was renumbered to **F.12**, and “F.12 Operational Guidance” to **F.13**.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# RESPLite Specification v1 — Overview and Goals
|
|
2
|
+
|
|
3
|
+
## 1. Overview
|
|
4
|
+
|
|
5
|
+
RESPLite is a Redis-compatible subset server implemented in Node.js and backed by SQLite.
|
|
6
|
+
It exposes a TCP port that speaks RESP2 so existing Redis clients can connect to it.
|
|
7
|
+
The system is designed for single-node deployments where persistence, low operational overhead, and practical Redis compatibility matter more than full Redis feature parity.
|
|
8
|
+
|
|
9
|
+
This project is not a full Redis clone.
|
|
10
|
+
It is a RESP server with Redis-like semantics for a carefully selected subset of commands that map naturally and efficiently to SQLite.
|
|
11
|
+
|
|
12
|
+
Core principles:
|
|
13
|
+
|
|
14
|
+
- RESP-first product design
|
|
15
|
+
- SQLite as the persistent source of truth
|
|
16
|
+
- Hot in-memory cache for frequently accessed data
|
|
17
|
+
- Strictly scoped compatibility
|
|
18
|
+
- Strong correctness and test coverage before feature expansion
|
|
19
|
+
- No features that require unnatural or fragile implementation on SQLite
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. Product Goals
|
|
24
|
+
|
|
25
|
+
Version 1 focuses on the following goals:
|
|
26
|
+
|
|
27
|
+
- Expose a TCP server that speaks RESP2
|
|
28
|
+
- Support a useful subset of Redis commands
|
|
29
|
+
- Persist all data in SQLite
|
|
30
|
+
- Maintain practical compatibility with existing Redis clients
|
|
31
|
+
- Support strings, hashes, sets, and TTLs
|
|
32
|
+
- Provide SCAN and TYPE for basic introspection
|
|
33
|
+
- Keep the architecture ready for future FT.* commands powered by SQLite FTS5 with BM25 ranking
|
|
34
|
+
|
|
35
|
+
This project is intended to be packaged and distributed as an npm module, but v1 starts with RESP server mode only.
|
|
36
|
+
There is no embedded direct JavaScript API in the initial scope.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. Non-Goals
|
|
41
|
+
|
|
42
|
+
The following are explicitly out of scope for v1:
|
|
43
|
+
|
|
44
|
+
- Pub/Sub
|
|
45
|
+
- Streams
|
|
46
|
+
- Lua scripting
|
|
47
|
+
- Redis Cluster
|
|
48
|
+
- Replication
|
|
49
|
+
- MULTI / EXEC / WATCH
|
|
50
|
+
- Blocking commands such as BLPOP
|
|
51
|
+
- Multiple logical databases via SELECT
|
|
52
|
+
- Full edge-case parity with Redis for every command and protocol nuance
|
|
53
|
+
- Matching Redis performance for high-concurrency, memory-first workloads
|
|
54
|
+
|
|
55
|
+
The project should return a clear error for unsupported commands:
|
|
56
|
+
|
|
57
|
+
- `ERR command not supported yet`
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. Positioning
|
|
62
|
+
|
|
63
|
+
RESPLite should be described as:
|
|
64
|
+
|
|
65
|
+
> A RESP2 server with practical Redis compatibility, backed by SQLite for persistent single-node workloads.
|
|
66
|
+
|
|
67
|
+
It should not be described as:
|
|
68
|
+
|
|
69
|
+
- a full Redis replacement for all workloads
|
|
70
|
+
- a Redis Cluster alternative
|
|
71
|
+
- a low-latency in-memory data store competitor for large-scale write-heavy systems
|
|
72
|
+
|
|
73
|
+
The intended sweet spot is:
|
|
74
|
+
|
|
75
|
+
- bots
|
|
76
|
+
- internal tools
|
|
77
|
+
- small to medium web applications
|
|
78
|
+
- persistent caches
|
|
79
|
+
- local development environments
|
|
80
|
+
- low-ops VPS deployments
|
|
81
|
+
- metadata stores
|
|
82
|
+
- feature flags
|
|
83
|
+
- counters
|
|
84
|
+
- session-like state where persistence matters
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 5. Protocol
|
|
89
|
+
|
|
90
|
+
### 5.1 Supported protocol version
|
|
91
|
+
|
|
92
|
+
v1 supports:
|
|
93
|
+
|
|
94
|
+
- RESP2 only
|
|
95
|
+
|
|
96
|
+
RESP3 is out of scope for v1.
|
|
97
|
+
|
|
98
|
+
### 5.2 Wire compatibility target
|
|
99
|
+
|
|
100
|
+
The server should be compatible enough for practical use with:
|
|
101
|
+
|
|
102
|
+
- `redis-cli`
|
|
103
|
+
- the official `redis` npm client
|
|
104
|
+
|
|
105
|
+
The wire-level contract must correctly support:
|
|
106
|
+
|
|
107
|
+
- Simple Strings
|
|
108
|
+
- Bulk Strings
|
|
109
|
+
- Null Bulk Strings
|
|
110
|
+
- Integers
|
|
111
|
+
- Arrays
|
|
112
|
+
- Errors
|
|
113
|
+
|
|
114
|
+
### 5.3 Binary safety
|
|
115
|
+
|
|
116
|
+
The implementation must treat the following as binary-safe values:
|
|
117
|
+
|
|
118
|
+
- keys
|
|
119
|
+
- string values
|
|
120
|
+
- hash fields
|
|
121
|
+
- hash values
|
|
122
|
+
- set members
|
|
123
|
+
|
|
124
|
+
Internal command processing should use `Buffer` objects, not UTF-8 strings, as the default representation.
|
|
125
|
+
SQLite storage should use `BLOB` columns where appropriate.
|