sliftutils 0.14.0 → 0.15.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/.cursorrules CHANGED
@@ -79,6 +79,10 @@ Coding Styles
79
79
 
80
80
  Never use environment variables. All configuration should be on the disk, or, if specific to a current run, passed as command line parameters.
81
81
 
82
+ Never use inline styles, always use the CSS helper.
83
+
84
+ Don't use as any.
85
+
82
86
 
83
87
  General Styling
84
88
  Never use em or rem. Only use px or vw/vh/%.
package/index.d.ts CHANGED
@@ -19,6 +19,7 @@ declare module "sliftutils/misc/fs" {
19
19
  }
20
20
 
21
21
  declare module "sliftutils/misc/getSecret" {
22
+ export declare function resetSecret(key: string): void;
22
23
  export declare const getSecret: {
23
24
  (key: string): Promise<string>;
24
25
  clear(key: string): void;
@@ -1,3 +1,4 @@
1
+ export declare function resetSecret(key: string): void;
1
2
  export declare const getSecret: {
2
3
  (key: string): Promise<string>;
3
4
  clear(key: string): void;
package/misc/getSecret.ts CHANGED
@@ -1,28 +1,99 @@
1
1
 
2
2
  import { cache } from "socket-function/src/caching";
3
- import os from "os";
4
- import fs from "fs";
3
+ import { isNode } from "typesafecss";
5
4
 
6
- export const getSecret = cache(async function getSecret(key: string): Promise<string> {
7
- const jsonIndex = key.indexOf(".json");
8
- if (jsonIndex === -1) {
9
- const filePath = os.homedir() + "/" + key;
10
- return fs.readFileSync(filePath, "utf-8").trim();
5
+ const secretStoragePrefix = "secret_";
6
+
7
+ function getStorageKey(key: string) {
8
+ return secretStoragePrefix + key.replace(/[\/\\\.]/g, "_");
9
+ }
10
+
11
+ export function resetSecret(key: string) {
12
+ if (isNode()) {
13
+ throw new Error("resetSecret is only supported in the browser");
11
14
  }
15
+ localStorage.removeItem(getStorageKey(key));
16
+ }
17
+
18
+ export const getSecret = cache(async function getSecret(key: string): Promise<string> {
19
+ if (isNode()) {
20
+ const os = await import("os");
21
+ const fs = await import("fs");
22
+ const jsonIndex = key.indexOf(".json");
23
+ if (jsonIndex === -1) {
24
+ const filePath = os.homedir() + "/" + key;
25
+ return fs.readFileSync(filePath, "utf-8").trim();
26
+ }
12
27
 
13
- const pathPart = key.slice(0, jsonIndex + ".json".length);
14
- const filePath = os.homedir() + "/" + pathPart;
15
- const contents = fs.readFileSync(filePath, "utf-8");
16
- const json = JSON.parse(contents);
28
+ const pathPart = key.slice(0, jsonIndex + ".json".length);
29
+ const filePath = os.homedir() + "/" + pathPart;
30
+ const contents = fs.readFileSync(filePath, "utf-8");
31
+ const json = JSON.parse(contents);
17
32
 
18
- const keyPart = key.slice(jsonIndex + ".json.".length);
19
- if (!keyPart) {
20
- return JSON.stringify(json);
33
+ const keyPart = key.slice(jsonIndex + ".json.".length);
34
+ if (!keyPart) {
35
+ return JSON.stringify(json);
36
+ }
37
+
38
+ const value = json[keyPart];
39
+ if (value === undefined) {
40
+ throw new Error(`Expected key "${keyPart}" in ${filePath}, was undefined`);
41
+ }
42
+ return String(value);
21
43
  }
22
44
 
23
- const value = json[keyPart];
24
- if (value === undefined) {
25
- throw new Error(`Expected key "${keyPart}" in ${filePath}, was undefined`);
45
+ // Browser implementation
46
+ const storageKey = getStorageKey(key);
47
+ const cached = localStorage.getItem(storageKey);
48
+ if (cached) {
49
+ return cached;
26
50
  }
27
- return String(value);
28
- });
51
+
52
+ // Show modal to prompt user for secret
53
+ const { showFullscreenModal, FullscreenModal } = await import("../render-utils/FullscreenModal");
54
+ const { showModal } = await import("../render-utils/modal");
55
+ const { observable } = await import("mobx");
56
+ const preact = await import("preact");
57
+
58
+ return new Promise<string>((resolve) => {
59
+ const state = observable({
60
+ value: "",
61
+ });
62
+
63
+ const { close } = showModal({
64
+ contents: preact.createElement(FullscreenModal, {
65
+ onCancel: () => {
66
+ // Don't allow cancel without a value
67
+ },
68
+ },
69
+ preact.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 10 } },
70
+ preact.createElement("div", { style: { fontWeight: "bold" } }, `Enter secret for: ${key}`),
71
+ preact.createElement("input", {
72
+ type: "password",
73
+ style: { padding: 10, fontSize: 16 },
74
+ onInput: (e: Event) => {
75
+ state.value = (e.target as HTMLInputElement).value;
76
+ },
77
+ onKeyDown: (e: KeyboardEvent) => {
78
+ if (e.code === "Enter" && state.value) {
79
+ localStorage.setItem(storageKey, state.value);
80
+ close();
81
+ resolve(state.value);
82
+ }
83
+ },
84
+ }),
85
+ preact.createElement("button", {
86
+ style: { padding: 10, fontSize: 16, cursor: "pointer" },
87
+ onClick: () => {
88
+ if (state.value) {
89
+ localStorage.setItem(storageKey, state.value);
90
+ close();
91
+ resolve(state.value);
92
+ }
93
+ },
94
+ }, "Save"),
95
+ ),
96
+ ),
97
+ });
98
+ });
99
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [