@rebasepro/utils 0.9.0 → 0.9.1-canary.0de22e0

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/src/sha1.ts ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Minimal SHA-1 implementation that runs in both Node and the browser.
3
+ *
4
+ * This exists because generated Postgres policy names embed a SHA-1 digest of
5
+ * the security rule. The DDL generator runs on the server (where `node:crypto`
6
+ * is available) but the Studio has to derive the same names in the browser to
7
+ * tell a policy it generated apart from one it did not. `node:crypto` cannot be
8
+ * bundled for the browser, so the shared derivation needs a portable digest.
9
+ *
10
+ * SHA-1 is used purely to name things deterministically — never for security.
11
+ * The output is byte-identical to `createHash("sha1").update(str).digest("hex")`,
12
+ * which `sha1.test.ts` pins against `node:crypto` directly.
13
+ */
14
+
15
+ /** Rotate a 32-bit word left by `n` bits. */
16
+ function rotl(value: number, n: number): number {
17
+ return (value << n) | (value >>> (32 - n));
18
+ }
19
+
20
+ /**
21
+ * SHA-1 digest of a string, hex-encoded.
22
+ *
23
+ * The input is encoded as UTF-8, matching Node's default handling of strings
24
+ * passed to `hash.update(str)`.
25
+ */
26
+ export function sha1Hex(input: string): string {
27
+ const bytes: number[] = Array.from(new TextEncoder().encode(input));
28
+ const bitLength = bytes.length * 8;
29
+
30
+ // Padding: 0x80, then zeroes up to 56 bytes mod 64, then the length as a
31
+ // 64-bit big-endian integer.
32
+ bytes.push(0x80);
33
+ while (bytes.length % 64 !== 56) bytes.push(0);
34
+
35
+ const hi = Math.floor(bitLength / 0x100000000);
36
+ const lo = bitLength >>> 0;
37
+ bytes.push((hi >>> 24) & 0xff, (hi >>> 16) & 0xff, (hi >>> 8) & 0xff, hi & 0xff);
38
+ bytes.push((lo >>> 24) & 0xff, (lo >>> 16) & 0xff, (lo >>> 8) & 0xff, lo & 0xff);
39
+
40
+ let h0 = 0x67452301;
41
+ let h1 = 0xefcdab89;
42
+ let h2 = 0x98badcfe;
43
+ let h3 = 0x10325476;
44
+ let h4 = 0xc3d2e1f0;
45
+
46
+ const w = new Array<number>(80);
47
+
48
+ for (let offset = 0; offset < bytes.length; offset += 64) {
49
+ for (let i = 0; i < 16; i++) {
50
+ const j = offset + i * 4;
51
+ w[i] = ((bytes[j] << 24) | (bytes[j + 1] << 16) | (bytes[j + 2] << 8) | bytes[j + 3]) | 0;
52
+ }
53
+ for (let i = 16; i < 80; i++) {
54
+ w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
55
+ }
56
+
57
+ let a = h0;
58
+ let b = h1;
59
+ let c = h2;
60
+ let d = h3;
61
+ let e = h4;
62
+
63
+ for (let i = 0; i < 80; i++) {
64
+ let f: number;
65
+ let k: number;
66
+ if (i < 20) {
67
+ f = (b & c) | (~b & d);
68
+ k = 0x5a827999;
69
+ } else if (i < 40) {
70
+ f = b ^ c ^ d;
71
+ k = 0x6ed9eba1;
72
+ } else if (i < 60) {
73
+ f = (b & c) | (b & d) | (c & d);
74
+ k = 0x8f1bbcdc;
75
+ } else {
76
+ f = b ^ c ^ d;
77
+ k = 0xca62c1d6;
78
+ }
79
+
80
+ const temp = (rotl(a, 5) + f + e + k + w[i]) | 0;
81
+ e = d;
82
+ d = c;
83
+ c = rotl(b, 30);
84
+ b = a;
85
+ a = temp;
86
+ }
87
+
88
+ h0 = (h0 + a) | 0;
89
+ h1 = (h1 + b) | 0;
90
+ h2 = (h2 + c) | 0;
91
+ h3 = (h3 + d) | 0;
92
+ h4 = (h4 + e) | 0;
93
+ }
94
+
95
+ return [h0, h1, h2, h3, h4]
96
+ .map(word => (word >>> 0).toString(16).padStart(8, "0"))
97
+ .join("");
98
+ }
package/src/strings.ts CHANGED
@@ -37,8 +37,23 @@ export function camelCase(str: string): string {
37
37
  .join("");
38
38
  }
39
39
 
40
+ /**
41
+ * A random base-36 string of exactly `strLength` characters.
42
+ *
43
+ * Not `Math.random().toString(36).slice(2, 2 + strLength)`: that has no
44
+ * guaranteed length. Base-36 of a double drops trailing zeros, so the source
45
+ * string is short about once in 36 calls and the slice quietly returns fewer
46
+ * characters than asked for — `randomString(10)` returning 9. These values
47
+ * prefix uploaded filenames to keep them apart, so a short one is a likelier
48
+ * collision, and it fails at the rate that makes a test look flaky.
49
+ */
40
50
  export function randomString(strLength = 5) {
41
- return Math.random().toString(36).slice(2, 2 + strLength);
51
+ const alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
52
+ let result = "";
53
+ for (let i = 0; i < strLength; i++) {
54
+ result += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
55
+ }
56
+ return result;
42
57
  }
43
58
 
44
59
  export function randomColor() {