@nice-code/util 0.2.9 → 0.2.11

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.
Files changed (3) hide show
  1. package/README.md +159 -1
  2. package/build/index.js +204 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1 +1,159 @@
1
- # @nice-code/utils
1
+ # @nice-code/util
2
+
3
+ Typed storage adapters for browser, Cloudflare Durable Objects, and in-memory use.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ bun add @nice-code/util
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Typed storage
14
+
15
+ `createTypedStorage` wraps a `StorageAdapter` and adds full TypeScript key and value inference based on a schema type parameter.
16
+
17
+ ```ts
18
+ import { createTypedWebLocalStorage } from "@nice-code/util";
19
+
20
+ // Define the shape of your storage
21
+ interface IAppStorage {
22
+ user_id: string;
23
+ theme: "light" | "dark";
24
+ last_seen: number;
25
+ }
26
+
27
+ const storage = createTypedWebLocalStorage<IAppStorage>(localStorage, "app:");
28
+
29
+ // All keys autocomplete; values are typed
30
+ await storage.setJson("theme", "dark");
31
+ const theme = await storage.getJson("theme"); // "light" | "dark" | undefined
32
+ const userId = await storage.getJsonOrDef("user_id", "guest"); // string
33
+ await storage.removeItem("last_seen");
34
+ ```
35
+
36
+ All methods are async and key-prefixed if a prefix is provided.
37
+
38
+ ---
39
+
40
+ ## Available adapters
41
+
42
+ ### Browser — `localStorage` / `sessionStorage`
43
+
44
+ ```ts
45
+ import {
46
+ createTypedWebLocalStorage,
47
+ createTypedWebSessionStorage,
48
+ } from "@nice-code/util";
49
+
50
+ const local = createTypedWebLocalStorage<IAppStorage>(localStorage, "prefix:");
51
+ const session = createTypedWebSessionStorage<IAppStorage>(sessionStorage);
52
+ ```
53
+
54
+ ### Cloudflare Durable Objects
55
+
56
+ ```ts
57
+ import { createDurableObjectTypedStorage } from "@nice-code/util";
58
+
59
+ // Inside a Durable Object class
60
+ export class MyDO {
61
+ private storage: ITypedStorage<IDOStorage>;
62
+
63
+ constructor(state: DurableObjectState) {
64
+ this.storage = createDurableObjectTypedStorage<IDOStorage>(state.storage, "do:");
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### In-memory (testing / SSR)
70
+
71
+ ```ts
72
+ import {
73
+ createTypedMemoryStorage_string,
74
+ createTypedMemoryStorage_json,
75
+ } from "@nice-code/util";
76
+
77
+ // String-serialized (like localStorage)
78
+ const store = createTypedMemoryStorage_string<IAppStorage>();
79
+
80
+ // JSON-native (no serialization overhead)
81
+ const jsonStore = createTypedMemoryStorage_json<IAppStorage>();
82
+
83
+ // Pass in your own Map to share state between instances
84
+ const shared = new Map<string, string>();
85
+ const a = createTypedMemoryStorage_string<IAppStorage>(shared);
86
+ const b = createTypedMemoryStorage_string<IAppStorage>(shared);
87
+ ```
88
+
89
+ ---
90
+
91
+ ## `ITypedStorage<T>` interface
92
+
93
+ ```ts
94
+ interface ITypedStorage<T extends Record<string, any>> {
95
+ getJson<K extends keyof T & string>(key: K): Promise<T[K] | undefined>;
96
+ getJsonOrDef<K extends keyof T & string>(key: K, defVal: T[K]): Promise<T[K]>;
97
+ setJson<K extends keyof T & string>(key: K, val: T[K]): Promise<void>;
98
+ removeItem<K extends keyof T & string>(key: K): Promise<void>;
99
+ }
100
+ ```
101
+
102
+ ---
103
+
104
+ ## `StorageAdapter` — low-level
105
+
106
+ Use `StorageAdapter` directly when you need a getter/setter pair or want to build a custom typed storage on top.
107
+
108
+ ```ts
109
+ import { StorageAdapter } from "@nice-code/util";
110
+ import { createMemoryStorageMethods_string } from "@nice-code/util";
111
+
112
+ const adapter = new StorageAdapter({
113
+ methods: createMemoryStorageMethods_string(),
114
+ keyPrefix: "myapp:",
115
+ });
116
+
117
+ await adapter.setJson("token", { value: "abc", exp: 9999 });
118
+ const token = await adapter.getJson<{ value: string; exp: number }>("token");
119
+ const safe = await adapter.getJsonOrDef("token", { value: "", exp: 0 });
120
+
121
+ // Convenient getter/setter pair for a single key
122
+ const { get, set } = adapter.createJsonGetterSetter<string>("theme");
123
+ await set("dark");
124
+ const theme = await get(); // string | undefined
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Custom adapter
130
+
131
+ Implement `TStorageAdapterMethods` to wrap any storage backend:
132
+
133
+ ```ts
134
+ import type { IStorageAdapterMethods_String } from "@nice-code/util";
135
+ import { EStorageAdapterType } from "@nice-code/util";
136
+
137
+ const redisMethods: IStorageAdapterMethods_String = {
138
+ type: EStorageAdapterType.string,
139
+ getItem: async (key) => redis.get(key),
140
+ setItem: async (key, value) => { await redis.set(key, value); },
141
+ removeItem: async (key) => { await redis.del(key); },
142
+ };
143
+
144
+ const storage = createTypedStorage<IMySchema>({
145
+ storageAdapter: new StorageAdapter({ methods: redisMethods, keyPrefix: "app:" }),
146
+ });
147
+ ```
148
+
149
+ ---
150
+
151
+ ## TypeScript utilities
152
+
153
+ ```ts
154
+ import type { StringKeys } from "@nice-code/util";
155
+
156
+ // Extracts string keys from a type
157
+ type Keys = StringKeys<{ a: string; b: number; 0: boolean }>;
158
+ // → "a" | "b"
159
+ ```
package/build/index.js CHANGED
@@ -1,8 +1,204 @@
1
- // src/index.ts
2
- export * from "./storage_adapter/StorageAdapter";
3
- export * from "./storage_adapter/specific/browser/browser_storage";
4
- export * from "./storage_adapter/specific/durable_object/durable_object_storage";
5
- export * from "./storage_adapter/specific/memory/memory_storage";
6
- export * from "./storage_adapter/storage_adapter.types";
7
- export * from "./storage_adapter/typed_storage/createTypedStorage";
8
- export * from "./typescript/special_typescript_types";
1
+ // src/storage_adapter/storage_adapter.types.ts
2
+ var EStorageAdapterType;
3
+ ((EStorageAdapterType2) => {
4
+ EStorageAdapterType2["string"] = "string";
5
+ EStorageAdapterType2["json"] = "json";
6
+ })(EStorageAdapterType ||= {});
7
+
8
+ // src/storage_adapter/StorageAdapter.ts
9
+ class StorageAdapter {
10
+ implementation;
11
+ keyPrefix;
12
+ constructor({ methods, keyPrefix }) {
13
+ this.implementation = methods;
14
+ this.keyPrefix = keyPrefix ?? "";
15
+ }
16
+ getPrefixedKey(key) {
17
+ return `${this.keyPrefix}${key}`;
18
+ }
19
+ async removeItem(key) {
20
+ await this.implementation.removeItem(this.getPrefixedKey(key));
21
+ }
22
+ async setJson(key, value) {
23
+ if (this.implementation.type === "string" /* string */) {
24
+ await this.implementation.setItem(this.getPrefixedKey(key), JSON.stringify(value));
25
+ } else {
26
+ await this.implementation.setItem(this.getPrefixedKey(key), value);
27
+ }
28
+ }
29
+ async getJson(key) {
30
+ if (this.implementation.type === "string" /* string */) {
31
+ const val = await this.implementation.getItem(this.getPrefixedKey(key));
32
+ if (val == null || val === "undefined" || val === "null") {
33
+ return;
34
+ }
35
+ return JSON.parse(val);
36
+ } else {
37
+ const val = await this.implementation.getItem(this.getPrefixedKey(key));
38
+ if (val == null || val === "undefined" || val === "null") {
39
+ return;
40
+ }
41
+ return val;
42
+ }
43
+ }
44
+ async getJsonOrDef(key, defVal) {
45
+ if (this.implementation.type === "string" /* string */) {
46
+ const val2 = await this.implementation.getItem(this.getPrefixedKey(key));
47
+ if (val2 == null || val2 === "undefined" || val2 === "null") {
48
+ return defVal;
49
+ }
50
+ return JSON.parse(val2);
51
+ }
52
+ const val = await this.implementation.getItem(this.getPrefixedKey(key));
53
+ if (val == null || val === "undefined" || val === "null") {
54
+ return defVal;
55
+ }
56
+ return val;
57
+ }
58
+ createJsonGetterSetter(key) {
59
+ return {
60
+ get: () => this.getJson(key),
61
+ set: (value) => this.setJson(key, value)
62
+ };
63
+ }
64
+ }
65
+ // src/storage_adapter/typed_storage/createTypedStorage.ts
66
+ function createTypedStorage({
67
+ storageAdapter
68
+ }) {
69
+ const getJson = async (key) => {
70
+ return storageAdapter.getJson(key);
71
+ };
72
+ const getJsonOrDef = async (key, defVal) => {
73
+ return await storageAdapter.getJson(key) ?? defVal;
74
+ };
75
+ const setJson = async (key, val) => {
76
+ return storageAdapter.setJson(key, val);
77
+ };
78
+ const removeItem = async (key) => {
79
+ await storageAdapter.removeItem(key);
80
+ };
81
+ return {
82
+ getJson,
83
+ getJsonOrDef,
84
+ setJson,
85
+ removeItem
86
+ };
87
+ }
88
+
89
+ // src/storage_adapter/specific/browser/browser_storage.ts
90
+ function createWebLocalStorageMethods(_localStorage) {
91
+ return {
92
+ type: "string" /* string */,
93
+ getItem: async (key) => _localStorage.getItem(key),
94
+ setItem: async (key, value) => {
95
+ _localStorage.setItem(key, value);
96
+ },
97
+ removeItem: async (key) => {
98
+ _localStorage.removeItem(key);
99
+ }
100
+ };
101
+ }
102
+ function createTypedWebLocalStorage(_localStorage, keyPrefix) {
103
+ return createTypedStorage({
104
+ storageAdapter: new StorageAdapter({
105
+ methods: createWebLocalStorageMethods(_localStorage),
106
+ keyPrefix
107
+ })
108
+ });
109
+ }
110
+ function createWebSessionStorageMethods(_sessionStorage) {
111
+ return {
112
+ type: "string" /* string */,
113
+ getItem: async (key) => _sessionStorage.getItem(key),
114
+ setItem: async (key, value) => {
115
+ _sessionStorage.setItem(key, value);
116
+ },
117
+ removeItem: async (key) => {
118
+ _sessionStorage.removeItem(key);
119
+ }
120
+ };
121
+ }
122
+ function createTypedWebSessionStorage(_sessionStorage, keyPrefix) {
123
+ return createTypedStorage({
124
+ storageAdapter: new StorageAdapter({
125
+ methods: createWebSessionStorageMethods(_sessionStorage),
126
+ keyPrefix
127
+ })
128
+ });
129
+ }
130
+ // src/storage_adapter/specific/durable_object/durable_object_storage.ts
131
+ function createDurableObjectStorageMethods(durableObjectStorage) {
132
+ return {
133
+ type: "json" /* json */,
134
+ getItem: (key) => durableObjectStorage.get(key),
135
+ setItem: (key, value) => durableObjectStorage.put(key, value),
136
+ removeItem: async (key) => {
137
+ await durableObjectStorage.delete(key);
138
+ }
139
+ };
140
+ }
141
+ function createDurableObjectTypedStorage(durableObjectStorage, keyPrefix) {
142
+ return createTypedStorage({
143
+ storageAdapter: new StorageAdapter({
144
+ methods: createDurableObjectStorageMethods(durableObjectStorage),
145
+ keyPrefix
146
+ })
147
+ });
148
+ }
149
+ // src/storage_adapter/specific/memory/memory_storage.ts
150
+ function createMemoryStorageMethods_string(memoryStorageMap = new Map) {
151
+ return {
152
+ type: "string" /* string */,
153
+ getItem: async (key) => memoryStorageMap.get(key) ?? null,
154
+ setItem: async (key, value) => {
155
+ memoryStorageMap.set(key, value);
156
+ },
157
+ removeItem: async (key) => {
158
+ memoryStorageMap.delete(key);
159
+ }
160
+ };
161
+ }
162
+ function createTypedMemoryStorage_string(memoryStorageMap = new Map, keyPrefix) {
163
+ return createTypedStorage({
164
+ storageAdapter: new StorageAdapter({
165
+ methods: createMemoryStorageMethods_string(memoryStorageMap),
166
+ keyPrefix
167
+ })
168
+ });
169
+ }
170
+ function createMemoryStorageMethods_json(memoryStorageMap = new Map) {
171
+ return {
172
+ type: "json" /* json */,
173
+ getItem: async (key) => memoryStorageMap.get(key),
174
+ setItem: async (key, value) => {
175
+ memoryStorageMap.set(key, value);
176
+ },
177
+ removeItem: async (key) => {
178
+ memoryStorageMap.delete(key);
179
+ }
180
+ };
181
+ }
182
+ function createTypedMemoryStorage_json(memoryStorageMap = new Map, keyPrefix) {
183
+ return createTypedStorage({
184
+ storageAdapter: new StorageAdapter({
185
+ methods: createMemoryStorageMethods_json(memoryStorageMap),
186
+ keyPrefix
187
+ })
188
+ });
189
+ }
190
+ export {
191
+ createWebSessionStorageMethods,
192
+ createWebLocalStorageMethods,
193
+ createTypedWebSessionStorage,
194
+ createTypedWebLocalStorage,
195
+ createTypedStorage,
196
+ createTypedMemoryStorage_string,
197
+ createTypedMemoryStorage_json,
198
+ createMemoryStorageMethods_string,
199
+ createMemoryStorageMethods_json,
200
+ createDurableObjectTypedStorage,
201
+ createDurableObjectStorageMethods,
202
+ StorageAdapter,
203
+ EStorageAdapterType
204
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nice-code/util",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {