@form-engine-ts/storage-localstorage 7.17.2 → 7.18.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.cjs +33 -8
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +37 -9
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -37,10 +37,10 @@ function parseJson(value, key) {
|
|
|
37
37
|
throw new Error(`Stored JSON at "${key}" is invalid.`, { cause });
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
function parseSchema(value, key) {
|
|
40
|
+
function parseSchema(value, key, validation = {}) {
|
|
41
41
|
const parsed = parseJson(value, key);
|
|
42
42
|
try {
|
|
43
|
-
(0, import_core.assertValidFormSchema)(parsed);
|
|
43
|
+
(0, import_core.assertValidFormSchema)(parsed, validation);
|
|
44
44
|
} catch (cause) {
|
|
45
45
|
throw new Error(`Stored schema at "${key}" is invalid.`, { cause });
|
|
46
46
|
}
|
|
@@ -56,7 +56,8 @@ function parseSubmission(value, key) {
|
|
|
56
56
|
function encoded(value) {
|
|
57
57
|
return encodeURIComponent(value);
|
|
58
58
|
}
|
|
59
|
-
function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
59
|
+
function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage, options = {}) {
|
|
60
|
+
const schemaValidation = options.schemaValidation ?? options.validation;
|
|
60
61
|
const storage = injectedStorage ?? (typeof globalThis.localStorage === "undefined" ? void 0 : globalThis.localStorage);
|
|
61
62
|
if (storage === void 0) {
|
|
62
63
|
throw new Error("LocalStorage is unavailable. Pass a StorageLike implementation when running outside a browser.");
|
|
@@ -73,21 +74,45 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
|
73
74
|
}
|
|
74
75
|
return keys;
|
|
75
76
|
};
|
|
77
|
+
const backend = {
|
|
78
|
+
resources: ["schema", "submission"],
|
|
79
|
+
async list(formId) {
|
|
80
|
+
const result = [];
|
|
81
|
+
for (const kind of ["schema", "submission"]) {
|
|
82
|
+
for (const key of prefixedKeys(kind === "schema" ? schemaPrefix : submissionPrefix)) {
|
|
83
|
+
const raw = storage.getItem(key);
|
|
84
|
+
if (raw === null) continue;
|
|
85
|
+
const value = kind === "schema" ? parseSchema(raw, key, schemaValidation) : parseSubmission(raw, key);
|
|
86
|
+
if (("formId" in value ? value.formId : value.id) === formId) result.push({ kind, id: key, value });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
},
|
|
91
|
+
async remove(resource) {
|
|
92
|
+
const raw = storage.getItem(resource.id);
|
|
93
|
+
if (raw === null) return 0;
|
|
94
|
+
if (JSON.stringify(parseJson(raw, resource.id)) !== JSON.stringify(resource.value))
|
|
95
|
+
throw new Error("Deletion revision conflict.");
|
|
96
|
+
storage.removeItem(resource.id);
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
76
100
|
return {
|
|
101
|
+
...(0, import_core.createFormLifecycleAdapter)(backend, options.lifecycle),
|
|
77
102
|
async saveSchema(schema) {
|
|
78
|
-
(0, import_core.assertValidFormSchema)(schema);
|
|
103
|
+
(0, import_core.assertValidFormSchema)(schema, schemaValidation);
|
|
79
104
|
storage.setItem(schemaKey(schema.id, schema.version), JSON.stringify(schema));
|
|
80
105
|
},
|
|
81
106
|
async getSchema(formId, formVersion) {
|
|
82
107
|
const key = schemaKey(formId, formVersion);
|
|
83
108
|
const value = storage.getItem(key);
|
|
84
|
-
return value === null ? null : cloneJson(parseSchema(value, key));
|
|
109
|
+
return value === null ? null : cloneJson(parseSchema(value, key, schemaValidation));
|
|
85
110
|
},
|
|
86
111
|
async listSchemas() {
|
|
87
112
|
return prefixedKeys(schemaPrefix).map((key) => {
|
|
88
113
|
const value = storage.getItem(key);
|
|
89
114
|
if (value === null) throw new Error(`Stored schema at "${key}" disappeared during reading.`);
|
|
90
|
-
return parseSchema(value, key);
|
|
115
|
+
return parseSchema(value, key, schemaValidation);
|
|
91
116
|
}).sort((left, right) => left.id.localeCompare(right.id) || left.version - right.version).map(cloneJson);
|
|
92
117
|
},
|
|
93
118
|
async deleteSchema(formId, formVersion) {
|
|
@@ -98,13 +123,13 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
|
98
123
|
if (storage.getItem(key) !== null) throw new Error(`A submission with ID "${submission.id}" already exists.`);
|
|
99
124
|
storage.setItem(key, JSON.stringify(submission));
|
|
100
125
|
},
|
|
101
|
-
async listSubmissions(formId, formVersion,
|
|
126
|
+
async listSubmissions(formId, formVersion, options2) {
|
|
102
127
|
return prefixedKeys(submissionPrefix).map((key) => {
|
|
103
128
|
const value = storage.getItem(key);
|
|
104
129
|
if (value === null) throw new Error(`Stored submission at "${key}" disappeared during reading.`);
|
|
105
130
|
return parseSubmission(value, key);
|
|
106
131
|
}).filter(
|
|
107
|
-
(submission) => submission.formId === formId && (formVersion === void 0 || submission.formVersion === formVersion) && (
|
|
132
|
+
(submission) => submission.formId === formId && (formVersion === void 0 || submission.formVersion === formVersion) && (options2?.since === void 0 || submission.submittedAt >= options2.since) && (options2?.until === void 0 || submission.submittedAt <= options2.until)
|
|
108
133
|
).sort((left, right) => left.submittedAt.localeCompare(right.submittedAt) || left.id.localeCompare(right.id)).map(cloneJson);
|
|
109
134
|
},
|
|
110
135
|
async deleteSubmission(submissionId) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormStorageAdapter } from '@form-engine-ts/core';
|
|
1
|
+
import { ValidateFormSchemaOptions, FormLifecycleOptions, FormStorageAdapter } from '@form-engine-ts/core';
|
|
2
2
|
|
|
3
3
|
interface StorageLike {
|
|
4
4
|
readonly length: number;
|
|
@@ -7,6 +7,11 @@ interface StorageLike {
|
|
|
7
7
|
removeItem(key: string): void;
|
|
8
8
|
key(index: number): string | null;
|
|
9
9
|
}
|
|
10
|
-
declare function createLocalStorageAdapter(storagePrefix?: string, injectedStorage?: StorageLike
|
|
10
|
+
declare function createLocalStorageAdapter(storagePrefix?: string, injectedStorage?: StorageLike, options?: {
|
|
11
|
+
/** @deprecated Use schemaValidation. */
|
|
12
|
+
readonly validation?: ValidateFormSchemaOptions;
|
|
13
|
+
readonly schemaValidation?: ValidateFormSchemaOptions;
|
|
14
|
+
readonly lifecycle?: FormLifecycleOptions;
|
|
15
|
+
}): FormStorageAdapter;
|
|
11
16
|
|
|
12
17
|
export { type StorageLike, createLocalStorageAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormStorageAdapter } from '@form-engine-ts/core';
|
|
1
|
+
import { ValidateFormSchemaOptions, FormLifecycleOptions, FormStorageAdapter } from '@form-engine-ts/core';
|
|
2
2
|
|
|
3
3
|
interface StorageLike {
|
|
4
4
|
readonly length: number;
|
|
@@ -7,6 +7,11 @@ interface StorageLike {
|
|
|
7
7
|
removeItem(key: string): void;
|
|
8
8
|
key(index: number): string | null;
|
|
9
9
|
}
|
|
10
|
-
declare function createLocalStorageAdapter(storagePrefix?: string, injectedStorage?: StorageLike
|
|
10
|
+
declare function createLocalStorageAdapter(storagePrefix?: string, injectedStorage?: StorageLike, options?: {
|
|
11
|
+
/** @deprecated Use schemaValidation. */
|
|
12
|
+
readonly validation?: ValidateFormSchemaOptions;
|
|
13
|
+
readonly schemaValidation?: ValidateFormSchemaOptions;
|
|
14
|
+
readonly lifecycle?: FormLifecycleOptions;
|
|
15
|
+
}): FormStorageAdapter;
|
|
11
16
|
|
|
12
17
|
export { type StorageLike, createLocalStorageAdapter };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
assertValidFormSchema,
|
|
4
|
+
createFormLifecycleAdapter
|
|
5
|
+
} from "@form-engine-ts/core";
|
|
3
6
|
function isRecord(value) {
|
|
4
7
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
8
|
}
|
|
@@ -13,10 +16,10 @@ function parseJson(value, key) {
|
|
|
13
16
|
throw new Error(`Stored JSON at "${key}" is invalid.`, { cause });
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
|
-
function parseSchema(value, key) {
|
|
19
|
+
function parseSchema(value, key, validation = {}) {
|
|
17
20
|
const parsed = parseJson(value, key);
|
|
18
21
|
try {
|
|
19
|
-
assertValidFormSchema(parsed);
|
|
22
|
+
assertValidFormSchema(parsed, validation);
|
|
20
23
|
} catch (cause) {
|
|
21
24
|
throw new Error(`Stored schema at "${key}" is invalid.`, { cause });
|
|
22
25
|
}
|
|
@@ -32,7 +35,8 @@ function parseSubmission(value, key) {
|
|
|
32
35
|
function encoded(value) {
|
|
33
36
|
return encodeURIComponent(value);
|
|
34
37
|
}
|
|
35
|
-
function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
38
|
+
function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage, options = {}) {
|
|
39
|
+
const schemaValidation = options.schemaValidation ?? options.validation;
|
|
36
40
|
const storage = injectedStorage ?? (typeof globalThis.localStorage === "undefined" ? void 0 : globalThis.localStorage);
|
|
37
41
|
if (storage === void 0) {
|
|
38
42
|
throw new Error("LocalStorage is unavailable. Pass a StorageLike implementation when running outside a browser.");
|
|
@@ -49,21 +53,45 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
|
49
53
|
}
|
|
50
54
|
return keys;
|
|
51
55
|
};
|
|
56
|
+
const backend = {
|
|
57
|
+
resources: ["schema", "submission"],
|
|
58
|
+
async list(formId) {
|
|
59
|
+
const result = [];
|
|
60
|
+
for (const kind of ["schema", "submission"]) {
|
|
61
|
+
for (const key of prefixedKeys(kind === "schema" ? schemaPrefix : submissionPrefix)) {
|
|
62
|
+
const raw = storage.getItem(key);
|
|
63
|
+
if (raw === null) continue;
|
|
64
|
+
const value = kind === "schema" ? parseSchema(raw, key, schemaValidation) : parseSubmission(raw, key);
|
|
65
|
+
if (("formId" in value ? value.formId : value.id) === formId) result.push({ kind, id: key, value });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
},
|
|
70
|
+
async remove(resource) {
|
|
71
|
+
const raw = storage.getItem(resource.id);
|
|
72
|
+
if (raw === null) return 0;
|
|
73
|
+
if (JSON.stringify(parseJson(raw, resource.id)) !== JSON.stringify(resource.value))
|
|
74
|
+
throw new Error("Deletion revision conflict.");
|
|
75
|
+
storage.removeItem(resource.id);
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
52
79
|
return {
|
|
80
|
+
...createFormLifecycleAdapter(backend, options.lifecycle),
|
|
53
81
|
async saveSchema(schema) {
|
|
54
|
-
assertValidFormSchema(schema);
|
|
82
|
+
assertValidFormSchema(schema, schemaValidation);
|
|
55
83
|
storage.setItem(schemaKey(schema.id, schema.version), JSON.stringify(schema));
|
|
56
84
|
},
|
|
57
85
|
async getSchema(formId, formVersion) {
|
|
58
86
|
const key = schemaKey(formId, formVersion);
|
|
59
87
|
const value = storage.getItem(key);
|
|
60
|
-
return value === null ? null : cloneJson(parseSchema(value, key));
|
|
88
|
+
return value === null ? null : cloneJson(parseSchema(value, key, schemaValidation));
|
|
61
89
|
},
|
|
62
90
|
async listSchemas() {
|
|
63
91
|
return prefixedKeys(schemaPrefix).map((key) => {
|
|
64
92
|
const value = storage.getItem(key);
|
|
65
93
|
if (value === null) throw new Error(`Stored schema at "${key}" disappeared during reading.`);
|
|
66
|
-
return parseSchema(value, key);
|
|
94
|
+
return parseSchema(value, key, schemaValidation);
|
|
67
95
|
}).sort((left, right) => left.id.localeCompare(right.id) || left.version - right.version).map(cloneJson);
|
|
68
96
|
},
|
|
69
97
|
async deleteSchema(formId, formVersion) {
|
|
@@ -74,13 +102,13 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage) {
|
|
|
74
102
|
if (storage.getItem(key) !== null) throw new Error(`A submission with ID "${submission.id}" already exists.`);
|
|
75
103
|
storage.setItem(key, JSON.stringify(submission));
|
|
76
104
|
},
|
|
77
|
-
async listSubmissions(formId, formVersion,
|
|
105
|
+
async listSubmissions(formId, formVersion, options2) {
|
|
78
106
|
return prefixedKeys(submissionPrefix).map((key) => {
|
|
79
107
|
const value = storage.getItem(key);
|
|
80
108
|
if (value === null) throw new Error(`Stored submission at "${key}" disappeared during reading.`);
|
|
81
109
|
return parseSubmission(value, key);
|
|
82
110
|
}).filter(
|
|
83
|
-
(submission) => submission.formId === formId && (formVersion === void 0 || submission.formVersion === formVersion) && (
|
|
111
|
+
(submission) => submission.formId === formId && (formVersion === void 0 || submission.formVersion === formVersion) && (options2?.since === void 0 || submission.submittedAt >= options2.since) && (options2?.until === void 0 || submission.submittedAt <= options2.until)
|
|
84
112
|
).sort((left, right) => left.submittedAt.localeCompare(right.submittedAt) || left.id.localeCompare(right.id)).map(cloneJson);
|
|
85
113
|
},
|
|
86
114
|
async deleteSubmission(submissionId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@form-engine-ts/storage-localstorage",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.18.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -39,7 +39,10 @@
|
|
|
39
39
|
"typescript"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@form-engine-ts/core": "7.
|
|
42
|
+
"@form-engine-ts/core": "7.18.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@form-engine-ts/storage": "7.18.0"
|
|
43
46
|
},
|
|
44
47
|
"scripts": {
|
|
45
48
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean --external @form-engine-ts/core",
|