@form-engine-ts/storage-localstorage 7.17.3 → 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 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, options) {
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) && (options?.since === void 0 || submission.submittedAt >= options.since) && (options?.until === void 0 || submission.submittedAt <= options.until)
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): FormStorageAdapter;
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): FormStorageAdapter;
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 { assertValidFormSchema } from "@form-engine-ts/core";
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, options) {
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) && (options?.since === void 0 || submission.submittedAt >= options.since) && (options?.until === void 0 || submission.submittedAt <= options.until)
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.17.3",
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.17.3"
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",