@form-engine-ts/storage-localstorage 8.0.0 → 8.0.1

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
@@ -123,6 +123,30 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage, optio
123
123
  if (storage.getItem(key) !== null) throw new Error(`A submission with ID "${submission.id}" already exists.`);
124
124
  storage.setItem(key, JSON.stringify(submission));
125
125
  },
126
+ async saveSubmissionWithinLimit(submission, maxResponses, saveOptions = {}) {
127
+ if (!Number.isInteger(maxResponses) || maxResponses < 1)
128
+ throw new RangeError("maxResponses must be a positive integer.");
129
+ const key = submissionKey(submission.id);
130
+ const payloadHash = await (0, import_core.hashFormSubmissionPayload)(submission);
131
+ const existingValue = storage.getItem(key);
132
+ if (existingValue !== null) {
133
+ if (saveOptions.idempotent !== true) throw new Error(`A submission with ID "${submission.id}" already exists.`);
134
+ const existing = parseSubmission(existingValue, key);
135
+ const existingPayloadHash = await (0, import_core.hashFormSubmissionPayload)(existing);
136
+ if (existingPayloadHash === payloadHash)
137
+ return { status: "duplicate", submission: cloneJson(existing), payloadHash };
138
+ return { status: "conflict", submissionId: submission.id, payloadHash, existingPayloadHash };
139
+ }
140
+ const count = prefixedKeys(submissionPrefix).reduce((total, key2) => {
141
+ const value = storage.getItem(key2);
142
+ if (value === null) return total;
143
+ const candidate = parseSubmission(value, key2);
144
+ return total + (candidate.formId === submission.formId && candidate.formVersion === submission.formVersion ? 1 : 0);
145
+ }, 0);
146
+ if (count >= maxResponses) return { status: "limit_reached" };
147
+ storage.setItem(key, JSON.stringify(submission));
148
+ if (saveOptions.idempotent === true) return { status: "created", submission: cloneJson(submission), payloadHash };
149
+ },
126
150
  async listSubmissions(formId, formVersion, options2) {
127
151
  return prefixedKeys(submissionPrefix).map((key) => {
128
152
  const value = storage.getItem(key);
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/index.ts
2
2
  import {
3
3
  assertValidFormSchema,
4
- createFormLifecycleAdapter
4
+ createFormLifecycleAdapter,
5
+ hashFormSubmissionPayload
5
6
  } from "@form-engine-ts/core";
6
7
  function isRecord(value) {
7
8
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -102,6 +103,30 @@ function createLocalStorageAdapter(storagePrefix = "pf_", injectedStorage, optio
102
103
  if (storage.getItem(key) !== null) throw new Error(`A submission with ID "${submission.id}" already exists.`);
103
104
  storage.setItem(key, JSON.stringify(submission));
104
105
  },
106
+ async saveSubmissionWithinLimit(submission, maxResponses, saveOptions = {}) {
107
+ if (!Number.isInteger(maxResponses) || maxResponses < 1)
108
+ throw new RangeError("maxResponses must be a positive integer.");
109
+ const key = submissionKey(submission.id);
110
+ const payloadHash = await hashFormSubmissionPayload(submission);
111
+ const existingValue = storage.getItem(key);
112
+ if (existingValue !== null) {
113
+ if (saveOptions.idempotent !== true) throw new Error(`A submission with ID "${submission.id}" already exists.`);
114
+ const existing = parseSubmission(existingValue, key);
115
+ const existingPayloadHash = await hashFormSubmissionPayload(existing);
116
+ if (existingPayloadHash === payloadHash)
117
+ return { status: "duplicate", submission: cloneJson(existing), payloadHash };
118
+ return { status: "conflict", submissionId: submission.id, payloadHash, existingPayloadHash };
119
+ }
120
+ const count = prefixedKeys(submissionPrefix).reduce((total, key2) => {
121
+ const value = storage.getItem(key2);
122
+ if (value === null) return total;
123
+ const candidate = parseSubmission(value, key2);
124
+ return total + (candidate.formId === submission.formId && candidate.formVersion === submission.formVersion ? 1 : 0);
125
+ }, 0);
126
+ if (count >= maxResponses) return { status: "limit_reached" };
127
+ storage.setItem(key, JSON.stringify(submission));
128
+ if (saveOptions.idempotent === true) return { status: "created", submission: cloneJson(submission), payloadHash };
129
+ },
105
130
  async listSubmissions(formId, formVersion, options2) {
106
131
  return prefixedKeys(submissionPrefix).map((key) => {
107
132
  const value = storage.getItem(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@form-engine-ts/storage-localstorage",
3
- "version": "8.0.0",
3
+ "version": "8.0.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -39,10 +39,10 @@
39
39
  "typescript"
40
40
  ],
41
41
  "dependencies": {
42
- "@form-engine-ts/core": "8.0.0"
42
+ "@form-engine-ts/core": "8.0.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@form-engine-ts/storage": "8.0.0"
45
+ "@form-engine-ts/storage": "8.0.1"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsup src/index.ts --format esm,cjs --dts --clean --external @form-engine-ts/core",