kami-redis 2.0.2 → 2.1.0
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/dist/index.d.ts +2365 -0
- package/dist/index.js +1 -241
- package/package.json +7 -2
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish.yml +0 -32
- package/.vscode/settings.json +0 -51
- package/CHANGELOG.md +0 -19
- package/bun.lock +0 -1237
- package/eslint.config.js +0 -28
- package/src/index.ts +0 -75
- package/src/utils/clean-up.ts +0 -3
- package/src/utils/format-value.ts +0 -16
- package/src/utils/get-value.ts +0 -18
- package/src/utils/graceful-exit.ts +0 -24
- package/src/utils/is-redis-url.ts +0 -23
- package/src/utils/prompt-for-key.ts +0 -30
- package/src/utils/view-key.ts +0 -95
- package/tsconfig.json +0 -27
- package/tsup.config.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -1,242 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/index.ts
|
|
4
|
-
import meow from "meow";
|
|
5
|
-
import pc2 from "picocolors";
|
|
6
|
-
import { createClient } from "redis";
|
|
7
|
-
|
|
8
|
-
// src/utils/clean-up.ts
|
|
9
|
-
function cleanup() {
|
|
10
|
-
return console.clear();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// src/utils/graceful-exit.ts
|
|
14
|
-
async function gracefulExit(code = 0) {
|
|
15
|
-
try {
|
|
16
|
-
if (process.stdin.isTTY) {
|
|
17
|
-
try {
|
|
18
|
-
process.stdin.setRawMode(false);
|
|
19
|
-
} catch {
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
process.stdin.pause();
|
|
24
|
-
} catch {
|
|
25
|
-
await client.quit();
|
|
26
|
-
}
|
|
27
|
-
} catch {
|
|
28
|
-
} finally {
|
|
29
|
-
cleanup();
|
|
30
|
-
process.exit(code);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// src/utils/is-redis-url.ts
|
|
35
|
-
function isRedisUrl(url2) {
|
|
36
|
-
let parsed;
|
|
37
|
-
try {
|
|
38
|
-
parsed = new URL(url2);
|
|
39
|
-
} catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
if (parsed.protocol !== "redis:" && parsed.protocol !== "rediss:") {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
if (!parsed.hostname) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
if (parsed.port && Number.isNaN(Number(parsed.port))) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// src/utils/prompt-for-key.ts
|
|
55
|
-
import inquirer from "inquirer";
|
|
56
|
-
async function promptForKey() {
|
|
57
|
-
const keys = await client.keys("*");
|
|
58
|
-
if (keys.length === 0)
|
|
59
|
-
return null;
|
|
60
|
-
try {
|
|
61
|
-
const { selectedKey } = await inquirer.prompt({
|
|
62
|
-
type: "list",
|
|
63
|
-
name: "selectedKey",
|
|
64
|
-
message: "Select a key to view its value:",
|
|
65
|
-
choices: keys,
|
|
66
|
-
pageSize: 20,
|
|
67
|
-
theme: {
|
|
68
|
-
icon: {
|
|
69
|
-
cursor: ">"
|
|
70
|
-
},
|
|
71
|
-
prefix: "0_0"
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
return selectedKey;
|
|
75
|
-
} catch {
|
|
76
|
-
await gracefulExit(0);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/utils/view-key.ts
|
|
81
|
-
import boxen from "boxen";
|
|
82
|
-
import highlight from "cli-highlight";
|
|
83
|
-
import clipboardy from "clipboardy";
|
|
84
|
-
import readline from "readline";
|
|
85
|
-
import pc from "picocolors";
|
|
86
|
-
|
|
87
|
-
// src/utils/format-value.ts
|
|
88
|
-
function formatValue(value) {
|
|
89
|
-
if (typeof value === "object" && value !== null) {
|
|
90
|
-
return JSON.stringify(value, null, 2);
|
|
91
|
-
}
|
|
92
|
-
if (typeof value === "string") {
|
|
93
|
-
try {
|
|
94
|
-
return JSON.stringify(JSON.parse(value), null, 2);
|
|
95
|
-
} catch {
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return String(value);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/utils/get-value.ts
|
|
103
|
-
async function getValue(selectedKey, type) {
|
|
104
|
-
switch (type) {
|
|
105
|
-
case "string":
|
|
106
|
-
return client.get(selectedKey);
|
|
107
|
-
case "hash":
|
|
108
|
-
return client.hGetAll(selectedKey);
|
|
109
|
-
case "list":
|
|
110
|
-
return client.lRange(selectedKey, 0, -1);
|
|
111
|
-
case "set":
|
|
112
|
-
return client.sMembers(selectedKey);
|
|
113
|
-
case "zset":
|
|
114
|
-
return client.zRangeWithScores(selectedKey, 0, -1);
|
|
115
|
-
default:
|
|
116
|
-
return "(unsupported type)";
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// src/utils/view-key.ts
|
|
121
|
-
async function viewKey(selectedKey) {
|
|
122
|
-
const type = await client.type(selectedKey);
|
|
123
|
-
const value = await getValue(selectedKey, type);
|
|
124
|
-
cleanup();
|
|
125
|
-
console.log(
|
|
126
|
-
boxen(highlight(formatValue(value), { language: "json", ignoreIllegals: true }), {
|
|
127
|
-
borderColor: "cyan",
|
|
128
|
-
padding: 1,
|
|
129
|
-
title: selectedKey,
|
|
130
|
-
borderStyle: "round"
|
|
131
|
-
})
|
|
132
|
-
);
|
|
133
|
-
console.log(pc.blue("Press 'd' to delete, 'c' to copy, \u2190 to go back, Ctrl+C to quit."));
|
|
134
|
-
readline.emitKeypressEvents(process.stdin);
|
|
135
|
-
try {
|
|
136
|
-
process.stdin.resume();
|
|
137
|
-
} catch {
|
|
138
|
-
}
|
|
139
|
-
if (process.stdin.isTTY) {
|
|
140
|
-
process.stdin.setRawMode(true);
|
|
141
|
-
}
|
|
142
|
-
return await new Promise((resolve) => {
|
|
143
|
-
const onKeypress = async (str, key) => {
|
|
144
|
-
if (!key) {
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (key.name === "d" && !key.ctrl && !key.meta) {
|
|
148
|
-
try {
|
|
149
|
-
await client.del(selectedKey);
|
|
150
|
-
} catch {
|
|
151
|
-
console.error(pc.red("Delete failed:"));
|
|
152
|
-
}
|
|
153
|
-
cleanup();
|
|
154
|
-
resolve("deleted");
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (key.name === "c" && !key.ctrl && !key.meta) {
|
|
158
|
-
try {
|
|
159
|
-
clipboardy.writeSync(formatValue(value));
|
|
160
|
-
cleanup();
|
|
161
|
-
resolve("back");
|
|
162
|
-
} catch (e) {
|
|
163
|
-
console.error(pc.red("Copy failed:"), e);
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (key.name === "left") {
|
|
168
|
-
cleanup();
|
|
169
|
-
resolve("back");
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (key.ctrl && key.name === "c" || key.sequence === "") {
|
|
173
|
-
cleanup();
|
|
174
|
-
resolve("quit");
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
const onData = async (chunk) => {
|
|
178
|
-
const s = chunk.toString();
|
|
179
|
-
if (s.includes("")) {
|
|
180
|
-
cleanup();
|
|
181
|
-
resolve("quit");
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
process.stdin.on("keypress", onKeypress);
|
|
185
|
-
process.stdin.on("data", onData);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// src/index.ts
|
|
190
|
-
var cli = meow(
|
|
191
|
-
`
|
|
192
|
-
Usage
|
|
193
|
-
kami-redis <url>
|
|
194
|
-
`,
|
|
195
|
-
{
|
|
196
|
-
importMeta: import.meta
|
|
197
|
-
}
|
|
198
|
-
);
|
|
199
|
-
var [url] = cli.input;
|
|
200
|
-
if (!url) {
|
|
201
|
-
console.log(cli.help);
|
|
202
|
-
process.exit(1);
|
|
203
|
-
}
|
|
204
|
-
if (!isRedisUrl(url)) {
|
|
205
|
-
console.log(cli.help);
|
|
206
|
-
console.log(pc2.red("Provided URL is not a valid Redis URL"));
|
|
207
|
-
process.exit(1);
|
|
208
|
-
}
|
|
209
|
-
var client = createClient({ url });
|
|
210
|
-
async function main() {
|
|
211
|
-
try {
|
|
212
|
-
cleanup();
|
|
213
|
-
await client.connect();
|
|
214
|
-
while (true) {
|
|
215
|
-
const selectedKey = await promptForKey();
|
|
216
|
-
if (!selectedKey) {
|
|
217
|
-
console.log("No keys in Redis!");
|
|
218
|
-
await client.quit();
|
|
219
|
-
process.exit(0);
|
|
220
|
-
}
|
|
221
|
-
const action = await viewKey(selectedKey);
|
|
222
|
-
if (action === "quit") {
|
|
223
|
-
await gracefulExit(0);
|
|
224
|
-
} else if (action === "deleted") {
|
|
225
|
-
continue;
|
|
226
|
-
} else if (action === "back") {
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
} catch (err) {
|
|
231
|
-
console.error(pc2.red("Unexpected error:"), err);
|
|
232
|
-
try {
|
|
233
|
-
await client.quit();
|
|
234
|
-
} catch {
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
main();
|
|
240
|
-
export {
|
|
241
|
-
client
|
|
242
|
-
};
|
|
2
|
+
import K from"meow";import h from"picocolors";import{createClient as E}from"redis";function p(e){try{let r=new URL(e);return(r.protocol==="redis:"||r.protocol==="rediss:")&&!!r.hostname&&(!r.port||!Number.isNaN(Number(r.port)))}catch{return!1}}import b from"inquirer";async function m(e=0){try{if(process.stdin.isTTY)try{process.stdin.setRawMode(!1)}catch{}try{process.stdin.pause()}catch{await t.quit()}}catch{}finally{console.clear(),process.exit(e)}}async function u(){let e=await t.keys("*");if(e.length===0)return null;try{let{selectedKey:r}=await b.prompt({type:"list",name:"selectedKey",message:"Select a key to view its value:",choices:e,pageSize:20,theme:{icon:{cursor:">"},prefix:"0_0"}});return r}catch{await m(0)}}import R from"boxen";import{highlight as q}from"cli-highlight";import N from"readline";import S from"picocolors";function f(e){if(typeof e=="object"&&e!==null)return JSON.stringify(e,null,2);if(typeof e=="string")try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}return String(e)}async function d(e,r){switch(r){case"string":return t.get(e);case"hash":return t.hGetAll(e);case"list":return t.lRange(e,0,-1);case"set":return t.sMembers(e);case"zset":return t.zRangeWithScores(e,0,-1);default:return"(unsupported type)"}}var y=!1;function T(){!y&&process.stdin.isTTY&&(N.emitKeypressEvents(process.stdin),y=!0)}async function g(e){let r=await t.type(e),w=await d(e,r);return console.clear(),console.log(R(q(f(w),{language:"json",ignoreIllegals:!0}),{borderColor:"cyan",padding:1,title:e,borderStyle:"round"})),console.log(S.dim("d: delete | c: copy | \u2190: back | ctrl+c: quit")),T(),new Promise(s=>{let n=!1,i=()=>{if(!n){if(n=!0,process.stdin.removeListener("keypress",l),process.stdin.isTTY)try{process.stdin.setRawMode(!1)}catch{}process.stdin.pause()}},l=async(M,o)=>{if(!(!o||n)){if(o.ctrl&&o.name==="c"){i(),console.clear(),s("quit");return}if(o.name==="d"){i();try{await t.del(e)}catch{}console.clear(),s("deleted");return}if(o.name==="c"){try{console.log("Copied to clipboard!")}catch(x){console.log("Error copying:",x)}i(),console.clear(),s("back");return}o.name==="left"&&(i(),console.clear(),s("back"))}};process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("keypress",l)})}var c=K("Usage: kami-redis <url>",{importMeta:import.meta}),[a]=c.input;a||(console.log(c.help),process.exit(1));p(a)||(console.log(c.help),console.log(h.red("Invalid Redis URL")),process.exit(1));var t=E({url:a});async function I(){try{for(console.clear(),await t.connect();;){let e=await u();e||(console.log("No keys in Redis"),await t.quit(),process.exit(0)),await g(e)==="quit"&&(await t.quit(),process.exit(0))}}catch(e){console.error(h.red("Error:"),e);try{await t.quit()}catch{}process.exit(1)}}process.on("SIGINT",async()=>{try{await t.quit()}catch{}process.exit(0)});I();export{t as client};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kami-redis",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"description": "Browse, inspect, copy, and delete Redis keys from your CLI",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -10,9 +10,14 @@
|
|
|
10
10
|
"bin": {
|
|
11
11
|
"kami-redis": "dist/index.js"
|
|
12
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"/dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"package.json"
|
|
17
|
+
],
|
|
13
18
|
"scripts": {
|
|
14
19
|
"dev": "bun run --watch src/index.ts",
|
|
15
|
-
"build": "tsup
|
|
20
|
+
"build": "tsup",
|
|
16
21
|
"lint": "eslint",
|
|
17
22
|
"lint:fix": "eslint --fix",
|
|
18
23
|
"release": "bun run build && changeset publish",
|
package/.changeset/README.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
|
|
4
|
-
with multi-package repos, or single-package repos to help you version and publish your code. You can
|
|
5
|
-
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
|
|
6
|
-
|
|
7
|
-
We have a quick list of common questions to get you started engaging with this project in
|
|
8
|
-
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
|
package/.changeset/config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
|
3
|
-
"changelog": "@changesets/cli/changelog",
|
|
4
|
-
"commit": false,
|
|
5
|
-
"fixed": [],
|
|
6
|
-
"linked": [],
|
|
7
|
-
"access": "public",
|
|
8
|
-
"baseBranch": "main",
|
|
9
|
-
"updateInternalDependencies": "patch",
|
|
10
|
-
"ignore": []
|
|
11
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- "**"
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
build:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- uses: actions/checkout@v3
|
|
12
|
-
- uses: oven-sh/setup-bun@v2
|
|
13
|
-
with:
|
|
14
|
-
bun-version: latest
|
|
15
|
-
|
|
16
|
-
- run: bun install
|
|
17
|
-
- run: bun run lint && bun run build
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
on:
|
|
3
|
-
workflow_run:
|
|
4
|
-
workflows: [CI]
|
|
5
|
-
branches: [main]
|
|
6
|
-
types: [completed]
|
|
7
|
-
|
|
8
|
-
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: write
|
|
12
|
-
pull-requests: write
|
|
13
|
-
|
|
14
|
-
jobs:
|
|
15
|
-
publish:
|
|
16
|
-
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
17
|
-
runs-on: ubuntu-latest
|
|
18
|
-
steps:
|
|
19
|
-
- uses: actions/checkout@v3
|
|
20
|
-
- uses: oven-sh/setup-bun@v2
|
|
21
|
-
with:
|
|
22
|
-
bun-version: latest
|
|
23
|
-
|
|
24
|
-
- run: bun install
|
|
25
|
-
- name: Create Release Pull Request or Publish
|
|
26
|
-
id: changesets
|
|
27
|
-
uses: changesets/action@v1
|
|
28
|
-
with:
|
|
29
|
-
publish: bun run release
|
|
30
|
-
env:
|
|
31
|
-
GITHUB_TOKEN: ${{ secrets.GHUB_TOKEN }}
|
|
32
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/.vscode/settings.json
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Disable the default formatter, use eslint instead
|
|
3
|
-
"prettier.enable": false,
|
|
4
|
-
"editor.formatOnSave": false,
|
|
5
|
-
|
|
6
|
-
// Auto fix
|
|
7
|
-
"editor.codeActionsOnSave": {
|
|
8
|
-
"source.fixAll.eslint": "explicit",
|
|
9
|
-
"source.organizeImports": "never"
|
|
10
|
-
},
|
|
11
|
-
|
|
12
|
-
// Silent the stylistic rules in you IDE, but still auto fix them
|
|
13
|
-
"eslint.rules.customizations": [
|
|
14
|
-
{ "rule": "style/*", "severity": "off", "fixable": true },
|
|
15
|
-
{ "rule": "format/*", "severity": "off", "fixable": true },
|
|
16
|
-
{ "rule": "*-indent", "severity": "off", "fixable": true },
|
|
17
|
-
{ "rule": "*-spacing", "severity": "off", "fixable": true },
|
|
18
|
-
{ "rule": "*-spaces", "severity": "off", "fixable": true },
|
|
19
|
-
{ "rule": "*-order", "severity": "off", "fixable": true },
|
|
20
|
-
{ "rule": "*-dangle", "severity": "off", "fixable": true },
|
|
21
|
-
{ "rule": "*-newline", "severity": "off", "fixable": true },
|
|
22
|
-
{ "rule": "*quotes", "severity": "off", "fixable": true },
|
|
23
|
-
{ "rule": "*semi", "severity": "off", "fixable": true }
|
|
24
|
-
],
|
|
25
|
-
|
|
26
|
-
// Enable eslint for all supported languages
|
|
27
|
-
"eslint.validate": [
|
|
28
|
-
"javascript",
|
|
29
|
-
"javascriptreact",
|
|
30
|
-
"typescript",
|
|
31
|
-
"typescriptreact",
|
|
32
|
-
"vue",
|
|
33
|
-
"html",
|
|
34
|
-
"markdown",
|
|
35
|
-
"json",
|
|
36
|
-
"json5",
|
|
37
|
-
"jsonc",
|
|
38
|
-
"yaml",
|
|
39
|
-
"toml",
|
|
40
|
-
"xml",
|
|
41
|
-
"gql",
|
|
42
|
-
"graphql",
|
|
43
|
-
"astro",
|
|
44
|
-
"svelte",
|
|
45
|
-
"css",
|
|
46
|
-
"less",
|
|
47
|
-
"scss",
|
|
48
|
-
"pcss",
|
|
49
|
-
"postcss"
|
|
50
|
-
]
|
|
51
|
-
}
|
package/CHANGELOG.md
DELETED