@evolu/common 6.0.1-preview.24 → 6.0.1-preview.26
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/src/Assert.d.ts +0 -13
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +0 -15
- package/dist/src/Cache.d.ts +44 -0
- package/dist/src/Cache.d.ts.map +1 -0
- package/dist/src/Cache.js +52 -0
- package/dist/src/Evolu/Db.d.ts +6 -6
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +4 -0
- package/dist/src/Evolu/LocalAuth.d.ts +2 -2
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.d.ts +116 -86
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +48 -45
- package/dist/src/Evolu/Relay.d.ts +6 -5
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +40 -39
- package/dist/src/Evolu/Storage.d.ts +6 -11
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +30 -9
- package/dist/src/Evolu/Sync.d.ts +5 -5
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +3 -5
- package/dist/src/Evolu/Timestamp.d.ts +24 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +24 -0
- package/dist/src/Identicon.d.ts +35 -0
- package/dist/src/Identicon.d.ts.map +1 -0
- package/dist/src/Identicon.js +143 -0
- package/dist/src/ManyToManyMap.d.ts +0 -3
- package/dist/src/ManyToManyMap.d.ts.map +1 -1
- package/dist/src/Result.d.ts +13 -6
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Sqlite.d.ts +36 -1
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +56 -3
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +36 -0
- package/dist/src/Type.d.ts +73 -9
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +124 -22
- package/dist/src/Types.d.ts +1 -1
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +2 -7
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/package.json +1 -1
- package/src/Assert.ts +0 -19
- package/src/Cache.ts +85 -0
- package/src/Evolu/Db.ts +11 -7
- package/src/Evolu/LocalAuth.ts +19 -7
- package/src/Evolu/Owner.ts +140 -103
- package/src/Evolu/Relay.ts +52 -48
- package/src/Evolu/Storage.ts +47 -23
- package/src/Evolu/Sync.ts +11 -12
- package/src/Evolu/Timestamp.ts +24 -0
- package/src/Identicon.ts +197 -0
- package/src/ManyToManyMap.ts +0 -3
- package/src/Result.ts +13 -6
- package/src/Sqlite.ts +68 -5
- package/src/Task.ts +41 -0
- package/src/Type.ts +262 -27
- package/src/Types.ts +1 -1
- package/src/WebSocket.ts +6 -10
- package/src/index.ts +2 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { idToIdBytes } from "./Type.js";
|
|
2
|
+
import { md5 } from "@noble/hashes/legacy.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a deterministic identicon SVG from an {@link Id}.
|
|
5
|
+
*
|
|
6
|
+
* Works with any {@link Id} including branded IDs like `OwnerId`, etc.
|
|
7
|
+
*
|
|
8
|
+
* Available styles:
|
|
9
|
+
*
|
|
10
|
+
* - `"github"` (default): 5x5 grid with horizontal mirroring (GitHub-style)
|
|
11
|
+
* - `"quadrant"`: 2x2 grid with direct RGB color mapping from bytes
|
|
12
|
+
* - `"gradient"`: Diagonal stripes with smooth color gradients
|
|
13
|
+
* - `"sutnar"`: Three compositional variants with adaptive colors
|
|
14
|
+
*
|
|
15
|
+
* ### Example
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const svg = createIdenticon(id);
|
|
19
|
+
* const quadrantStyle = createIdenticon(id, "quadrant");
|
|
20
|
+
* const gradientStyle = createIdenticon(id, "gradient");
|
|
21
|
+
* const sutnarStyle = createIdenticon(id, "sutnar");
|
|
22
|
+
*
|
|
23
|
+
* // Works with branded IDs
|
|
24
|
+
* const ownerSvg = createIdenticon(ownerId);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const createIdenticon = (id, style = "github") => {
|
|
28
|
+
const bytes = idToIdBytes(id);
|
|
29
|
+
switch (style) {
|
|
30
|
+
case "github": {
|
|
31
|
+
// GitHub-style identicon: MD5 hash the bytes first
|
|
32
|
+
const hashedBytes = md5(bytes);
|
|
33
|
+
// Map function for value ranges
|
|
34
|
+
const map = (value, inMin, inMax, outMin, outMax) => ((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
|
35
|
+
// Extract 12-bit hue from bytes[12] (lower 4 bits) + bytes[13]
|
|
36
|
+
const h = ((hashedBytes[12] & 0x0f) << 8) | hashedBytes[13];
|
|
37
|
+
const hue = map(h, 0, 4095, 0, 360);
|
|
38
|
+
const saturation = 65 - map(hashedBytes[14], 0, 255, 0, 20);
|
|
39
|
+
const lightness = 75 - map(hashedBytes[15], 0, 255, 0, 20);
|
|
40
|
+
const fgColor = `hsl(${hue},${saturation}%,${lightness}%)`;
|
|
41
|
+
const bgColor = `hsl(${hue},${saturation}%,90%)`;
|
|
42
|
+
let rects = `<rect width="5" height="5" fill="${bgColor}"/>`;
|
|
43
|
+
// Extract nibbles and generate pattern
|
|
44
|
+
let nibbleIndex = 0;
|
|
45
|
+
for (let x = 2; x >= 0; x--) {
|
|
46
|
+
for (let y = 0; y < 5; y++) {
|
|
47
|
+
const byte = hashedBytes[Math.floor(nibbleIndex / 2)];
|
|
48
|
+
const nibble = nibbleIndex % 2 === 0 ? byte >> 4 : byte & 0x0f;
|
|
49
|
+
const paint = nibble % 2 === 0;
|
|
50
|
+
nibbleIndex++;
|
|
51
|
+
if (paint) {
|
|
52
|
+
rects += `<rect x="${x}" y="${y}" width="1" height="1" fill="${fgColor}"/>`;
|
|
53
|
+
const mx = 4 - x;
|
|
54
|
+
if (mx !== x) {
|
|
55
|
+
rects += `<rect x="${mx}" y="${y}" width="1" height="1" fill="${fgColor}"/>`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5 5" shape-rendering="crispEdges">${rects}</svg>`;
|
|
61
|
+
}
|
|
62
|
+
case "quadrant": {
|
|
63
|
+
const toHex = (b) => b.toString(16).padStart(2, "0");
|
|
64
|
+
let rects = "";
|
|
65
|
+
for (let i = 0; i < 4; i++) {
|
|
66
|
+
const x = i % 2;
|
|
67
|
+
const y = Math.floor(i / 2);
|
|
68
|
+
const r = bytes[i * 3];
|
|
69
|
+
const g = bytes[i * 3 + 1];
|
|
70
|
+
const b = bytes[i * 3 + 2];
|
|
71
|
+
const color = `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
72
|
+
rects += `<rect x="${x}" y="${y}" width="1" height="1" fill="${color}"/>`;
|
|
73
|
+
}
|
|
74
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2">${rects}</svg>`;
|
|
75
|
+
}
|
|
76
|
+
case "gradient": {
|
|
77
|
+
// Smooth color gradients with diagonal stripes.
|
|
78
|
+
const toHex = (b) => b.toString(16).padStart(2, "0");
|
|
79
|
+
// Generate colors from bytes.
|
|
80
|
+
const color1 = `#${toHex(bytes[0])}${toHex(bytes[1])}${toHex(bytes[2])}`;
|
|
81
|
+
const color2 = `#${toHex(bytes[3])}${toHex(bytes[4])}${toHex(bytes[5])}`;
|
|
82
|
+
const color3 = `#${toHex(bytes[6])}${toHex(bytes[7])}${toHex(bytes[8])}`;
|
|
83
|
+
let defs = "";
|
|
84
|
+
let shapes = "";
|
|
85
|
+
// Diagonal stripes with gradient.
|
|
86
|
+
defs += `<linearGradient id="grad1-${id}" x1="0%" y1="0%" x2="0%" y2="100%">`;
|
|
87
|
+
defs += `<stop offset="0%" style="stop-color:${color1};stop-opacity:1" />`;
|
|
88
|
+
defs += `<stop offset="100%" style="stop-color:${color2};stop-opacity:1" />`;
|
|
89
|
+
defs += `</linearGradient>`;
|
|
90
|
+
defs += `<linearGradient id="grad2-${id}" x1="0%" y1="0%" x2="0%" y2="100%">`;
|
|
91
|
+
defs += `<stop offset="0%" style="stop-color:${color2};stop-opacity:1" />`;
|
|
92
|
+
defs += `<stop offset="100%" style="stop-color:${color3};stop-opacity:1" />`;
|
|
93
|
+
defs += `</linearGradient>`;
|
|
94
|
+
shapes += `<rect width="100" height="100" fill="url(#grad1-${id})"/>`;
|
|
95
|
+
const stripeWidth = 15 + (bytes[9] / 255) * 20;
|
|
96
|
+
const angle = 30 + (bytes[10] / 255) * 60;
|
|
97
|
+
shapes += `<rect x="20" y="-50" width="${stripeWidth}" height="200" fill="url(#grad2-${id})" transform="rotate(${angle} 50 50)" opacity="0.7"/>`;
|
|
98
|
+
shapes += `<rect x="60" y="-50" width="${stripeWidth}" height="200" fill="url(#grad2-${id})" transform="rotate(${angle} 50 50)" opacity="0.5"/>`;
|
|
99
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs>${defs}</defs>${shapes}</svg>`;
|
|
100
|
+
}
|
|
101
|
+
case "sutnar": {
|
|
102
|
+
// Three compositional variants with adaptive colors.
|
|
103
|
+
const hue = (bytes[0] / 255) * 360;
|
|
104
|
+
const saturation = 50 + (bytes[1] / 255) * 30;
|
|
105
|
+
const lightness = 50 + (bytes[2] / 255) * 20;
|
|
106
|
+
// Generate palette from base hue with variations
|
|
107
|
+
const toHsl = (h, s, l) => `hsl(${h},${s}%,${l}%)`;
|
|
108
|
+
const color1 = toHsl(hue, saturation, lightness);
|
|
109
|
+
const color2 = toHsl((hue + 120) % 360, saturation, lightness);
|
|
110
|
+
const color3 = toHsl((hue + 240) % 360, saturation, lightness);
|
|
111
|
+
const color4 = toHsl(hue, saturation * 0.3, lightness * 0.5);
|
|
112
|
+
const color5 = toHsl(hue, saturation * 0.5, Math.min(lightness * 1.3, 90));
|
|
113
|
+
const palette = [color1, color2, color3, color4, color5];
|
|
114
|
+
// Layout variant based on first byte.
|
|
115
|
+
const variant = bytes[3] % 3;
|
|
116
|
+
let shapes = "";
|
|
117
|
+
// Almost white background with subtle tint.
|
|
118
|
+
shapes += `<rect width="100" height="100" fill="${toHsl(hue, 10, 95)}"/>`;
|
|
119
|
+
if (variant === 0) {
|
|
120
|
+
// Composition A: Circle + horizontal bar.
|
|
121
|
+
const circleColor = palette[bytes[4] % palette.length];
|
|
122
|
+
const barColor = palette[(bytes[4] + 1) % palette.length];
|
|
123
|
+
shapes += `<circle cx="30" cy="50" r="22" fill="${circleColor}"/>`;
|
|
124
|
+
shapes += `<rect x="60" y="40" width="35" height="20" fill="${barColor}"/>`;
|
|
125
|
+
}
|
|
126
|
+
else if (variant === 1) {
|
|
127
|
+
// Composition B: Vertical bar + circle.
|
|
128
|
+
const barColor = palette[bytes[5] % palette.length];
|
|
129
|
+
const circleColor = palette[(bytes[5] + 1) % palette.length];
|
|
130
|
+
shapes += `<rect x="15" y="10" width="18" height="80" fill="${barColor}"/>`;
|
|
131
|
+
shapes += `<circle cx="70" cy="50" r="15" fill="${circleColor}"/>`;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Composition C: Square + circle.
|
|
135
|
+
const squareColor = palette[bytes[6] % palette.length];
|
|
136
|
+
const circleColor = palette[(bytes[6] + 1) % palette.length];
|
|
137
|
+
shapes += `<rect x="20" y="20" width="30" height="30" fill="${squareColor}"/>`;
|
|
138
|
+
shapes += `<circle cx="70" cy="70" r="18" fill="${circleColor}"/>`;
|
|
139
|
+
}
|
|
140
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${shapes}</svg>`;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
@@ -20,9 +20,6 @@
|
|
|
20
20
|
* - `deleteKey` and `deleteValue` are O(d) where d is the number of associated
|
|
21
21
|
* values / keys (the degree). This is optimal because every associated pair
|
|
22
22
|
* must be touched once.
|
|
23
|
-
* - In the Relay use case a socket (value) typically has only dozens of owners
|
|
24
|
-
* (degree small), and connection closes (triggering deleteValue) are
|
|
25
|
-
* relatively infrequent, so O(d) is acceptable.
|
|
26
23
|
*
|
|
27
24
|
* Object identity:
|
|
28
25
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ManyToManyMap.d.ts","sourceRoot":"","sources":["../../src/ManyToManyMap.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"ManyToManyMap.d.ts","sourceRoot":"","sources":["../../src/ManyToManyMap.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC;IACjC;;;OAGG;IACH,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEnC;;;OAGG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC;;;OAGG;IACH,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAElD;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAElD;;;OAGG;IACH,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC;IAExD;;;OAGG;IACH,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEpE,kDAAkD;IAClD,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEvC,yCAAyC;IACzC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAE5B,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEhC,0CAA0C;IAC1C,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAE/B,4CAA4C;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEnC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,mDAAmD;IACnD,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,iEAAiE;IACjE,SAAS,EAAE,MAAM,MAAM,CAAC;CACzB;AAED,uCAAuC;AACvC,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,CAAC,OAAK,aAAa,CAAC,CAAC,EAAE,CAAC,CA2I9D,CAAC"}
|
package/dist/src/Result.d.ts
CHANGED
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
* ### Naming Convention
|
|
88
88
|
*
|
|
89
89
|
* - For values: `const user = getUser()`
|
|
90
|
-
* - For void
|
|
91
|
-
* - For
|
|
90
|
+
* - For a single void operation: `const result = foo()`
|
|
91
|
+
* - For multiple void operations: use descriptive names for all
|
|
92
92
|
*
|
|
93
93
|
* ```ts
|
|
94
94
|
* const processUser = () => {
|
|
@@ -96,13 +96,20 @@
|
|
|
96
96
|
* const user = getUser();
|
|
97
97
|
* if (!user.ok) return user;
|
|
98
98
|
*
|
|
99
|
-
* // void operation
|
|
99
|
+
* // single void operation
|
|
100
100
|
* const result = saveToDatabase(user.value);
|
|
101
101
|
* if (!result.ok) return result;
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
103
|
+
* return ok();
|
|
104
|
+
* };
|
|
105
|
+
*
|
|
106
|
+
* const setupDatabase = () => {
|
|
107
|
+
* // multiple void operations - use descriptive names
|
|
108
|
+
* const baseTables = createBaseTables();
|
|
109
|
+
* if (!baseTables.ok) return baseTables;
|
|
110
|
+
*
|
|
111
|
+
* const relayTables = createRelayTables();
|
|
112
|
+
* if (!relayTables.ok) return relayTables;
|
|
106
113
|
*
|
|
107
114
|
* return ok();
|
|
108
115
|
* };
|
package/dist/src/Result.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Result.d.ts","sourceRoot":"","sources":["../../src/Result.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"Result.d.ts","sourceRoot":"","sources":["../../src/Result.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgVG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAE1C,mCAAmC;AACnC,MAAM,WAAW,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAC5C,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEpC;;;;GAIG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAC7C,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAErC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AAC/B,2DAA2D;AAC3D,wBAAgB,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AAKvC;;;;;;;;;GASG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,GAAG,CAAC,CAAC,CAA2B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,CAMvD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,CAAC,GAAG,IAC1B,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,CAAC,EAC1B,IAAI,MAAM,CAAC,EACX,UAAU,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,KAC9B,MAAM,CAAC,CAAC,EAAE,CAAC,CAMb,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,eAAO,MAAM,QAAQ,GAAU,CAAC,EAAE,CAAC,EACjC,WAAW,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,UAAU,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC,KAC9B,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAIpB,CAAC"}
|
package/dist/src/Sqlite.d.ts
CHANGED
|
@@ -111,13 +111,48 @@ export interface RawSql {
|
|
|
111
111
|
sql: string;
|
|
112
112
|
}
|
|
113
113
|
export type SqlTemplateParam = SqliteValue | SqlIdentifier | RawSql;
|
|
114
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* Creates a safe SQL query using a tagged template literal.
|
|
116
|
+
*
|
|
117
|
+
* Parameters are automatically escaped and bound as SQLite values. Use
|
|
118
|
+
* `sql.identifier` for column/table names and `sql.raw` for unescaped SQL.
|
|
119
|
+
*
|
|
120
|
+
* ### Example
|
|
121
|
+
*
|
|
122
|
+
* ```ts
|
|
123
|
+
* const id = 42;
|
|
124
|
+
* const name = "Alice";
|
|
125
|
+
*
|
|
126
|
+
* const result = sqlite.exec(sql`
|
|
127
|
+
* select *
|
|
128
|
+
* from users
|
|
129
|
+
* where id = ${id} and name = ${name};
|
|
130
|
+
* `);
|
|
131
|
+
*
|
|
132
|
+
* // For identifiers
|
|
133
|
+
* const tableName = "users";
|
|
134
|
+
* sqlite.exec(sql`
|
|
135
|
+
* create table ${sql.identifier(tableName)} (
|
|
136
|
+
* "id" text primary key,
|
|
137
|
+
* "name" text not null
|
|
138
|
+
* );
|
|
139
|
+
* `);
|
|
140
|
+
*
|
|
141
|
+
* // For raw SQL (use with caution)
|
|
142
|
+
* const orderBy = "created_at desc";
|
|
143
|
+
* sqlite.exec(sql`select * from users order by ${sql.raw(orderBy)};`);
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
115
146
|
export declare const sql: {
|
|
116
147
|
(strings: TemplateStringsArray, ...parameters: Array<SqlTemplateParam>): SqliteQuery;
|
|
117
148
|
identifier(identifier: string): SqlIdentifier;
|
|
118
149
|
raw(raw: string): RawSql;
|
|
119
150
|
prepared(strings: TemplateStringsArray, ...parameters: Array<SqlTemplateParam>): SqliteQuery;
|
|
120
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Checks if a SQL string contains mutation keywords (insert, update, delete,
|
|
154
|
+
* etc.). Results are cached for performance.
|
|
155
|
+
*/
|
|
121
156
|
export declare const isSqlMutation: Predicate<string>;
|
|
122
157
|
export interface SqliteQueryPlanRow {
|
|
123
158
|
id: number;
|
package/dist/src/Sqlite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Sqlite.d.ts","sourceRoot":"","sources":["../../src/Sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Sqlite.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { createLruCache } from "./Cache.js";
|
|
1
2
|
import { createTransferableError } from "./Error.js";
|
|
2
3
|
import { err, ok, tryAsync, trySync } from "./Result.js";
|
|
3
|
-
import { Null, Number, String, Uint8Array, union } from "./Type.js";
|
|
4
|
+
import { Null, Number, PositiveInt, String, Uint8Array, union, } from "./Type.js";
|
|
4
5
|
/**
|
|
5
6
|
* A value that can be stored in Sqlite.
|
|
6
7
|
*
|
|
@@ -121,7 +122,38 @@ export const createPreparedStatementsCache = (factory, disposeFn) => {
|
|
|
121
122
|
},
|
|
122
123
|
};
|
|
123
124
|
};
|
|
124
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Creates a safe SQL query using a tagged template literal.
|
|
127
|
+
*
|
|
128
|
+
* Parameters are automatically escaped and bound as SQLite values. Use
|
|
129
|
+
* `sql.identifier` for column/table names and `sql.raw` for unescaped SQL.
|
|
130
|
+
*
|
|
131
|
+
* ### Example
|
|
132
|
+
*
|
|
133
|
+
* ```ts
|
|
134
|
+
* const id = 42;
|
|
135
|
+
* const name = "Alice";
|
|
136
|
+
*
|
|
137
|
+
* const result = sqlite.exec(sql`
|
|
138
|
+
* select *
|
|
139
|
+
* from users
|
|
140
|
+
* where id = ${id} and name = ${name};
|
|
141
|
+
* `);
|
|
142
|
+
*
|
|
143
|
+
* // For identifiers
|
|
144
|
+
* const tableName = "users";
|
|
145
|
+
* sqlite.exec(sql`
|
|
146
|
+
* create table ${sql.identifier(tableName)} (
|
|
147
|
+
* "id" text primary key,
|
|
148
|
+
* "name" text not null
|
|
149
|
+
* );
|
|
150
|
+
* `);
|
|
151
|
+
*
|
|
152
|
+
* // For raw SQL (use with caution)
|
|
153
|
+
* const orderBy = "created_at desc";
|
|
154
|
+
* sqlite.exec(sql`select * from users order by ${sql.raw(orderBy)};`);
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
125
157
|
export const sql = (strings, ...parameters) => {
|
|
126
158
|
let sql = "";
|
|
127
159
|
const values = [];
|
|
@@ -158,6 +190,25 @@ sql.prepared = (strings, ...parameters) => {
|
|
|
158
190
|
const query = sql(strings, ...parameters);
|
|
159
191
|
return { ...query, options: { prepare: true } };
|
|
160
192
|
};
|
|
193
|
+
/**
|
|
194
|
+
* Checks if a SQL string contains mutation keywords (insert, update, delete,
|
|
195
|
+
* etc.). Results are cached for performance.
|
|
196
|
+
*/
|
|
197
|
+
export const isSqlMutation = (sql) => {
|
|
198
|
+
/**
|
|
199
|
+
* Without cache, "insert 1_000_000" Storage test dropped from 57742
|
|
200
|
+
* inserts/sec to 34k. Regex we used was fast, but CodeQL flagged it as a
|
|
201
|
+
* potential ReDoS vulnerability, so manual comment removal was the only
|
|
202
|
+
* option. LRU cache restores performance.
|
|
203
|
+
*/
|
|
204
|
+
const cached = isSqlMutationCache.get(sql);
|
|
205
|
+
if (cached !== undefined)
|
|
206
|
+
return cached;
|
|
207
|
+
const result = isSqlMutationRegEx.test(removeSqlComments(sql));
|
|
208
|
+
isSqlMutationCache.set(sql, result);
|
|
209
|
+
return result;
|
|
210
|
+
};
|
|
211
|
+
const isSqlMutationCache = createLruCache(PositiveInt.orThrow(10_000));
|
|
161
212
|
const isSqlMutationRegEx = new RegExp(`\\b(${[
|
|
162
213
|
"alter",
|
|
163
214
|
"create",
|
|
@@ -177,6 +228,9 @@ const isSqlMutationRegEx = new RegExp(`\\b(${[
|
|
|
177
228
|
* ReDoS vulnerabilities.
|
|
178
229
|
*/
|
|
179
230
|
const removeSqlComments = (sql) => {
|
|
231
|
+
// Fast path: if there are no comments, return the original string
|
|
232
|
+
if (!sql.includes("--"))
|
|
233
|
+
return sql;
|
|
180
234
|
let result = "";
|
|
181
235
|
let i = 0;
|
|
182
236
|
while (i < sql.length) {
|
|
@@ -200,7 +254,6 @@ const removeSqlComments = (sql) => {
|
|
|
200
254
|
}
|
|
201
255
|
return result;
|
|
202
256
|
};
|
|
203
|
-
export const isSqlMutation = (sql) => isSqlMutationRegEx.test(removeSqlComments(sql));
|
|
204
257
|
export const explainSqliteQueryPlan = (deps) => (query) => {
|
|
205
258
|
const result = deps.sqlite.exec({
|
|
206
259
|
...query,
|
package/dist/src/Task.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,MAAM,EAAW,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAA4B,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAkB,WAAW,EAAE,MAAM,WAAW,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2IG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,EAAE,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IAEH,CAAC,QAAQ,SAAS,WAAW,GAAG,SAAS,GAAG,SAAS,EACnD,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CACR,MAAM,CAAC,CAAC,EAAE,QAAQ,SAAS;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,CACzE,CAAC;CACH;AAED,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,uEAAuE;AACvE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"Task.d.ts","sourceRoot":"","sources":["../../src/Task.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Task.js
CHANGED
|
@@ -11,6 +11,28 @@ import { PositiveInt } from "./Type.js";
|
|
|
11
11
|
const isAbortError = (error) => typeof error === "object" &&
|
|
12
12
|
error !== null &&
|
|
13
13
|
error.type === "AbortError";
|
|
14
|
+
// For React Native
|
|
15
|
+
if (typeof AbortSignal.any !== "function") {
|
|
16
|
+
AbortSignal.any = function (signals) {
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
const onAbort = (event) => {
|
|
19
|
+
controller.abort(event.target.reason);
|
|
20
|
+
cleanup();
|
|
21
|
+
};
|
|
22
|
+
const cleanup = () => {
|
|
23
|
+
for (const s of signals)
|
|
24
|
+
s.removeEventListener("abort", onAbort);
|
|
25
|
+
};
|
|
26
|
+
for (const s of signals) {
|
|
27
|
+
if (s.aborted) {
|
|
28
|
+
controller.abort(s.reason);
|
|
29
|
+
return controller.signal;
|
|
30
|
+
}
|
|
31
|
+
s.addEventListener("abort", onAbort);
|
|
32
|
+
}
|
|
33
|
+
return controller.signal;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
14
36
|
/**
|
|
15
37
|
* Combines user signal from context with an internal signal.
|
|
16
38
|
*
|
|
@@ -80,6 +102,20 @@ export const toTask = (fn) =>
|
|
|
80
102
|
}),
|
|
81
103
|
]);
|
|
82
104
|
});
|
|
105
|
+
// For React Native
|
|
106
|
+
if (typeof AbortSignal.timeout !== "function") {
|
|
107
|
+
AbortSignal.timeout = function (ms) {
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const id = setTimeout(() => {
|
|
110
|
+
controller.abort();
|
|
111
|
+
}, ms);
|
|
112
|
+
// clear timeout if aborted early
|
|
113
|
+
controller.signal.addEventListener("abort", () => {
|
|
114
|
+
clearTimeout(id);
|
|
115
|
+
});
|
|
116
|
+
return controller.signal;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
83
119
|
/**
|
|
84
120
|
* Creates a {@link Task} that waits for the specified duration.
|
|
85
121
|
*
|
package/dist/src/Type.d.ts
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* {@link Result}) instead of throwing. We either get a safely typed value or a
|
|
6
6
|
* precise, composable error value telling us exactly why validation failed.
|
|
7
7
|
*
|
|
8
|
+
* Evolu Type supports [Standard Schema](https://standardschema.dev/) for
|
|
9
|
+
* interoperability with 40+ validation-compatible tools and frameworks.
|
|
10
|
+
*
|
|
8
11
|
* Why another validation library?
|
|
9
12
|
*
|
|
10
13
|
* - **Result-based error handling** – no exceptions for normal control flow.
|
|
@@ -184,7 +187,7 @@ Error extends TypeError = never,
|
|
|
184
187
|
/** The parent type. */
|
|
185
188
|
Parent = T,
|
|
186
189
|
/** The parent's error. */
|
|
187
|
-
ParentError extends TypeError = Error> {
|
|
190
|
+
ParentError extends TypeError = Error> extends StandardSchemaV1<Input, T> {
|
|
188
191
|
readonly name: Name;
|
|
189
192
|
/**
|
|
190
193
|
* Creates `T` from an `Input` value.
|
|
@@ -235,7 +238,6 @@ ParentError extends TypeError = Error> {
|
|
|
235
238
|
*
|
|
236
239
|
* - When you need to convert a validation result to a nullable value
|
|
237
240
|
* - When the error is not important and you just want the value or nothing
|
|
238
|
-
* - APIs that expect `T | null`
|
|
239
241
|
*
|
|
240
242
|
* ### Example
|
|
241
243
|
*
|
|
@@ -342,8 +344,6 @@ ParentError extends TypeError = Error> {
|
|
|
342
344
|
*/
|
|
343
345
|
readonly ParentError: ParentError;
|
|
344
346
|
/**
|
|
345
|
-
* Error | ParentError
|
|
346
|
-
*
|
|
347
347
|
* ### Example
|
|
348
348
|
*
|
|
349
349
|
* ```ts
|
|
@@ -412,7 +412,7 @@ export type InferParent<A extends AnyType> = A extends Type<any, any, any, any,
|
|
|
412
412
|
*/
|
|
413
413
|
export type InferParentError<A extends AnyType> = A extends Type<any, any, any, any, any, infer ParentError> ? ParentError : never;
|
|
414
414
|
/**
|
|
415
|
-
* Extracts all error types
|
|
415
|
+
* Extracts all error types from a {@link Type}.
|
|
416
416
|
*
|
|
417
417
|
* @category Utilities
|
|
418
418
|
*/
|
|
@@ -1126,7 +1126,7 @@ export declare const idBytesTypeValueLength: NonNegativeInt;
|
|
|
1126
1126
|
export declare const idToIdBytes: (id: Id) => IdBytes;
|
|
1127
1127
|
export declare const idBytesToId: (idBytes: IdBytes) => Id;
|
|
1128
1128
|
/**
|
|
1129
|
-
* Positive number.
|
|
1129
|
+
* Positive number (> 0).
|
|
1130
1130
|
*
|
|
1131
1131
|
* ### Example
|
|
1132
1132
|
*
|
|
@@ -1144,7 +1144,7 @@ export interface PositiveError extends TypeError<"Positive"> {
|
|
|
1144
1144
|
}
|
|
1145
1145
|
export declare const formatPositiveError: TypeErrorFormatter<PositiveError>;
|
|
1146
1146
|
/**
|
|
1147
|
-
* Negative number.
|
|
1147
|
+
* Negative number (< 0).
|
|
1148
1148
|
*
|
|
1149
1149
|
* ### Example
|
|
1150
1150
|
*
|
|
@@ -1159,7 +1159,7 @@ export interface NegativeError extends TypeError<"Negative"> {
|
|
|
1159
1159
|
}
|
|
1160
1160
|
export declare const formatNegativeError: TypeErrorFormatter<NegativeError>;
|
|
1161
1161
|
/**
|
|
1162
|
-
* Non-positive number.
|
|
1162
|
+
* Non-positive number (≤ 0).
|
|
1163
1163
|
*
|
|
1164
1164
|
* ### Example
|
|
1165
1165
|
*
|
|
@@ -1174,7 +1174,7 @@ export interface NonPositiveError extends TypeError<"NonPositive"> {
|
|
|
1174
1174
|
}
|
|
1175
1175
|
export declare const formatNonPositiveError: TypeErrorFormatter<NonPositiveError>;
|
|
1176
1176
|
/**
|
|
1177
|
-
* Non-negative number.
|
|
1177
|
+
* Non-negative number (≥ 0).
|
|
1178
1178
|
*
|
|
1179
1179
|
* ### Example
|
|
1180
1180
|
*
|
|
@@ -2103,5 +2103,69 @@ export type TypeErrors<ExtraErrors extends TypeError = never> = StringError | Nu
|
|
|
2103
2103
|
* @category Utilities
|
|
2104
2104
|
*/
|
|
2105
2105
|
export declare const createFormatTypeError: <ExtraErrors extends TypeError = never>(extraFormatter?: TypeErrorFormatter<ExtraErrors>) => TypeErrorFormatter<TypeErrors<ExtraErrors>>;
|
|
2106
|
+
/**
|
|
2107
|
+
* Converts an Evolu {@link TypeError} to Standard Schema V1 issues format.
|
|
2108
|
+
*
|
|
2109
|
+
* This function recursively converts Evolu's typed errors into the Standard
|
|
2110
|
+
* Schema issue format with proper path tracking for nested structures.
|
|
2111
|
+
*
|
|
2112
|
+
* @category Utilities
|
|
2113
|
+
*/
|
|
2114
|
+
export declare const typeErrorToStandardSchemaIssues: <ExtraErrors extends TypeError = never>(error: TypeErrors<ExtraErrors>, formatTypeError: TypeErrorFormatter<TypeErrors<ExtraErrors>>, path?: ReadonlyArray<PropertyKey>) => ReadonlyArray<StandardSchemaV1.Issue>;
|
|
2115
|
+
/** The Standard Schema interface. */
|
|
2116
|
+
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
2117
|
+
/** The Standard Schema properties. */
|
|
2118
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
2119
|
+
}
|
|
2120
|
+
export declare namespace StandardSchemaV1 {
|
|
2121
|
+
/** The Standard Schema properties interface. */
|
|
2122
|
+
interface Props<Input = unknown, Output = Input> {
|
|
2123
|
+
/** The version number of the standard. */
|
|
2124
|
+
readonly version: 1;
|
|
2125
|
+
/** The vendor name of the schema library. */
|
|
2126
|
+
readonly vendor: string;
|
|
2127
|
+
/** Validates unknown input values. */
|
|
2128
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
2129
|
+
/** Inferred types associated with the schema. */
|
|
2130
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
2131
|
+
}
|
|
2132
|
+
/** The result interface of the validate function. */
|
|
2133
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
2134
|
+
/** The result interface if validation succeeds. */
|
|
2135
|
+
interface SuccessResult<Output> {
|
|
2136
|
+
/** The typed output value. */
|
|
2137
|
+
readonly value: Output;
|
|
2138
|
+
/** The non-existent issues. */
|
|
2139
|
+
readonly issues?: undefined;
|
|
2140
|
+
}
|
|
2141
|
+
/** The result interface if validation fails. */
|
|
2142
|
+
interface FailureResult {
|
|
2143
|
+
/** The issues of failed validation. */
|
|
2144
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
2145
|
+
}
|
|
2146
|
+
/** The issue interface of the failure output. */
|
|
2147
|
+
interface Issue {
|
|
2148
|
+
/** The error message of the issue. */
|
|
2149
|
+
readonly message: string;
|
|
2150
|
+
/** The path of the issue, if any. */
|
|
2151
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
2152
|
+
}
|
|
2153
|
+
/** The path segment interface of the issue. */
|
|
2154
|
+
interface PathSegment {
|
|
2155
|
+
/** The key representing a path segment. */
|
|
2156
|
+
readonly key: PropertyKey;
|
|
2157
|
+
}
|
|
2158
|
+
/** The Standard Schema types interface. */
|
|
2159
|
+
interface Types<Input = unknown, Output = Input> {
|
|
2160
|
+
/** The input type of the schema. */
|
|
2161
|
+
readonly input: Input;
|
|
2162
|
+
/** The output type of the schema. */
|
|
2163
|
+
readonly output: Output;
|
|
2164
|
+
}
|
|
2165
|
+
/** Infers the input type of a Standard Schema. */
|
|
2166
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
2167
|
+
/** Infers the output type of a Standard Schema. */
|
|
2168
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
2169
|
+
}
|
|
2106
2170
|
export {};
|
|
2107
2171
|
//# sourceMappingURL=Type.d.ts.map
|