@vielzeug/postmaster 26.10.15 → 26.10.17

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Helmuth Saatkamp
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1 +1 @@
1
- {"version":3,"file":"_json.cjs","names":[],"sources":["../src/_json.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n"],"mappings":"gCAGA,SAAgB,YAAe,EAAmC,EAAmB,CAGnF,OAFK,EACD,OAAO,GAAa,WAAmB,EAAS,CAAK,EAClD,EAAS,MAAM,CAAK,EAFL,CAGxB,CAEA,SAAgB,YAAY,EAA2B,CACrD,IAAI,EAEJ,GAAI,CACF,EAAa,KAAK,UAAU,CAAK,CACnC,OAAS,EAAO,CACd,MAAM,IAAI,EAAA,gBAAgB,wCAAyC,CAAE,MAAO,CAAM,CAAC,CACrF,CAEA,GAAI,IAAe,IAAA,GACjB,MAAM,IAAI,EAAA,gBAAgB,uCAAuC,EAGnE,OAAO,KAAK,MAAM,CAAU,CAC9B,CAEA,SAAgB,YAAY,EAAgB,EAA4B,CAKtE,OAJI,aAAiB,MACZ,CAAE,QAAS,EAAM,QAAS,KAAM,EAAM,KAAM,WAAY,CAAI,EAG9D,CAAE,QAAS,OAAO,CAAK,EAAG,KAAM,QAAS,WAAY,CAAI,CAClE,CAEA,SAAgB,aAAa,EAAyB,CACpD,OAAO,aAAiB,cAAgB,EAAM,OAAS,YACzD"}
1
+ {"version":3,"file":"_json.cjs","names":["PostmasterError","require_errors","validate","value","serialized","error","now"],"sources":["../src/_json.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n"],"mappings":"A,gCAGA,SAAgB,YAAe,EAAmC,EAAmB,CAGnF,OAFKE,EACD,OAAOA,GAAa,WAAmBA,EAASC,CAAK,EAClDD,EAAS,MAAMC,CAAK,EAFLA,CAGxB,CAEA,SAAgB,YAAY,EAA2B,CACrD,IAAIC,EAEJ,GAAI,CACF,EAAa,KAAK,UAAUD,CAAK,CACnC,OAASE,EAAO,CACd,MAAM,IAAIL,EAAAA,gBAAgB,wCAAyC,CAAE,MAAOK,CAAM,CAAC,CACrF,CAEA,GAAID,IAAe,IAAA,GACjB,MAAM,IAAIJ,EAAAA,gBAAgB,uCAAuC,EAGnE,OAAO,KAAK,MAAMI,CAAU,CAC9B,CAEA,SAAgB,YAAY,EAAgB,EAA4B,CAKtE,OAJIC,aAAiB,MACZ,CAAE,QAASA,EAAM,QAAS,KAAMA,EAAM,KAAM,WAAYC,CAAI,EAG9D,CAAE,QAAS,OAAOD,CAAK,EAAG,KAAM,QAAS,WAAYC,CAAI,CAClE,CAEA,SAAgB,aAAa,EAAyB,CACpD,OAAOD,aAAiB,cAAgBA,EAAM,OAAS,YACzD,C"}
package/dist/_json.js CHANGED
@@ -1,2 +1,33 @@
1
- import{PostmasterError as e}from"./errors.js";function runValidate(e,t){return e?typeof e==`function`?e(t):e.parse(t):t}function asJsonValue(t){let n;try{n=JSON.stringify(t)}catch(t){throw new e(`job payload must be JSON-serializable`,{cause:t})}if(n===void 0)throw new e(`job payload must be JSON-serializable`);return JSON.parse(n)}function failureFrom(e,t){return e instanceof Error?{message:e.message,name:e.name,occurredAt:t}:{message:String(e),name:`Error`,occurredAt:t}}function isAbortError(e){return e instanceof DOMException&&e.name===`AbortError`}export{asJsonValue,failureFrom,isAbortError,runValidate};
1
+ import { PostmasterError as e } from "./errors.js";
2
+ //#region src/_json.ts
3
+ function runValidate(e, t) {
4
+ return e ? typeof e == "function" ? e(t) : e.parse(t) : t;
5
+ }
6
+ function asJsonValue(t) {
7
+ let n;
8
+ try {
9
+ n = JSON.stringify(t);
10
+ } catch (t) {
11
+ throw new e("job payload must be JSON-serializable", { cause: t });
12
+ }
13
+ if (n === void 0) throw new e("job payload must be JSON-serializable");
14
+ return JSON.parse(n);
15
+ }
16
+ function failureFrom(e, t) {
17
+ return e instanceof Error ? {
18
+ message: e.message,
19
+ name: e.name,
20
+ occurredAt: t
21
+ } : {
22
+ message: String(e),
23
+ name: "Error",
24
+ occurredAt: t
25
+ };
26
+ }
27
+ function isAbortError(e) {
28
+ return e instanceof DOMException && e.name === "AbortError";
29
+ }
30
+ //#endregion
31
+ export { asJsonValue, failureFrom, isAbortError, runValidate };
32
+
2
33
  //# sourceMappingURL=_json.js.map
package/dist/_json.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"_json.js","names":[],"sources":["../src/_json.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n"],"mappings":"8CAGA,SAAgB,YAAe,EAAmC,EAAmB,CAGnF,OAFK,EACD,OAAO,GAAa,WAAmB,EAAS,CAAK,EAClD,EAAS,MAAM,CAAK,EAFL,CAGxB,CAEA,SAAgB,YAAY,EAA2B,CACrD,IAAI,EAEJ,GAAI,CACF,EAAa,KAAK,UAAU,CAAK,CACnC,OAAS,EAAO,CACd,MAAM,IAAI,EAAgB,wCAAyC,CAAE,MAAO,CAAM,CAAC,CACrF,CAEA,GAAI,IAAe,IAAA,GACjB,MAAM,IAAI,EAAgB,uCAAuC,EAGnE,OAAO,KAAK,MAAM,CAAU,CAC9B,CAEA,SAAgB,YAAY,EAAgB,EAA4B,CAKtE,OAJI,aAAiB,MACZ,CAAE,QAAS,EAAM,QAAS,KAAM,EAAM,KAAM,WAAY,CAAI,EAG9D,CAAE,QAAS,OAAO,CAAK,EAAG,KAAM,QAAS,WAAY,CAAI,CAClE,CAEA,SAAgB,aAAa,EAAyB,CACpD,OAAO,aAAiB,cAAgB,EAAM,OAAS,YACzD"}
1
+ {"version":3,"file":"_json.js","names":["validate","value","serialized","error","PostmasterError","now"],"sources":["../src/_json.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JsonValue, StoredFailure, Validate } from './types.ts';\n\nexport function runValidate<T>(validate: Validate<T> | undefined, value: unknown): T {\n if (!validate) return value as T;\n if (typeof validate === 'function') return validate(value);\n return validate.parse(value);\n}\n\nexport function asJsonValue(value: unknown): JsonValue {\n let serialized: string | undefined;\n\n try {\n serialized = JSON.stringify(value);\n } catch (error) {\n throw new PostmasterError('job payload must be JSON-serializable', { cause: error });\n }\n\n if (serialized === undefined) {\n throw new PostmasterError('job payload must be JSON-serializable');\n }\n\n return JSON.parse(serialized) as JsonValue;\n}\n\nexport function failureFrom(error: unknown, now: number): StoredFailure {\n if (error instanceof Error) {\n return { message: error.message, name: error.name, occurredAt: now };\n }\n\n return { message: String(error), name: 'Error', occurredAt: now };\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === 'AbortError';\n}\n"],"mappings":";;AAGA,SAAgB,YAAe,GAAmC,GAAmB;CAGnF,OAFKA,IACD,OAAOA,KAAa,aAAmBA,EAASC,CAAK,IAClDD,EAAS,MAAMC,CAAK,IAFLA;AAGxB;AAEA,SAAgB,YAAY,GAA2B;CACrD,IAAIC;CAEJ,IAAI;EACF,IAAa,KAAK,UAAUD,CAAK;CACnC,SAASE,GAAO;EACd,MAAM,IAAIC,EAAgB,yCAAyC,EAAE,OAAOD,EAAM,CAAC;CACrF;CAEA,IAAID,MAAe,KAAA,GACjB,MAAM,IAAIE,EAAgB,uCAAuC;CAGnE,OAAO,KAAK,MAAMF,CAAU;AAC9B;AAEA,SAAgB,YAAY,GAAgB,GAA4B;CAKtE,OAJIC,aAAiB,QACZ;EAAE,SAASA,EAAM;EAAS,MAAMA,EAAM;EAAM,YAAYE;CAAI,IAG9D;EAAE,SAAS,OAAOF,CAAK;EAAG,MAAM;EAAS,YAAYE;CAAI;AAClE;AAEA,SAAgB,aAAa,GAAyB;CACpD,OAAOF,aAAiB,gBAAgBA,EAAM,SAAS;AACzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"_store-utils.cjs","names":[],"sources":["../src/_store-utils.ts"],"sourcesContent":["import type { StoredJob } from './types.ts';\n\n/**\n * Strips `undefined` optional keys so persisted records only carry defined fields.\n * Shared by the IndexedDB store and the in-memory test store.\n */\nexport function normalize(entry: StoredJob): StoredJob {\n const { failure, leaseExpiresAt, ownerId, ...rest } = entry;\n return {\n ...rest,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n"],"mappings":"AAMA,SAAgB,UAAU,EAA6B,CACrD,GAAM,CAAE,UAAS,iBAAgB,UAAS,GAAG,GAAS,EACtD,MAAO,CACL,GAAG,EACH,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAI,IAAmB,IAAA,GAAiC,CAAC,EAAtB,CAAE,gBAAe,EACpD,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,CACxC,CACF"}
1
+ {"version":3,"file":"_store-utils.cjs","names":["rest","entry","failure","leaseExpiresAt","ownerId"],"sources":["../src/_store-utils.ts"],"sourcesContent":["import type { StoredJob } from './types.ts';\n\n/**\n * Strips `undefined` optional keys so persisted records only carry defined fields.\n * Shared by the IndexedDB store and the in-memory test store.\n */\nexport function normalize(entry: StoredJob): StoredJob {\n const { failure, leaseExpiresAt, ownerId, ...rest } = entry;\n return {\n ...rest,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n"],"mappings":"AAMA,SAAgB,UAAU,EAA6B,CACrD,GAAM,CAAE,UAAS,iBAAgB,UAAS,GAAGA,GAASC,EACtD,MAAO,CACL,GAAGD,EACH,GAAIE,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAIC,IAAmB,IAAA,GAAiC,CAAC,EAAtB,CAAE,gBAAe,EACpD,GAAIC,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,CACxC,CACF,C"}
@@ -1,2 +1,14 @@
1
- function normalize(e){let{failure:t,leaseExpiresAt:n,ownerId:r,...i}=e;return{...i,...t===void 0?{}:{failure:t},...n===void 0?{}:{leaseExpiresAt:n},...r===void 0?{}:{ownerId:r}}}export{normalize};
1
+ //#region src/_store-utils.ts
2
+ function normalize(e) {
3
+ let { failure: t, leaseExpiresAt: n, ownerId: r, ...i } = e;
4
+ return {
5
+ ...i,
6
+ ...t === void 0 ? {} : { failure: t },
7
+ ...n === void 0 ? {} : { leaseExpiresAt: n },
8
+ ...r === void 0 ? {} : { ownerId: r }
9
+ };
10
+ }
11
+ //#endregion
12
+ export { normalize };
13
+
2
14
  //# sourceMappingURL=_store-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_store-utils.js","names":[],"sources":["../src/_store-utils.ts"],"sourcesContent":["import type { StoredJob } from './types.ts';\n\n/**\n * Strips `undefined` optional keys so persisted records only carry defined fields.\n * Shared by the IndexedDB store and the in-memory test store.\n */\nexport function normalize(entry: StoredJob): StoredJob {\n const { failure, leaseExpiresAt, ownerId, ...rest } = entry;\n return {\n ...rest,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n"],"mappings":"AAMA,SAAgB,UAAU,EAA6B,CACrD,GAAM,CAAE,UAAS,iBAAgB,UAAS,GAAG,GAAS,EACtD,MAAO,CACL,GAAG,EACH,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAI,IAAmB,IAAA,GAAiC,CAAC,EAAtB,CAAE,gBAAe,EACpD,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,CACxC,CACF"}
1
+ {"version":3,"file":"_store-utils.js","names":["rest","entry","failure","leaseExpiresAt","ownerId"],"sources":["../src/_store-utils.ts"],"sourcesContent":["import type { StoredJob } from './types.ts';\n\n/**\n * Strips `undefined` optional keys so persisted records only carry defined fields.\n * Shared by the IndexedDB store and the in-memory test store.\n */\nexport function normalize(entry: StoredJob): StoredJob {\n const { failure, leaseExpiresAt, ownerId, ...rest } = entry;\n return {\n ...rest,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n"],"mappings":";AAMA,SAAgB,UAAU,GAA6B;CACrD,IAAM,EAAE,YAAS,mBAAgB,YAAS,GAAGA,MAASC;CACtD,OAAO;EACL,GAAGD;EACH,GAAIE,MAAY,KAAA,IAA0B,CAAC,IAAf,EAAE,WAAQ;EACtC,GAAIC,MAAmB,KAAA,IAAiC,CAAC,IAAtB,EAAE,kBAAe;EACpD,GAAIC,MAAY,KAAA,IAA0B,CAAC,IAAf,EAAE,WAAQ;CACxC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.cjs","names":[],"sources":["../src/definitions.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n"],"mappings":"gCAGA,SAAS,cAAc,EAAgC,EAAoB,CACpE,OAED,CAAC,OAAO,UAAU,EAAM,WAAW,GAAK,EAAM,YAAc,GAC9D,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,+CAA+C,CAE1F,CAEA,SAAS,mBAAmB,EAAc,EAAmC,CAC3E,IAAM,EAAa,EAAI,QACvB,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAO,OAAO,KAAK,CAAU,EACnC,GAAI,EAAK,SAAW,EAAG,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,+BAA+B,EAE7F,IAAM,EAAW,EACd,IAAK,GAAQ,CACZ,IAAM,EAAU,OAAO,CAAG,EAC1B,GAAI,CAAC,OAAO,UAAU,CAAO,GAAK,OAAO,CAAO,IAAM,EACpD,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,+BAA+B,EAAI,EAAE,EAE9E,GAAI,EAAU,GAAK,GAAW,EAAI,QAChC,MAAM,IAAI,EAAA,gBACR,QAAQ,EAAK,+BAA+B,EAAQ,qBAAqB,EAAI,QAAU,EAAE,EAC3F,EAEF,GAAI,OAAO,EAAW,IAAa,WACjC,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,2BAA2B,EAAQ,oBAAoB,EAEhG,OAAO,CACT,CAAC,CAAC,CACD,MAAM,EAAG,IAAM,EAAI,CAAC,EAEvB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAS,OAAQ,IAC3C,GAAI,EAAS,KAAW,EAAS,EAAQ,GAAK,EAC5C,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,mCAAmC,EAAS,EAAQ,GAAK,GAAG,EAIvG,GAAI,EAAS,GAAG,EAAE,IAAM,EAAI,QAAU,EACpC,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,sCAAsC,EAAI,SAAS,CAE9F,CAEA,SAAS,YAAY,EAAc,EAAmC,CACpE,GAAI,CAAC,OAAO,UAAU,EAAI,OAAO,GAAK,EAAI,QAAU,EAClD,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,qCAAqC,EAG9E,GAAI,OAAO,EAAI,SAAY,YAAc,OAAO,EAAI,KAAQ,WAC1D,MAAM,IAAI,EAAA,gBAAgB,QAAQ,EAAK,8BAA8B,EAGvE,cAAc,EAAI,MAAO,CAAI,EAC7B,mBAAmB,EAAM,CAAG,CAC9B,CAEA,SAAgB,WAA2C,EAAY,CACrE,IAAK,GAAM,CAAC,EAAM,KAAQ,OAAO,QAAQ,CAAI,EAAG,YAAY,EAAM,CAAG,EAErE,OAAO,CACT"}
1
+ {"version":3,"file":"definitions.cjs","names":["PostmasterError","require_errors","retry","name","migrations","job","keys","versions","version","key","a","b","index","jobs"],"sources":["../src/definitions.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n"],"mappings":"A,gCAGA,SAAS,cAAc,EAAgC,EAAoB,CACzE,GAAKE,IAED,CAAC,OAAO,UAAUA,EAAM,WAAW,GAAKA,EAAM,YAAc,GAC9D,MAAM,IAAIF,EAAAA,gBAAgB,QAAQG,EAAK,+CAA+C,CAE1F,CAEA,SAAS,mBAAmB,EAAc,EAAmC,CAC3E,IAAMC,EAAaC,EAAI,QACvB,GAAI,CAACD,EAAY,OAEjB,IAAME,EAAO,OAAO,KAAKF,CAAU,EACnC,GAAIE,EAAK,SAAW,EAAG,MAAM,IAAIN,EAAAA,gBAAgB,QAAQG,EAAK,+BAA+B,EAE7F,IAAMI,EAAWD,EACd,IAAK,GAAQ,CACZ,IAAME,EAAU,OAAOC,CAAG,EAC1B,GAAI,CAAC,OAAO,UAAUD,CAAO,GAAK,OAAOA,CAAO,IAAMC,EACpD,MAAM,IAAIT,EAAAA,gBAAgB,QAAQG,EAAK,+BAA+BM,EAAI,EAAE,EAE9E,GAAID,EAAU,GAAKA,GAAWH,EAAI,QAChC,MAAM,IAAIL,EAAAA,gBACR,QAAQG,EAAK,+BAA+BK,EAAQ,qBAAqBH,EAAI,QAAU,EAAE,EAC3F,EAEF,GAAI,OAAOD,EAAWI,IAAa,WACjC,MAAM,IAAIR,EAAAA,gBAAgB,QAAQG,EAAK,2BAA2BK,EAAQ,oBAAoB,EAEhG,OAAOA,CACT,CAAC,CAAC,CACD,MAAM,EAAG,IAAME,EAAIC,CAAC,EAEvB,IAAK,IAAIC,EAAQ,EAAGA,EAAQL,EAAS,OAAQ,IAC3C,GAAIA,EAASK,KAAWL,EAASK,EAAQ,GAAK,EAC5C,MAAM,IAAIZ,EAAAA,gBAAgB,QAAQG,EAAK,mCAAmCI,EAASK,EAAQ,GAAK,GAAG,EAIvG,GAAIL,EAAS,GAAG,EAAE,IAAMF,EAAI,QAAU,EACpC,MAAM,IAAIL,EAAAA,gBAAgB,QAAQG,EAAK,sCAAsCE,EAAI,SAAS,CAE9F,CAEA,SAAS,YAAY,EAAc,EAAmC,CACpE,GAAI,CAAC,OAAO,UAAUA,EAAI,OAAO,GAAKA,EAAI,QAAU,EAClD,MAAM,IAAIL,EAAAA,gBAAgB,QAAQG,EAAK,qCAAqC,EAG9E,GAAI,OAAOE,EAAI,SAAY,YAAc,OAAOA,EAAI,KAAQ,WAC1D,MAAM,IAAIL,EAAAA,gBAAgB,QAAQG,EAAK,8BAA8B,EAGvE,cAAcE,EAAI,MAAOF,CAAI,EAC7B,mBAAmBA,EAAME,CAAG,CAC9B,CAEA,SAAgB,WAA2C,EAAY,CACrE,IAAK,GAAM,CAACF,EAAME,KAAQ,OAAO,QAAQQ,CAAI,EAAG,YAAYV,EAAME,CAAG,EAErE,OAAOQ,CACT,C"}
@@ -1,2 +1,33 @@
1
- import{PostmasterError as e}from"./errors.js";function validateRetry(t,n){if(t&&(!Number.isInteger(t.maxAttempts)||t.maxAttempts<1))throw new e(`job "${n}" retry.maxAttempts must be a positive integer`)}function validateMigrations(t,n){let r=n.migrate;if(!r)return;let i=Object.keys(r);if(i.length===0)throw new e(`job "${t}" migrations must not be empty`);let a=i.map(i=>{let a=Number(i);if(!Number.isInteger(a)||String(a)!==i)throw new e(`job "${t}" has invalid migration key "${i}"`);if(a<1||a>=n.version)throw new e(`job "${t}" has invalid migration key "${a}" (valid range: 1..${n.version-1})`);if(typeof r[a]!=`function`)throw new e(`job "${t}" migration from version ${a} must be a function`);return a}).sort((e,t)=>e-t);for(let n=1;n<a.length;n++)if(a[n]!==a[n-1]+1)throw new e(`job "${t}" missing migration from version ${a[n-1]+1}`);if(a.at(-1)!==n.version-1)throw new e(`job "${t}" migrations must lead into version ${n.version}`)}function validateJob(t,n){if(!Number.isInteger(n.version)||n.version<1)throw new e(`job "${t}" version must be a positive integer`);if(typeof n.execute!=`function`||typeof n.key!=`function`)throw new e(`job "${t}" must define execute and key`);validateRetry(n.retry,t),validateMigrations(t,n)}function defineJobs(e){for(let[t,n]of Object.entries(e))validateJob(t,n);return e}export{defineJobs};
1
+ import { PostmasterError as e } from "./errors.js";
2
+ //#region src/definitions.ts
3
+ function validateRetry(t, n) {
4
+ if (t && (!Number.isInteger(t.maxAttempts) || t.maxAttempts < 1)) throw new e(`job "${n}" retry.maxAttempts must be a positive integer`);
5
+ }
6
+ function validateMigrations(t, n) {
7
+ let r = n.migrate;
8
+ if (!r) return;
9
+ let i = Object.keys(r);
10
+ if (i.length === 0) throw new e(`job "${t}" migrations must not be empty`);
11
+ let a = i.map((i) => {
12
+ let a = Number(i);
13
+ if (!Number.isInteger(a) || String(a) !== i) throw new e(`job "${t}" has invalid migration key "${i}"`);
14
+ if (a < 1 || a >= n.version) throw new e(`job "${t}" has invalid migration key "${a}" (valid range: 1..${n.version - 1})`);
15
+ if (typeof r[a] != "function") throw new e(`job "${t}" migration from version ${a} must be a function`);
16
+ return a;
17
+ }).sort((e, t) => e - t);
18
+ for (let n = 1; n < a.length; n++) if (a[n] !== a[n - 1] + 1) throw new e(`job "${t}" missing migration from version ${a[n - 1] + 1}`);
19
+ if (a.at(-1) !== n.version - 1) throw new e(`job "${t}" migrations must lead into version ${n.version}`);
20
+ }
21
+ function validateJob(t, n) {
22
+ if (!Number.isInteger(n.version) || n.version < 1) throw new e(`job "${t}" version must be a positive integer`);
23
+ if (typeof n.execute != "function" || typeof n.key != "function") throw new e(`job "${t}" must define execute and key`);
24
+ validateRetry(n.retry, t), validateMigrations(t, n);
25
+ }
26
+ function defineJobs(e) {
27
+ for (let [t, n] of Object.entries(e)) validateJob(t, n);
28
+ return e;
29
+ }
30
+ //#endregion
31
+ export { defineJobs };
32
+
2
33
  //# sourceMappingURL=definitions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","names":[],"sources":["../src/definitions.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n"],"mappings":"8CAGA,SAAS,cAAc,EAAgC,EAAoB,CACpE,OAED,CAAC,OAAO,UAAU,EAAM,WAAW,GAAK,EAAM,YAAc,GAC9D,MAAM,IAAI,EAAgB,QAAQ,EAAK,+CAA+C,CAE1F,CAEA,SAAS,mBAAmB,EAAc,EAAmC,CAC3E,IAAM,EAAa,EAAI,QACvB,GAAI,CAAC,EAAY,OAEjB,IAAM,EAAO,OAAO,KAAK,CAAU,EACnC,GAAI,EAAK,SAAW,EAAG,MAAM,IAAI,EAAgB,QAAQ,EAAK,+BAA+B,EAE7F,IAAM,EAAW,EACd,IAAK,GAAQ,CACZ,IAAM,EAAU,OAAO,CAAG,EAC1B,GAAI,CAAC,OAAO,UAAU,CAAO,GAAK,OAAO,CAAO,IAAM,EACpD,MAAM,IAAI,EAAgB,QAAQ,EAAK,+BAA+B,EAAI,EAAE,EAE9E,GAAI,EAAU,GAAK,GAAW,EAAI,QAChC,MAAM,IAAI,EACR,QAAQ,EAAK,+BAA+B,EAAQ,qBAAqB,EAAI,QAAU,EAAE,EAC3F,EAEF,GAAI,OAAO,EAAW,IAAa,WACjC,MAAM,IAAI,EAAgB,QAAQ,EAAK,2BAA2B,EAAQ,oBAAoB,EAEhG,OAAO,CACT,CAAC,CAAC,CACD,MAAM,EAAG,IAAM,EAAI,CAAC,EAEvB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAS,OAAQ,IAC3C,GAAI,EAAS,KAAW,EAAS,EAAQ,GAAK,EAC5C,MAAM,IAAI,EAAgB,QAAQ,EAAK,mCAAmC,EAAS,EAAQ,GAAK,GAAG,EAIvG,GAAI,EAAS,GAAG,EAAE,IAAM,EAAI,QAAU,EACpC,MAAM,IAAI,EAAgB,QAAQ,EAAK,sCAAsC,EAAI,SAAS,CAE9F,CAEA,SAAS,YAAY,EAAc,EAAmC,CACpE,GAAI,CAAC,OAAO,UAAU,EAAI,OAAO,GAAK,EAAI,QAAU,EAClD,MAAM,IAAI,EAAgB,QAAQ,EAAK,qCAAqC,EAG9E,GAAI,OAAO,EAAI,SAAY,YAAc,OAAO,EAAI,KAAQ,WAC1D,MAAM,IAAI,EAAgB,QAAQ,EAAK,8BAA8B,EAGvE,cAAc,EAAI,MAAO,CAAI,EAC7B,mBAAmB,EAAM,CAAG,CAC9B,CAEA,SAAgB,WAA2C,EAAY,CACrE,IAAK,GAAM,CAAC,EAAM,KAAQ,OAAO,QAAQ,CAAI,EAAG,YAAY,EAAM,CAAG,EAErE,OAAO,CACT"}
1
+ {"version":3,"file":"definitions.js","names":["retry","PostmasterError","name","migrations","job","keys","versions","version","key","a","b","index","jobs"],"sources":["../src/definitions.ts"],"sourcesContent":["import { PostmasterError } from './errors.ts';\nimport type { JobDefinition, JobDefinitions, RetryPolicy } from './types.ts';\n\nfunction validateRetry(retry: RetryPolicy | undefined, name: string): void {\n if (!retry) return;\n\n if (!Number.isInteger(retry.maxAttempts) || retry.maxAttempts < 1) {\n throw new PostmasterError(`job \"${name}\" retry.maxAttempts must be a positive integer`);\n }\n}\n\nfunction validateMigrations(name: string, job: JobDefinition<unknown>): void {\n const migrations = job.migrate;\n if (!migrations) return;\n\n const keys = Object.keys(migrations);\n if (keys.length === 0) throw new PostmasterError(`job \"${name}\" migrations must not be empty`);\n\n const versions = keys\n .map((key) => {\n const version = Number(key);\n if (!Number.isInteger(version) || String(version) !== key) {\n throw new PostmasterError(`job \"${name}\" has invalid migration key \"${key}\"`);\n }\n if (version < 1 || version >= job.version) {\n throw new PostmasterError(\n `job \"${name}\" has invalid migration key \"${version}\" (valid range: 1..${job.version - 1})`,\n );\n }\n if (typeof migrations[version] !== 'function') {\n throw new PostmasterError(`job \"${name}\" migration from version ${version} must be a function`);\n }\n return version;\n })\n .sort((a, b) => a - b);\n\n for (let index = 1; index < versions.length; index++) {\n if (versions[index] !== versions[index - 1] + 1) {\n throw new PostmasterError(`job \"${name}\" missing migration from version ${versions[index - 1] + 1}`);\n }\n }\n\n if (versions.at(-1) !== job.version - 1) {\n throw new PostmasterError(`job \"${name}\" migrations must lead into version ${job.version}`);\n }\n}\n\nfunction validateJob(name: string, job: JobDefinition<unknown>): void {\n if (!Number.isInteger(job.version) || job.version < 1) {\n throw new PostmasterError(`job \"${name}\" version must be a positive integer`);\n }\n\n if (typeof job.execute !== 'function' || typeof job.key !== 'function') {\n throw new PostmasterError(`job \"${name}\" must define execute and key`);\n }\n\n validateRetry(job.retry, name);\n validateMigrations(name, job);\n}\n\nexport function defineJobs<const J extends JobDefinitions>(jobs: J): J {\n for (const [name, job] of Object.entries(jobs)) validateJob(name, job);\n\n return jobs;\n}\n"],"mappings":";;AAGA,SAAS,cAAc,GAAgC,GAAoB;CACzE,IAAKA,MAED,CAAC,OAAO,UAAUA,EAAM,WAAW,KAAKA,EAAM,cAAc,IAC9D,MAAM,IAAIC,EAAgB,QAAQC,EAAK,+CAA+C;AAE1F;AAEA,SAAS,mBAAmB,GAAc,GAAmC;CAC3E,IAAMC,IAAaC,EAAI;CACvB,IAAI,CAACD,GAAY;CAEjB,IAAME,IAAO,OAAO,KAAKF,CAAU;CACnC,IAAIE,EAAK,WAAW,GAAG,MAAM,IAAIJ,EAAgB,QAAQC,EAAK,+BAA+B;CAE7F,IAAMI,IAAWD,EACd,KAAK,MAAQ;EACZ,IAAME,IAAU,OAAOC,CAAG;EAC1B,IAAI,CAAC,OAAO,UAAUD,CAAO,KAAK,OAAOA,CAAO,MAAMC,GACpD,MAAM,IAAIP,EAAgB,QAAQC,EAAK,+BAA+BM,EAAI,EAAE;EAE9E,IAAID,IAAU,KAAKA,KAAWH,EAAI,SAChC,MAAM,IAAIH,EACR,QAAQC,EAAK,+BAA+BK,EAAQ,qBAAqBH,EAAI,UAAU,EAAE,EAC3F;EAEF,IAAI,OAAOD,EAAWI,MAAa,YACjC,MAAM,IAAIN,EAAgB,QAAQC,EAAK,2BAA2BK,EAAQ,oBAAoB;EAEhG,OAAOA;CACT,CAAC,CAAC,CACD,MAAM,GAAG,MAAME,IAAIC,CAAC;CAEvB,KAAK,IAAIC,IAAQ,GAAGA,IAAQL,EAAS,QAAQ,KAC3C,IAAIA,EAASK,OAAWL,EAASK,IAAQ,KAAK,GAC5C,MAAM,IAAIV,EAAgB,QAAQC,EAAK,mCAAmCI,EAASK,IAAQ,KAAK,GAAG;CAIvG,IAAIL,EAAS,GAAG,EAAE,MAAMF,EAAI,UAAU,GACpC,MAAM,IAAIH,EAAgB,QAAQC,EAAK,sCAAsCE,EAAI,SAAS;AAE9F;AAEA,SAAS,YAAY,GAAc,GAAmC;CACpE,IAAI,CAAC,OAAO,UAAUA,EAAI,OAAO,KAAKA,EAAI,UAAU,GAClD,MAAM,IAAIH,EAAgB,QAAQC,EAAK,qCAAqC;CAG9E,IAAI,OAAOE,EAAI,WAAY,cAAc,OAAOA,EAAI,OAAQ,YAC1D,MAAM,IAAIH,EAAgB,QAAQC,EAAK,8BAA8B;CAIvE,AADA,cAAcE,EAAI,OAAOF,CAAI,GAC7B,mBAAmBA,GAAME,CAAG;AAC9B;AAEA,SAAgB,WAA2C,GAAY;CACrE,KAAK,IAAM,CAACF,GAAME,MAAQ,OAAO,QAAQQ,CAAI,GAAG,YAAYV,GAAME,CAAG;CAErE,OAAOQ;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n"],"mappings":"AAAA,IAAa,gBAAb,cAAqC,KAAM,CACzC,YAAY,EAAiB,EAAwB,CACnD,MAAM,EAAS,CAAO,EACtB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,wBAAb,cAA6C,eAAgB,CAAC,EACjD,mBAAb,cAAwC,eAAgB,CAAC"}
1
+ {"version":3,"file":"errors.cjs","names":["message","options"],"sources":["../src/errors.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n"],"mappings":"AAAA,IAAa,gBAAb,cAAqC,KAAM,CACzC,YAAY,EAAiB,EAAwB,CACnD,MAAMA,EAASC,CAAO,EACtB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,wBAAb,cAA6C,eAAgB,CAAC,EACjD,mBAAb,cAAwC,eAAgB,CAAC,E"}
package/dist/errors.js CHANGED
@@ -1,2 +1,10 @@
1
- var PostmasterError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},PostmasterDisposedError=class extends PostmasterError{},PostmasterJobError=class extends PostmasterError{};export{PostmasterDisposedError,PostmasterError,PostmasterJobError};
1
+ //#region src/errors.ts
2
+ var PostmasterError = class extends Error {
3
+ constructor(e, t) {
4
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }, PostmasterDisposedError = class extends PostmasterError {}, PostmasterJobError = class extends PostmasterError {};
7
+ //#endregion
8
+ export { PostmasterDisposedError, PostmasterError, PostmasterJobError };
9
+
2
10
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n"],"mappings":"AAAA,IAAa,gBAAb,cAAqC,KAAM,CACzC,YAAY,EAAiB,EAAwB,CACnD,MAAM,EAAS,CAAO,EACtB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,wBAAb,cAA6C,eAAgB,CAAC,EACjD,mBAAb,cAAwC,eAAgB,CAAC"}
1
+ {"version":3,"file":"errors.js","names":["message","options"],"sources":["../src/errors.ts"],"sourcesContent":["export class PostmasterError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class PostmasterDisposedError extends PostmasterError {}\nexport class PostmasterJobError extends PostmasterError {}\n"],"mappings":";AAAA,IAAa,kBAAb,cAAqC,MAAM;CACzC,YAAY,GAAiB,GAAwB;EAGnD,AAFA,MAAMA,GAASC,CAAO,GACtB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAEa,0BAAb,cAA6C,gBAAgB,CAAC,GACjD,qBAAb,cAAwC,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1,4 @@
1
- import{PostmasterDisposedError as e,PostmasterError as t,PostmasterJobError as n}from"./errors.js";import{defineJobs as r}from"./definitions.js";import{createPostmaster as i}from"./postmaster.js";export{e as PostmasterDisposedError,t as PostmasterError,n as PostmasterJobError,i as createPostmaster,r as defineJobs};
1
+ import { PostmasterDisposedError as e, PostmasterError as t, PostmasterJobError as n } from "./errors.js";
2
+ import { defineJobs as r } from "./definitions.js";
3
+ import { createPostmaster as i } from "./postmaster.js";
4
+ export { e as PostmasterDisposedError, t as PostmasterError, n as PostmasterJobError, i as createPostmaster, r as defineJobs };
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.cjs","names":[],"sources":["../src/indexeddb.ts"],"sourcesContent":["import { isPlainObject } from '@vielzeug/arsenal';\nimport { table } from '@vielzeug/vault';\nimport { createIndexedDB } from '@vielzeug/vault/indexeddb';\nimport { normalize } from './_store-utils.ts';\nimport { PostmasterError } from './errors.ts';\nimport type {\n EntryFilter,\n EntryStatus,\n JsonValue,\n PostmasterStats,\n PostmasterStore,\n StoredFailure,\n StoredJob,\n StoreTx,\n} from './types.ts';\n\nconst CORRUPT = Symbol('corrupt');\n\ntype CorruptRecord = {\n readonly [CORRUPT]: CorruptStoredJob;\n readonly availableAt?: number;\n readonly id: string;\n readonly leaseExpiresAt?: number;\n readonly status?: EntryStatus;\n};\n\ntype DatabaseJob = CorruptRecord | StoredJob;\n\ntype PostmasterSchema = {\n jobs: ReturnType<typeof table<DatabaseJob, 'id'>>;\n};\n\nexport interface CorruptStoredJob {\n readonly id?: string;\n readonly reason: string;\n}\n\ntype IndexedDbPostmasterStoreOptions = {\n readonly name: string;\n readonly onCorruptRecord?: (record: CorruptStoredJob) => void;\n};\n\nconst ENTRY_STATUSES: readonly EntryStatus[] = ['dead-letter', 'queued', 'running'];\n\nfunction isEntryStatus(value: unknown): value is EntryStatus {\n return typeof value === 'string' && ENTRY_STATUSES.includes(value as EntryStatus);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0;\n}\n\nfunction isJsonValue(value: unknown, seen = new Set<object>()): value is JsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || seen.has(value)) return false;\n\n seen.add(value);\n const valid = Array.isArray(value)\n ? value.every((item) => isJsonValue(item, seen))\n : isPlainObject(value) && Object.values(value).every((item) => isJsonValue(item, seen));\n seen.delete(value);\n return valid;\n}\n\nfunction isStoredFailure(value: unknown): value is StoredFailure {\n return (\n isPlainObject(value) &&\n typeof value.message === 'string' &&\n isNonEmptyString(value.name) &&\n isTimestamp(value.occurredAt)\n );\n}\n\n/**\n * Validates that persisted data conforms to the {@link StoredJob} shape before\n * it re-enters Postmaster's in-memory world. Replaces the prior no-op cast and\n * enforces Vault's required-codec boundary on durable records.\n */\nfunction parseStoredJob(value: unknown): StoredJob {\n if (!isPlainObject(value)) {\n throw new PostmasterError('invalid stored job: expected a plain object');\n }\n\n const {\n id,\n name,\n key,\n status,\n version,\n payload,\n attempts,\n availableAt,\n createdAt,\n updatedAt,\n failure,\n leaseExpiresAt,\n ownerId,\n } = value;\n\n if (!isNonEmptyString(id)) throw new PostmasterError('invalid stored job: id must be a non-empty string');\n if (!isNonEmptyString(name)) throw new PostmasterError('invalid stored job: name must be a non-empty string');\n if (!isNonEmptyString(key)) throw new PostmasterError('invalid stored job: key must be a non-empty string');\n if (!isEntryStatus(status)) {\n throw new PostmasterError('invalid stored job: status must be one of dead-letter, queued, running');\n }\n if (!isNonNegativeInteger(version) || version < 1) {\n throw new PostmasterError('invalid stored job: version must be a positive integer');\n }\n if (!isJsonValue(payload)) throw new PostmasterError('invalid stored job: payload must be a JSON value');\n if (!isNonNegativeInteger(attempts)) {\n throw new PostmasterError('invalid stored job: attempts must be a non-negative integer');\n }\n if (!isTimestamp(availableAt)) throw new PostmasterError('invalid stored job: availableAt must be a timestamp');\n if (!isTimestamp(createdAt)) throw new PostmasterError('invalid stored job: createdAt must be a timestamp');\n if (!isTimestamp(updatedAt)) throw new PostmasterError('invalid stored job: updatedAt must be a timestamp');\n if (failure !== undefined && !isStoredFailure(failure)) {\n throw new PostmasterError('invalid stored job: failure must be a StoredFailure');\n }\n\n if (status === 'running') {\n if (attempts < 1) throw new PostmasterError('invalid stored job: running jobs must have an attempt');\n if (!isTimestamp(leaseExpiresAt)) {\n throw new PostmasterError('invalid stored job: running jobs must have a lease expiry');\n }\n if (!isNonEmptyString(ownerId)) {\n throw new PostmasterError('invalid stored job: running jobs must have an owner');\n }\n if (failure !== undefined) throw new PostmasterError('invalid stored job: running jobs must not have a failure');\n } else if (leaseExpiresAt !== undefined || ownerId !== undefined) {\n throw new PostmasterError('invalid stored job: only running jobs may have lease ownership');\n }\n\n return {\n attempts,\n availableAt,\n createdAt,\n id,\n key,\n name,\n payload,\n status,\n updatedAt,\n version,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n\nfunction isValidRecord(record: DatabaseJob): record is StoredJob {\n return !(CORRUPT in record);\n}\n\nfunction wrap<T>(operation: string, fn: () => Promise<T>): Promise<T> {\n return fn().catch((cause: unknown) => {\n if (cause instanceof PostmasterError) throw cause;\n throw new PostmasterError(`${operation} failed`, { cause });\n });\n}\n\nexport function createIndexedDbPostmasterStore(options: IndexedDbPostmasterStoreOptions): PostmasterStore {\n const reported = new Set<string>();\n const decode = (value: unknown): DatabaseJob => {\n try {\n return parseStoredJob(value);\n } catch (cause) {\n const id = isPlainObject(value) && isNonEmptyString(value.id) ? value.id : undefined;\n const reason = cause instanceof Error ? cause.message : String(cause);\n const issue: CorruptStoredJob = { ...(id === undefined ? {} : { id }), reason };\n const signature = `${id ?? ''}\\u0000${reason}`;\n if (!reported.has(signature)) {\n reported.add(signature);\n try {\n options.onCorruptRecord?.(issue);\n } catch {}\n }\n return {\n [CORRUPT]: issue,\n id: id ?? '',\n ...(isPlainObject(value) && isTimestamp(value.availableAt) ? { availableAt: value.availableAt } : {}),\n ...(isPlainObject(value) && isTimestamp(value.leaseExpiresAt) ? { leaseExpiresAt: value.leaseExpiresAt } : {}),\n ...(isPlainObject(value) && isEntryStatus(value.status) ? { status: value.status } : {}),\n };\n }\n };\n const schema: PostmasterSchema = {\n jobs: table<DatabaseJob, 'id'>('id', {\n indexes: ['availableAt', 'leaseExpiresAt', 'status'],\n }),\n };\n const vault = createIndexedDB({\n codecs: {\n jobs: {\n decode,\n encode: (record) => {\n if (!isValidRecord(record)) throw new PostmasterError('cannot persist a corrupt stored job');\n return parseStoredJob(record);\n },\n },\n },\n name: options.name,\n schema,\n });\n\n const buildTx = (vaultTx: Parameters<Parameters<typeof vault.batch>[1]>[0]): StoreTx => ({\n async countByStatus(): Promise<PostmasterStats> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let queued = 0;\n let running = 0;\n let deadLetter = 0;\n for (const entry of entries) {\n if (entry.status === 'queued') queued += 1;\n else if (entry.status === 'running') running += 1;\n else if (entry.status === 'dead-letter') deadLetter += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n await vaultTx.delete('jobs', id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n const candidates = entries.filter(\n (entry) =>\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now),\n );\n candidates.sort((a, b) => a.availableAt - b.availableAt || a.createdAt - b.createdAt);\n return candidates[0] ? normalize(candidates[0]) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let next: number | undefined;\n for (const entry of entries) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = await vaultTx.get('jobs', id);\n return entry && isValidRecord(entry) ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n await vaultTx.put('jobs', normalize(entry));\n },\n });\n\n return {\n get disposalSignal() {\n return vault.disposalSignal;\n },\n dispose(): Promise<void> {\n return wrap('disposing IndexedDB store', () => vault.dispose());\n },\n get disposed() {\n return vault.disposed;\n },\n list(filter?: EntryFilter): Promise<StoredJob[]> {\n return wrap('listing jobs', async () => {\n const entries =\n filter?.status === undefined\n ? await vault.getAll('jobs')\n : await vault.getAllByIndex('jobs', 'status', filter.status);\n return entries\n .filter(isValidRecord)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n return vault.observe('jobs', () => listener(), { immediate: false });\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return wrap('executing transaction', () => vault.batch(['jobs'], async (vaultTx) => fn(buildTx(vaultTx))));\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await vault.dispose();\n },\n };\n}\n\nexport type { IndexedDbPostmasterStoreOptions };\n"],"mappings":"0OAgBA,IAAM,EAAU,OAAO,SAAS,EA0B1B,EAAyC,CAAC,cAAe,SAAU,SAAS,EAElF,SAAS,cAAc,EAAsC,CAC3D,OAAO,OAAO,GAAU,UAAY,EAAe,SAAS,CAAoB,CAClF,CAEA,SAAS,iBAAiB,EAAiC,CACzD,OAAO,OAAO,GAAU,UAAY,EAAM,OAAS,CACrD,CAEA,SAAS,qBAAqB,EAAiC,CAC7D,OAAO,OAAO,UAAU,CAAK,GAAM,GAAoB,CACzD,CAEA,SAAS,YAAY,EAAiC,CACpD,OAAO,OAAO,cAAc,CAAK,GAAM,GAAoB,CAC7D,CAEA,SAAS,YAAY,EAAgB,EAAO,IAAI,IAAmC,CACjF,GAAI,IAAU,MAAQ,OAAO,GAAU,WAAa,OAAO,GAAU,SAAU,MAAO,GACtF,GAAI,OAAO,GAAU,SAAU,OAAO,OAAO,SAAS,CAAK,EAC3D,GAAI,OAAO,GAAU,UAAY,EAAK,IAAI,CAAK,EAAG,MAAO,GAEzD,EAAK,IAAI,CAAK,EACd,IAAM,EAAQ,MAAM,QAAQ,CAAK,EAC7B,EAAM,MAAO,GAAS,YAAY,EAAM,CAAI,CAAC,GAAA,EAC7C,EAAA,cAAA,CAAc,CAAK,GAAK,OAAO,OAAO,CAAK,CAAC,CAAC,MAAO,GAAS,YAAY,EAAM,CAAI,CAAC,EAExF,OADA,EAAK,OAAO,CAAK,EACV,CACT,CAEA,SAAS,gBAAgB,EAAwC,CAC/D,OAAA,EACE,EAAA,cAAA,CAAc,CAAK,GACnB,OAAO,EAAM,SAAY,UACzB,iBAAiB,EAAM,IAAI,GAC3B,YAAY,EAAM,UAAU,CAEhC,CAOA,SAAS,eAAe,EAA2B,CACjD,GAAI,EAAA,EAAC,EAAA,cAAA,CAAc,CAAK,EACtB,MAAM,IAAI,EAAA,gBAAgB,6CAA6C,EAGzE,GAAM,CACJ,KACA,OACA,MACA,SACA,UACA,UACA,WACA,cACA,YACA,YACA,UACA,iBACA,WACE,EAEJ,GAAI,CAAC,iBAAiB,CAAE,EAAG,MAAM,IAAI,EAAA,gBAAgB,mDAAmD,EACxG,GAAI,CAAC,iBAAiB,CAAI,EAAG,MAAM,IAAI,EAAA,gBAAgB,qDAAqD,EAC5G,GAAI,CAAC,iBAAiB,CAAG,EAAG,MAAM,IAAI,EAAA,gBAAgB,oDAAoD,EAC1G,GAAI,CAAC,cAAc,CAAM,EACvB,MAAM,IAAI,EAAA,gBAAgB,wEAAwE,EAEpG,GAAI,CAAC,qBAAqB,CAAO,GAAK,EAAU,EAC9C,MAAM,IAAI,EAAA,gBAAgB,wDAAwD,EAEpF,GAAI,CAAC,YAAY,CAAO,EAAG,MAAM,IAAI,EAAA,gBAAgB,kDAAkD,EACvG,GAAI,CAAC,qBAAqB,CAAQ,EAChC,MAAM,IAAI,EAAA,gBAAgB,6DAA6D,EAEzF,GAAI,CAAC,YAAY,CAAW,EAAG,MAAM,IAAI,EAAA,gBAAgB,qDAAqD,EAC9G,GAAI,CAAC,YAAY,CAAS,EAAG,MAAM,IAAI,EAAA,gBAAgB,mDAAmD,EAC1G,GAAI,CAAC,YAAY,CAAS,EAAG,MAAM,IAAI,EAAA,gBAAgB,mDAAmD,EAC1G,GAAI,IAAY,IAAA,IAAa,CAAC,gBAAgB,CAAO,EACnD,MAAM,IAAI,EAAA,gBAAgB,qDAAqD,EAGjF,GAAI,IAAW,UAAW,CACxB,GAAI,EAAW,EAAG,MAAM,IAAI,EAAA,gBAAgB,uDAAuD,EACnG,GAAI,CAAC,YAAY,CAAc,EAC7B,MAAM,IAAI,EAAA,gBAAgB,2DAA2D,EAEvF,GAAI,CAAC,iBAAiB,CAAO,EAC3B,MAAM,IAAI,EAAA,gBAAgB,qDAAqD,EAEjF,GAAI,IAAY,IAAA,GAAW,MAAM,IAAI,EAAA,gBAAgB,0DAA0D,CACjH,MAAO,GAAI,IAAmB,IAAA,IAAa,IAAY,IAAA,GACrD,MAAM,IAAI,EAAA,gBAAgB,gEAAgE,EAG5F,MAAO,CACL,WACA,cACA,YACA,KACA,MACA,OACA,UACA,SACA,YACA,UACA,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAI,IAAmB,IAAA,GAAiC,CAAC,EAAtB,CAAE,gBAAe,EACpD,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,CACxC,CACF,CAEA,SAAS,cAAc,EAA0C,CAC/D,MAAO,EAAE,KAAW,EACtB,CAEA,SAAS,KAAQ,EAAmB,EAAkC,CACpE,OAAO,EAAG,CAAC,CAAC,MAAO,GAAmB,CAEpC,MADI,aAAiB,EAAA,gBAAuB,EACtC,IAAI,EAAA,gBAAgB,GAAG,EAAU,SAAU,CAAE,OAAM,CAAC,CAC5D,CAAC,CACH,CAEA,SAAgB,+BAA+B,EAA2D,CACxG,IAAM,EAAW,IAAI,IACf,OAAU,GAAgC,CAC9C,GAAI,CACF,OAAO,eAAe,CAAK,CAC7B,OAAS,EAAO,CACd,IAAM,GAAA,EAAK,EAAA,cAAA,CAAc,CAAK,GAAK,iBAAiB,EAAM,EAAE,EAAI,EAAM,GAAK,IAAA,GACrE,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC9D,EAA0B,CAAE,GAAI,IAAO,IAAA,GAAY,CAAC,EAAI,CAAE,IAAG,EAAI,QAAO,EACxE,EAAY,GAAG,GAAM,GAAG,QAAQ,IACtC,GAAI,CAAC,EAAS,IAAI,CAAS,EAAG,CAC5B,EAAS,IAAI,CAAS,EACtB,GAAI,CACF,EAAQ,kBAAkB,CAAK,CACjC,MAAQ,CAAC,CACX,CACA,MAAO,EACJ,GAAU,EACX,GAAI,GAAM,GACV,IAAA,EAAI,EAAA,cAAA,CAAc,CAAK,GAAK,YAAY,EAAM,WAAW,EAAI,CAAE,YAAa,EAAM,WAAY,EAAI,CAAC,EACnG,IAAA,EAAI,EAAA,cAAA,CAAc,CAAK,GAAK,YAAY,EAAM,cAAc,EAAI,CAAE,eAAgB,EAAM,cAAe,EAAI,CAAC,EAC5G,IAAA,EAAI,EAAA,cAAA,CAAc,CAAK,GAAK,cAAc,EAAM,MAAM,EAAI,CAAE,OAAQ,EAAM,MAAO,EAAI,CAAC,CACxF,CACF,CACF,EACM,EAA2B,CAC/B,MAAA,EAAM,EAAA,MAAA,CAAyB,KAAM,CACnC,QAAS,CAAC,cAAe,iBAAkB,QAAQ,CACrD,CAAC,CACH,EACM,GAAA,EAAQ,EAAA,gBAAA,CAAgB,CAC5B,OAAQ,CACN,KAAM,CACJ,OACA,OAAS,GAAW,CAClB,GAAI,CAAC,cAAc,CAAM,EAAG,MAAM,IAAI,EAAA,gBAAgB,qCAAqC,EAC3F,OAAO,eAAe,CAAM,CAC9B,CACF,CACF,EACA,KAAM,EAAQ,KACd,QACF,CAAC,EAEK,QAAW,IAAwE,CACvF,MAAM,eAA0C,CAC9C,IAAM,GAAW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aAAa,EAC/D,EAAS,EACT,EAAU,EACV,EAAa,EACjB,IAAK,IAAM,KAAS,EACd,EAAM,SAAW,SAAU,GAAU,EAChC,EAAM,SAAW,UAAW,GAAW,EACvC,EAAM,SAAW,gBAAe,GAAc,GAEzD,MAAO,CAAE,aAAY,SAAQ,SAAQ,CACvC,EACA,MAAM,OAAO,EAA2B,CACtC,MAAM,EAAQ,OAAO,OAAQ,CAAE,CACjC,EACA,MAAM,cAAc,EAA6C,CAE/D,IAAM,GADW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aACnC,CAAA,CAAQ,OACxB,GACE,EAAM,SAAW,UAAY,EAAM,aAAe,GAClD,EAAM,SAAW,YAAc,EAAM,gBAAkB,IAAM,CAClE,EAEA,OADA,EAAW,MAAM,EAAG,IAAM,EAAE,YAAc,EAAE,aAAe,EAAE,UAAY,EAAE,SAAS,EAC7E,EAAW,GAAK,EAAA,UAAU,EAAW,EAAE,EAAI,IAAA,EACpD,EACA,MAAM,aAAa,EAA0C,CAC3D,IAAM,GAAW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aAAa,EAC/D,EACJ,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAI,EACA,EAAM,SAAW,UAAY,EAAM,YAAc,EAAK,EAAO,EAAM,YAC9D,EAAM,SAAW,YAAc,EAAM,gBAAkB,GAAK,IAAK,EAAO,EAAM,gBACnF,IAAS,IAAA,KAAc,IAAS,IAAA,IAAa,EAAO,KAAO,EAAO,EACxE,CACA,OAAO,CACT,EACA,MAAM,IAAI,EAA4C,CACpD,IAAM,EAAQ,MAAM,EAAQ,IAAI,OAAQ,CAAE,EAC1C,OAAO,GAAS,cAAc,CAAK,EAAI,EAAA,UAAU,CAAK,EAAI,IAAA,EAC5D,EACA,MAAM,IAAI,EAAiC,CACzC,MAAM,EAAQ,IAAI,OAAQ,EAAA,UAAU,CAAK,CAAC,CAC5C,CACF,GAEA,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAM,cACf,EACA,SAAyB,CACvB,OAAO,KAAK,gCAAmC,EAAM,QAAQ,CAAC,CAChE,EACA,IAAI,UAAW,CACb,OAAO,EAAM,QACf,EACA,KAAK,EAA4C,CAC/C,OAAO,KAAK,eAAgB,UAExB,GAAQ,SAAW,IAAA,GACf,MAAM,EAAM,OAAO,MAAM,EACzB,MAAM,EAAM,cAAc,OAAQ,SAAU,EAAO,MAAM,EAAA,CAE5D,OAAO,aAAa,CAAC,CACrB,MAAM,EAAG,IAAM,EAAE,UAAY,EAAE,SAAS,CAAC,CACzC,IAAI,EAAA,SAAS,CACjB,CACH,EACA,UAAU,EAAkC,CAC1C,OAAO,EAAM,QAAQ,WAAc,EAAS,EAAG,CAAE,UAAW,EAAM,CAAC,CACrE,EACA,SAAY,EAA6C,CACvD,OAAO,KAAK,4BAA+B,EAAM,MAAM,CAAC,MAAM,EAAG,KAAO,IAAY,EAAG,QAAQ,CAAO,CAAC,CAAC,CAAC,CAC3G,EACA,MAAO,OAAO,eAA+B,CAC3C,MAAM,EAAM,QAAQ,CACtB,CACF,CACF"}
1
+ {"version":3,"file":"indexeddb.cjs","names":["isPlainObject","PostmasterError","table","createIndexedDB","normalize","require_errors","require__store_utils","_vielzeug_arsenal","_vielzeug_vault","_vielzeug_vault_indexeddb","CORRUPT","ENTRY_STATUSES","value","seen","valid","item","id","name","key","status","version","payload","attempts","availableAt","createdAt","updatedAt","failure","leaseExpiresAt","ownerId","record","fn","cause","operation","reported","reason","issue","signature","options","schema","vault","entries","vaultTx","queued","running","deadLetter","entry","candidates","now","a","b","next","wake","filter","listener"],"sources":["../src/indexeddb.ts"],"sourcesContent":["import { isPlainObject } from '@vielzeug/arsenal';\nimport { table } from '@vielzeug/vault';\nimport { createIndexedDB } from '@vielzeug/vault/indexeddb';\nimport { normalize } from './_store-utils.ts';\nimport { PostmasterError } from './errors.ts';\nimport type {\n EntryFilter,\n EntryStatus,\n JsonValue,\n PostmasterStats,\n PostmasterStore,\n StoredFailure,\n StoredJob,\n StoreTx,\n} from './types.ts';\n\nconst CORRUPT = Symbol('corrupt');\n\ntype CorruptRecord = {\n readonly [CORRUPT]: CorruptStoredJob;\n readonly availableAt?: number;\n readonly id: string;\n readonly leaseExpiresAt?: number;\n readonly status?: EntryStatus;\n};\n\ntype DatabaseJob = CorruptRecord | StoredJob;\n\ntype PostmasterSchema = {\n jobs: ReturnType<typeof table<DatabaseJob, 'id'>>;\n};\n\nexport interface CorruptStoredJob {\n readonly id?: string;\n readonly reason: string;\n}\n\ntype IndexedDbPostmasterStoreOptions = {\n readonly name: string;\n readonly onCorruptRecord?: (record: CorruptStoredJob) => void;\n};\n\nconst ENTRY_STATUSES: readonly EntryStatus[] = ['dead-letter', 'queued', 'running'];\n\nfunction isEntryStatus(value: unknown): value is EntryStatus {\n return typeof value === 'string' && ENTRY_STATUSES.includes(value as EntryStatus);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0;\n}\n\nfunction isJsonValue(value: unknown, seen = new Set<object>()): value is JsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || seen.has(value)) return false;\n\n seen.add(value);\n const valid = Array.isArray(value)\n ? value.every((item) => isJsonValue(item, seen))\n : isPlainObject(value) && Object.values(value).every((item) => isJsonValue(item, seen));\n seen.delete(value);\n return valid;\n}\n\nfunction isStoredFailure(value: unknown): value is StoredFailure {\n return (\n isPlainObject(value) &&\n typeof value.message === 'string' &&\n isNonEmptyString(value.name) &&\n isTimestamp(value.occurredAt)\n );\n}\n\n/**\n * Validates that persisted data conforms to the {@link StoredJob} shape before\n * it re-enters Postmaster's in-memory world. Replaces the prior no-op cast and\n * enforces Vault's required-codec boundary on durable records.\n */\nfunction parseStoredJob(value: unknown): StoredJob {\n if (!isPlainObject(value)) {\n throw new PostmasterError('invalid stored job: expected a plain object');\n }\n\n const {\n id,\n name,\n key,\n status,\n version,\n payload,\n attempts,\n availableAt,\n createdAt,\n updatedAt,\n failure,\n leaseExpiresAt,\n ownerId,\n } = value;\n\n if (!isNonEmptyString(id)) throw new PostmasterError('invalid stored job: id must be a non-empty string');\n if (!isNonEmptyString(name)) throw new PostmasterError('invalid stored job: name must be a non-empty string');\n if (!isNonEmptyString(key)) throw new PostmasterError('invalid stored job: key must be a non-empty string');\n if (!isEntryStatus(status)) {\n throw new PostmasterError('invalid stored job: status must be one of dead-letter, queued, running');\n }\n if (!isNonNegativeInteger(version) || version < 1) {\n throw new PostmasterError('invalid stored job: version must be a positive integer');\n }\n if (!isJsonValue(payload)) throw new PostmasterError('invalid stored job: payload must be a JSON value');\n if (!isNonNegativeInteger(attempts)) {\n throw new PostmasterError('invalid stored job: attempts must be a non-negative integer');\n }\n if (!isTimestamp(availableAt)) throw new PostmasterError('invalid stored job: availableAt must be a timestamp');\n if (!isTimestamp(createdAt)) throw new PostmasterError('invalid stored job: createdAt must be a timestamp');\n if (!isTimestamp(updatedAt)) throw new PostmasterError('invalid stored job: updatedAt must be a timestamp');\n if (failure !== undefined && !isStoredFailure(failure)) {\n throw new PostmasterError('invalid stored job: failure must be a StoredFailure');\n }\n\n if (status === 'running') {\n if (attempts < 1) throw new PostmasterError('invalid stored job: running jobs must have an attempt');\n if (!isTimestamp(leaseExpiresAt)) {\n throw new PostmasterError('invalid stored job: running jobs must have a lease expiry');\n }\n if (!isNonEmptyString(ownerId)) {\n throw new PostmasterError('invalid stored job: running jobs must have an owner');\n }\n if (failure !== undefined) throw new PostmasterError('invalid stored job: running jobs must not have a failure');\n } else if (leaseExpiresAt !== undefined || ownerId !== undefined) {\n throw new PostmasterError('invalid stored job: only running jobs may have lease ownership');\n }\n\n return {\n attempts,\n availableAt,\n createdAt,\n id,\n key,\n name,\n payload,\n status,\n updatedAt,\n version,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n\nfunction isValidRecord(record: DatabaseJob): record is StoredJob {\n return !(CORRUPT in record);\n}\n\nfunction wrap<T>(operation: string, fn: () => Promise<T>): Promise<T> {\n return fn().catch((cause: unknown) => {\n if (cause instanceof PostmasterError) throw cause;\n throw new PostmasterError(`${operation} failed`, { cause });\n });\n}\n\nexport function createIndexedDbPostmasterStore(options: IndexedDbPostmasterStoreOptions): PostmasterStore {\n const reported = new Set<string>();\n const decode = (value: unknown): DatabaseJob => {\n try {\n return parseStoredJob(value);\n } catch (cause) {\n const id = isPlainObject(value) && isNonEmptyString(value.id) ? value.id : undefined;\n const reason = cause instanceof Error ? cause.message : String(cause);\n const issue: CorruptStoredJob = { ...(id === undefined ? {} : { id }), reason };\n const signature = `${id ?? ''}\\u0000${reason}`;\n if (!reported.has(signature)) {\n reported.add(signature);\n try {\n options.onCorruptRecord?.(issue);\n } catch {}\n }\n return {\n [CORRUPT]: issue,\n id: id ?? '',\n ...(isPlainObject(value) && isTimestamp(value.availableAt) ? { availableAt: value.availableAt } : {}),\n ...(isPlainObject(value) && isTimestamp(value.leaseExpiresAt) ? { leaseExpiresAt: value.leaseExpiresAt } : {}),\n ...(isPlainObject(value) && isEntryStatus(value.status) ? { status: value.status } : {}),\n };\n }\n };\n const schema: PostmasterSchema = {\n jobs: table<DatabaseJob, 'id'>('id', {\n indexes: ['availableAt', 'leaseExpiresAt', 'status'],\n }),\n };\n const vault = createIndexedDB({\n codecs: {\n jobs: {\n decode,\n encode: (record) => {\n if (!isValidRecord(record)) throw new PostmasterError('cannot persist a corrupt stored job');\n return parseStoredJob(record);\n },\n },\n },\n name: options.name,\n schema,\n });\n\n const buildTx = (vaultTx: Parameters<Parameters<typeof vault.batch>[1]>[0]): StoreTx => ({\n async countByStatus(): Promise<PostmasterStats> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let queued = 0;\n let running = 0;\n let deadLetter = 0;\n for (const entry of entries) {\n if (entry.status === 'queued') queued += 1;\n else if (entry.status === 'running') running += 1;\n else if (entry.status === 'dead-letter') deadLetter += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n await vaultTx.delete('jobs', id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n const candidates = entries.filter(\n (entry) =>\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now),\n );\n candidates.sort((a, b) => a.availableAt - b.availableAt || a.createdAt - b.createdAt);\n return candidates[0] ? normalize(candidates[0]) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let next: number | undefined;\n for (const entry of entries) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = await vaultTx.get('jobs', id);\n return entry && isValidRecord(entry) ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n await vaultTx.put('jobs', normalize(entry));\n },\n });\n\n return {\n get disposalSignal() {\n return vault.disposalSignal;\n },\n dispose(): Promise<void> {\n return wrap('disposing IndexedDB store', () => vault.dispose());\n },\n get disposed() {\n return vault.disposed;\n },\n list(filter?: EntryFilter): Promise<StoredJob[]> {\n return wrap('listing jobs', async () => {\n const entries =\n filter?.status === undefined\n ? await vault.getAll('jobs')\n : await vault.getAllByIndex('jobs', 'status', filter.status);\n return entries\n .filter(isValidRecord)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n return vault.observe('jobs', () => listener(), { immediate: false });\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return wrap('executing transaction', () => vault.batch(['jobs'], async (vaultTx) => fn(buildTx(vaultTx))));\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await vault.dispose();\n },\n };\n}\n\nexport type { IndexedDbPostmasterStoreOptions };\n"],"mappings":"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"}
package/dist/indexeddb.js CHANGED
@@ -1,2 +1,176 @@
1
- import{PostmasterError as e}from"./errors.js";import{normalize as t}from"./_store-utils.js";import{isPlainObject as n}from"@vielzeug/arsenal";import{table as r}from"@vielzeug/vault";import{createIndexedDB as i}from"@vielzeug/vault/indexeddb";var a=Symbol(`corrupt`),o=[`dead-letter`,`queued`,`running`];function isEntryStatus(e){return typeof e==`string`&&o.includes(e)}function isNonEmptyString(e){return typeof e==`string`&&e.length>0}function isNonNegativeInteger(e){return Number.isInteger(e)&&e>=0}function isTimestamp(e){return Number.isSafeInteger(e)&&e>=0}function isJsonValue(e,t=new Set){if(e===null||typeof e==`boolean`||typeof e==`string`)return!0;if(typeof e==`number`)return Number.isFinite(e);if(typeof e!=`object`||t.has(e))return!1;t.add(e);let r=Array.isArray(e)?e.every(e=>isJsonValue(e,t)):n(e)&&Object.values(e).every(e=>isJsonValue(e,t));return t.delete(e),r}function isStoredFailure(e){return n(e)&&typeof e.message==`string`&&isNonEmptyString(e.name)&&isTimestamp(e.occurredAt)}function parseStoredJob(t){if(!n(t))throw new e(`invalid stored job: expected a plain object`);let{id:r,name:i,key:a,status:o,version:s,payload:c,attempts:l,availableAt:u,createdAt:d,updatedAt:f,failure:p,leaseExpiresAt:m,ownerId:h}=t;if(!isNonEmptyString(r))throw new e(`invalid stored job: id must be a non-empty string`);if(!isNonEmptyString(i))throw new e(`invalid stored job: name must be a non-empty string`);if(!isNonEmptyString(a))throw new e(`invalid stored job: key must be a non-empty string`);if(!isEntryStatus(o))throw new e(`invalid stored job: status must be one of dead-letter, queued, running`);if(!isNonNegativeInteger(s)||s<1)throw new e(`invalid stored job: version must be a positive integer`);if(!isJsonValue(c))throw new e(`invalid stored job: payload must be a JSON value`);if(!isNonNegativeInteger(l))throw new e(`invalid stored job: attempts must be a non-negative integer`);if(!isTimestamp(u))throw new e(`invalid stored job: availableAt must be a timestamp`);if(!isTimestamp(d))throw new e(`invalid stored job: createdAt must be a timestamp`);if(!isTimestamp(f))throw new e(`invalid stored job: updatedAt must be a timestamp`);if(p!==void 0&&!isStoredFailure(p))throw new e(`invalid stored job: failure must be a StoredFailure`);if(o===`running`){if(l<1)throw new e(`invalid stored job: running jobs must have an attempt`);if(!isTimestamp(m))throw new e(`invalid stored job: running jobs must have a lease expiry`);if(!isNonEmptyString(h))throw new e(`invalid stored job: running jobs must have an owner`);if(p!==void 0)throw new e(`invalid stored job: running jobs must not have a failure`)}else if(m!==void 0||h!==void 0)throw new e(`invalid stored job: only running jobs may have lease ownership`);return{attempts:l,availableAt:u,createdAt:d,id:r,key:a,name:i,payload:c,status:o,updatedAt:f,version:s,...p===void 0?{}:{failure:p},...m===void 0?{}:{leaseExpiresAt:m},...h===void 0?{}:{ownerId:h}}}function isValidRecord(e){return!(a in e)}function wrap(t,n){return n().catch(n=>{throw n instanceof e?n:new e(`${t} failed`,{cause:n})})}function createIndexedDbPostmasterStore(o){let s=new Set,decode=e=>{try{return parseStoredJob(e)}catch(t){let r=n(e)&&isNonEmptyString(e.id)?e.id:void 0,i=t instanceof Error?t.message:String(t),c={...r===void 0?{}:{id:r},reason:i},l=`${r??``}\u0000${i}`;if(!s.has(l)){s.add(l);try{o.onCorruptRecord?.(c)}catch{}}return{[a]:c,id:r??``,...n(e)&&isTimestamp(e.availableAt)?{availableAt:e.availableAt}:{},...n(e)&&isTimestamp(e.leaseExpiresAt)?{leaseExpiresAt:e.leaseExpiresAt}:{},...n(e)&&isEntryStatus(e.status)?{status:e.status}:{}}}},c={jobs:r(`id`,{indexes:[`availableAt`,`leaseExpiresAt`,`status`]})},l=i({codecs:{jobs:{decode,encode:t=>{if(!isValidRecord(t))throw new e(`cannot persist a corrupt stored job`);return parseStoredJob(t)}}},name:o.name,schema:c}),buildTx=e=>({async countByStatus(){let t=(await e.getAll(`jobs`)).filter(isValidRecord),n=0,r=0,i=0;for(let e of t)e.status===`queued`?n+=1:e.status===`running`?r+=1:e.status===`dead-letter`&&(i+=1);return{deadLetter:i,queued:n,running:r}},async delete(t){await e.delete(`jobs`,t)},async findClaimable(n){let r=(await e.getAll(`jobs`)).filter(isValidRecord).filter(e=>e.status===`queued`&&e.availableAt<=n||e.status===`running`&&(e.leaseExpiresAt??0)<=n);return r.sort((e,t)=>e.availableAt-t.availableAt||e.createdAt-t.createdAt),r[0]?t(r[0]):void 0},async findNextWake(t){let n=(await e.getAll(`jobs`)).filter(isValidRecord),r;for(let e of n){let n;e.status===`queued`&&e.availableAt>t?n=e.availableAt:e.status===`running`&&(e.leaseExpiresAt??0)>t&&(n=e.leaseExpiresAt),n!==void 0&&(r===void 0||n<r)&&(r=n)}return r},async get(n){let r=await e.get(`jobs`,n);return r&&isValidRecord(r)?t(r):void 0},async put(n){await e.put(`jobs`,t(n))}});return{get disposalSignal(){return l.disposalSignal},dispose(){return wrap(`disposing IndexedDB store`,()=>l.dispose())},get disposed(){return l.disposed},list(e){return wrap(`listing jobs`,async()=>(e?.status===void 0?await l.getAll(`jobs`):await l.getAllByIndex(`jobs`,`status`,e.status)).filter(isValidRecord).sort((e,t)=>e.createdAt-t.createdAt).map(t))},subscribe(e){return l.observe(`jobs`,()=>e(),{immediate:!1})},transact(e){return wrap(`executing transaction`,()=>l.batch([`jobs`],async t=>e(buildTx(t))))},async[Symbol.asyncDispose](){await l.dispose()}}}export{createIndexedDbPostmasterStore};
1
+ import { PostmasterError as e } from "./errors.js";
2
+ import { normalize as t } from "./_store-utils.js";
3
+ import { isPlainObject as n } from "@vielzeug/arsenal";
4
+ import { table as r } from "@vielzeug/vault";
5
+ import { createIndexedDB as i } from "@vielzeug/vault/indexeddb";
6
+ //#region src/indexeddb.ts
7
+ var a = Symbol("corrupt"), o = [
8
+ "dead-letter",
9
+ "queued",
10
+ "running"
11
+ ];
12
+ function isEntryStatus(e) {
13
+ return typeof e == "string" && o.includes(e);
14
+ }
15
+ function isNonEmptyString(e) {
16
+ return typeof e == "string" && e.length > 0;
17
+ }
18
+ function isNonNegativeInteger(e) {
19
+ return Number.isInteger(e) && e >= 0;
20
+ }
21
+ function isTimestamp(e) {
22
+ return Number.isSafeInteger(e) && e >= 0;
23
+ }
24
+ function isJsonValue(e, t = /* @__PURE__ */ new Set()) {
25
+ if (e === null || typeof e == "boolean" || typeof e == "string") return !0;
26
+ if (typeof e == "number") return Number.isFinite(e);
27
+ if (typeof e != "object" || t.has(e)) return !1;
28
+ t.add(e);
29
+ let r = Array.isArray(e) ? e.every((e) => isJsonValue(e, t)) : n(e) && Object.values(e).every((e) => isJsonValue(e, t));
30
+ return t.delete(e), r;
31
+ }
32
+ function isStoredFailure(e) {
33
+ return n(e) && typeof e.message == "string" && isNonEmptyString(e.name) && isTimestamp(e.occurredAt);
34
+ }
35
+ function parseStoredJob(t) {
36
+ if (!n(t)) throw new e("invalid stored job: expected a plain object");
37
+ let { id: r, name: i, key: a, status: o, version: s, payload: c, attempts: l, availableAt: u, createdAt: d, updatedAt: f, failure: p, leaseExpiresAt: m, ownerId: h } = t;
38
+ if (!isNonEmptyString(r)) throw new e("invalid stored job: id must be a non-empty string");
39
+ if (!isNonEmptyString(i)) throw new e("invalid stored job: name must be a non-empty string");
40
+ if (!isNonEmptyString(a)) throw new e("invalid stored job: key must be a non-empty string");
41
+ if (!isEntryStatus(o)) throw new e("invalid stored job: status must be one of dead-letter, queued, running");
42
+ if (!isNonNegativeInteger(s) || s < 1) throw new e("invalid stored job: version must be a positive integer");
43
+ if (!isJsonValue(c)) throw new e("invalid stored job: payload must be a JSON value");
44
+ if (!isNonNegativeInteger(l)) throw new e("invalid stored job: attempts must be a non-negative integer");
45
+ if (!isTimestamp(u)) throw new e("invalid stored job: availableAt must be a timestamp");
46
+ if (!isTimestamp(d)) throw new e("invalid stored job: createdAt must be a timestamp");
47
+ if (!isTimestamp(f)) throw new e("invalid stored job: updatedAt must be a timestamp");
48
+ if (p !== void 0 && !isStoredFailure(p)) throw new e("invalid stored job: failure must be a StoredFailure");
49
+ if (o === "running") {
50
+ if (l < 1) throw new e("invalid stored job: running jobs must have an attempt");
51
+ if (!isTimestamp(m)) throw new e("invalid stored job: running jobs must have a lease expiry");
52
+ if (!isNonEmptyString(h)) throw new e("invalid stored job: running jobs must have an owner");
53
+ if (p !== void 0) throw new e("invalid stored job: running jobs must not have a failure");
54
+ } else if (m !== void 0 || h !== void 0) throw new e("invalid stored job: only running jobs may have lease ownership");
55
+ return {
56
+ attempts: l,
57
+ availableAt: u,
58
+ createdAt: d,
59
+ id: r,
60
+ key: a,
61
+ name: i,
62
+ payload: c,
63
+ status: o,
64
+ updatedAt: f,
65
+ version: s,
66
+ ...p === void 0 ? {} : { failure: p },
67
+ ...m === void 0 ? {} : { leaseExpiresAt: m },
68
+ ...h === void 0 ? {} : { ownerId: h }
69
+ };
70
+ }
71
+ function isValidRecord(e) {
72
+ return !(a in e);
73
+ }
74
+ function wrap(t, n) {
75
+ return n().catch((n) => {
76
+ throw n instanceof e ? n : new e(`${t} failed`, { cause: n });
77
+ });
78
+ }
79
+ function createIndexedDbPostmasterStore(o) {
80
+ let s = /* @__PURE__ */ new Set(), decode = (e) => {
81
+ try {
82
+ return parseStoredJob(e);
83
+ } catch (t) {
84
+ let r = n(e) && isNonEmptyString(e.id) ? e.id : void 0, i = t instanceof Error ? t.message : String(t), c = {
85
+ ...r === void 0 ? {} : { id: r },
86
+ reason: i
87
+ }, l = `${r ?? ""}\u0000${i}`;
88
+ if (!s.has(l)) {
89
+ s.add(l);
90
+ try {
91
+ o.onCorruptRecord?.(c);
92
+ } catch {}
93
+ }
94
+ return {
95
+ [a]: c,
96
+ id: r ?? "",
97
+ ...n(e) && isTimestamp(e.availableAt) ? { availableAt: e.availableAt } : {},
98
+ ...n(e) && isTimestamp(e.leaseExpiresAt) ? { leaseExpiresAt: e.leaseExpiresAt } : {},
99
+ ...n(e) && isEntryStatus(e.status) ? { status: e.status } : {}
100
+ };
101
+ }
102
+ }, c = { jobs: r("id", { indexes: [
103
+ "availableAt",
104
+ "leaseExpiresAt",
105
+ "status"
106
+ ] }) }, l = i({
107
+ codecs: { jobs: {
108
+ decode,
109
+ encode: (t) => {
110
+ if (!isValidRecord(t)) throw new e("cannot persist a corrupt stored job");
111
+ return parseStoredJob(t);
112
+ }
113
+ } },
114
+ name: o.name,
115
+ schema: c
116
+ }), buildTx = (e) => ({
117
+ async countByStatus() {
118
+ let t = (await e.getAll("jobs")).filter(isValidRecord), n = 0, r = 0, i = 0;
119
+ for (let e of t) e.status === "queued" ? n += 1 : e.status === "running" ? r += 1 : e.status === "dead-letter" && (i += 1);
120
+ return {
121
+ deadLetter: i,
122
+ queued: n,
123
+ running: r
124
+ };
125
+ },
126
+ async delete(t) {
127
+ await e.delete("jobs", t);
128
+ },
129
+ async findClaimable(n) {
130
+ let r = (await e.getAll("jobs")).filter(isValidRecord).filter((e) => e.status === "queued" && e.availableAt <= n || e.status === "running" && (e.leaseExpiresAt ?? 0) <= n);
131
+ return r.sort((e, t) => e.availableAt - t.availableAt || e.createdAt - t.createdAt), r[0] ? t(r[0]) : void 0;
132
+ },
133
+ async findNextWake(t) {
134
+ let n = (await e.getAll("jobs")).filter(isValidRecord), r;
135
+ for (let e of n) {
136
+ let n;
137
+ e.status === "queued" && e.availableAt > t ? n = e.availableAt : e.status === "running" && (e.leaseExpiresAt ?? 0) > t && (n = e.leaseExpiresAt), n !== void 0 && (r === void 0 || n < r) && (r = n);
138
+ }
139
+ return r;
140
+ },
141
+ async get(n) {
142
+ let r = await e.get("jobs", n);
143
+ return r && isValidRecord(r) ? t(r) : void 0;
144
+ },
145
+ async put(n) {
146
+ await e.put("jobs", t(n));
147
+ }
148
+ });
149
+ return {
150
+ get disposalSignal() {
151
+ return l.disposalSignal;
152
+ },
153
+ dispose() {
154
+ return wrap("disposing IndexedDB store", () => l.dispose());
155
+ },
156
+ get disposed() {
157
+ return l.disposed;
158
+ },
159
+ list(e) {
160
+ return wrap("listing jobs", async () => (e?.status === void 0 ? await l.getAll("jobs") : await l.getAllByIndex("jobs", "status", e.status)).filter(isValidRecord).sort((e, t) => e.createdAt - t.createdAt).map(t));
161
+ },
162
+ subscribe(e) {
163
+ return l.observe("jobs", () => e(), { immediate: !1 });
164
+ },
165
+ transact(e) {
166
+ return wrap("executing transaction", () => l.batch(["jobs"], async (t) => e(buildTx(t))));
167
+ },
168
+ async [Symbol.asyncDispose]() {
169
+ await l.dispose();
170
+ }
171
+ };
172
+ }
173
+ //#endregion
174
+ export { createIndexedDbPostmasterStore };
175
+
2
176
  //# sourceMappingURL=indexeddb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.js","names":[],"sources":["../src/indexeddb.ts"],"sourcesContent":["import { isPlainObject } from '@vielzeug/arsenal';\nimport { table } from '@vielzeug/vault';\nimport { createIndexedDB } from '@vielzeug/vault/indexeddb';\nimport { normalize } from './_store-utils.ts';\nimport { PostmasterError } from './errors.ts';\nimport type {\n EntryFilter,\n EntryStatus,\n JsonValue,\n PostmasterStats,\n PostmasterStore,\n StoredFailure,\n StoredJob,\n StoreTx,\n} from './types.ts';\n\nconst CORRUPT = Symbol('corrupt');\n\ntype CorruptRecord = {\n readonly [CORRUPT]: CorruptStoredJob;\n readonly availableAt?: number;\n readonly id: string;\n readonly leaseExpiresAt?: number;\n readonly status?: EntryStatus;\n};\n\ntype DatabaseJob = CorruptRecord | StoredJob;\n\ntype PostmasterSchema = {\n jobs: ReturnType<typeof table<DatabaseJob, 'id'>>;\n};\n\nexport interface CorruptStoredJob {\n readonly id?: string;\n readonly reason: string;\n}\n\ntype IndexedDbPostmasterStoreOptions = {\n readonly name: string;\n readonly onCorruptRecord?: (record: CorruptStoredJob) => void;\n};\n\nconst ENTRY_STATUSES: readonly EntryStatus[] = ['dead-letter', 'queued', 'running'];\n\nfunction isEntryStatus(value: unknown): value is EntryStatus {\n return typeof value === 'string' && ENTRY_STATUSES.includes(value as EntryStatus);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0;\n}\n\nfunction isJsonValue(value: unknown, seen = new Set<object>()): value is JsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || seen.has(value)) return false;\n\n seen.add(value);\n const valid = Array.isArray(value)\n ? value.every((item) => isJsonValue(item, seen))\n : isPlainObject(value) && Object.values(value).every((item) => isJsonValue(item, seen));\n seen.delete(value);\n return valid;\n}\n\nfunction isStoredFailure(value: unknown): value is StoredFailure {\n return (\n isPlainObject(value) &&\n typeof value.message === 'string' &&\n isNonEmptyString(value.name) &&\n isTimestamp(value.occurredAt)\n );\n}\n\n/**\n * Validates that persisted data conforms to the {@link StoredJob} shape before\n * it re-enters Postmaster's in-memory world. Replaces the prior no-op cast and\n * enforces Vault's required-codec boundary on durable records.\n */\nfunction parseStoredJob(value: unknown): StoredJob {\n if (!isPlainObject(value)) {\n throw new PostmasterError('invalid stored job: expected a plain object');\n }\n\n const {\n id,\n name,\n key,\n status,\n version,\n payload,\n attempts,\n availableAt,\n createdAt,\n updatedAt,\n failure,\n leaseExpiresAt,\n ownerId,\n } = value;\n\n if (!isNonEmptyString(id)) throw new PostmasterError('invalid stored job: id must be a non-empty string');\n if (!isNonEmptyString(name)) throw new PostmasterError('invalid stored job: name must be a non-empty string');\n if (!isNonEmptyString(key)) throw new PostmasterError('invalid stored job: key must be a non-empty string');\n if (!isEntryStatus(status)) {\n throw new PostmasterError('invalid stored job: status must be one of dead-letter, queued, running');\n }\n if (!isNonNegativeInteger(version) || version < 1) {\n throw new PostmasterError('invalid stored job: version must be a positive integer');\n }\n if (!isJsonValue(payload)) throw new PostmasterError('invalid stored job: payload must be a JSON value');\n if (!isNonNegativeInteger(attempts)) {\n throw new PostmasterError('invalid stored job: attempts must be a non-negative integer');\n }\n if (!isTimestamp(availableAt)) throw new PostmasterError('invalid stored job: availableAt must be a timestamp');\n if (!isTimestamp(createdAt)) throw new PostmasterError('invalid stored job: createdAt must be a timestamp');\n if (!isTimestamp(updatedAt)) throw new PostmasterError('invalid stored job: updatedAt must be a timestamp');\n if (failure !== undefined && !isStoredFailure(failure)) {\n throw new PostmasterError('invalid stored job: failure must be a StoredFailure');\n }\n\n if (status === 'running') {\n if (attempts < 1) throw new PostmasterError('invalid stored job: running jobs must have an attempt');\n if (!isTimestamp(leaseExpiresAt)) {\n throw new PostmasterError('invalid stored job: running jobs must have a lease expiry');\n }\n if (!isNonEmptyString(ownerId)) {\n throw new PostmasterError('invalid stored job: running jobs must have an owner');\n }\n if (failure !== undefined) throw new PostmasterError('invalid stored job: running jobs must not have a failure');\n } else if (leaseExpiresAt !== undefined || ownerId !== undefined) {\n throw new PostmasterError('invalid stored job: only running jobs may have lease ownership');\n }\n\n return {\n attempts,\n availableAt,\n createdAt,\n id,\n key,\n name,\n payload,\n status,\n updatedAt,\n version,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n\nfunction isValidRecord(record: DatabaseJob): record is StoredJob {\n return !(CORRUPT in record);\n}\n\nfunction wrap<T>(operation: string, fn: () => Promise<T>): Promise<T> {\n return fn().catch((cause: unknown) => {\n if (cause instanceof PostmasterError) throw cause;\n throw new PostmasterError(`${operation} failed`, { cause });\n });\n}\n\nexport function createIndexedDbPostmasterStore(options: IndexedDbPostmasterStoreOptions): PostmasterStore {\n const reported = new Set<string>();\n const decode = (value: unknown): DatabaseJob => {\n try {\n return parseStoredJob(value);\n } catch (cause) {\n const id = isPlainObject(value) && isNonEmptyString(value.id) ? value.id : undefined;\n const reason = cause instanceof Error ? cause.message : String(cause);\n const issue: CorruptStoredJob = { ...(id === undefined ? {} : { id }), reason };\n const signature = `${id ?? ''}\\u0000${reason}`;\n if (!reported.has(signature)) {\n reported.add(signature);\n try {\n options.onCorruptRecord?.(issue);\n } catch {}\n }\n return {\n [CORRUPT]: issue,\n id: id ?? '',\n ...(isPlainObject(value) && isTimestamp(value.availableAt) ? { availableAt: value.availableAt } : {}),\n ...(isPlainObject(value) && isTimestamp(value.leaseExpiresAt) ? { leaseExpiresAt: value.leaseExpiresAt } : {}),\n ...(isPlainObject(value) && isEntryStatus(value.status) ? { status: value.status } : {}),\n };\n }\n };\n const schema: PostmasterSchema = {\n jobs: table<DatabaseJob, 'id'>('id', {\n indexes: ['availableAt', 'leaseExpiresAt', 'status'],\n }),\n };\n const vault = createIndexedDB({\n codecs: {\n jobs: {\n decode,\n encode: (record) => {\n if (!isValidRecord(record)) throw new PostmasterError('cannot persist a corrupt stored job');\n return parseStoredJob(record);\n },\n },\n },\n name: options.name,\n schema,\n });\n\n const buildTx = (vaultTx: Parameters<Parameters<typeof vault.batch>[1]>[0]): StoreTx => ({\n async countByStatus(): Promise<PostmasterStats> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let queued = 0;\n let running = 0;\n let deadLetter = 0;\n for (const entry of entries) {\n if (entry.status === 'queued') queued += 1;\n else if (entry.status === 'running') running += 1;\n else if (entry.status === 'dead-letter') deadLetter += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n await vaultTx.delete('jobs', id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n const candidates = entries.filter(\n (entry) =>\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now),\n );\n candidates.sort((a, b) => a.availableAt - b.availableAt || a.createdAt - b.createdAt);\n return candidates[0] ? normalize(candidates[0]) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let next: number | undefined;\n for (const entry of entries) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = await vaultTx.get('jobs', id);\n return entry && isValidRecord(entry) ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n await vaultTx.put('jobs', normalize(entry));\n },\n });\n\n return {\n get disposalSignal() {\n return vault.disposalSignal;\n },\n dispose(): Promise<void> {\n return wrap('disposing IndexedDB store', () => vault.dispose());\n },\n get disposed() {\n return vault.disposed;\n },\n list(filter?: EntryFilter): Promise<StoredJob[]> {\n return wrap('listing jobs', async () => {\n const entries =\n filter?.status === undefined\n ? await vault.getAll('jobs')\n : await vault.getAllByIndex('jobs', 'status', filter.status);\n return entries\n .filter(isValidRecord)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n return vault.observe('jobs', () => listener(), { immediate: false });\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return wrap('executing transaction', () => vault.batch(['jobs'], async (vaultTx) => fn(buildTx(vaultTx))));\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await vault.dispose();\n },\n };\n}\n\nexport type { IndexedDbPostmasterStoreOptions };\n"],"mappings":"kPAgBA,IAAM,EAAU,OAAO,SAAS,EA0B1B,EAAyC,CAAC,cAAe,SAAU,SAAS,EAElF,SAAS,cAAc,EAAsC,CAC3D,OAAO,OAAO,GAAU,UAAY,EAAe,SAAS,CAAoB,CAClF,CAEA,SAAS,iBAAiB,EAAiC,CACzD,OAAO,OAAO,GAAU,UAAY,EAAM,OAAS,CACrD,CAEA,SAAS,qBAAqB,EAAiC,CAC7D,OAAO,OAAO,UAAU,CAAK,GAAM,GAAoB,CACzD,CAEA,SAAS,YAAY,EAAiC,CACpD,OAAO,OAAO,cAAc,CAAK,GAAM,GAAoB,CAC7D,CAEA,SAAS,YAAY,EAAgB,EAAO,IAAI,IAAmC,CACjF,GAAI,IAAU,MAAQ,OAAO,GAAU,WAAa,OAAO,GAAU,SAAU,MAAO,GACtF,GAAI,OAAO,GAAU,SAAU,OAAO,OAAO,SAAS,CAAK,EAC3D,GAAI,OAAO,GAAU,UAAY,EAAK,IAAI,CAAK,EAAG,MAAO,GAEzD,EAAK,IAAI,CAAK,EACd,IAAM,EAAQ,MAAM,QAAQ,CAAK,EAC7B,EAAM,MAAO,GAAS,YAAY,EAAM,CAAI,CAAC,EAC7C,EAAc,CAAK,GAAK,OAAO,OAAO,CAAK,CAAC,CAAC,MAAO,GAAS,YAAY,EAAM,CAAI,CAAC,EAExF,OADA,EAAK,OAAO,CAAK,EACV,CACT,CAEA,SAAS,gBAAgB,EAAwC,CAC/D,OACE,EAAc,CAAK,GACnB,OAAO,EAAM,SAAY,UACzB,iBAAiB,EAAM,IAAI,GAC3B,YAAY,EAAM,UAAU,CAEhC,CAOA,SAAS,eAAe,EAA2B,CACjD,GAAI,CAAC,EAAc,CAAK,EACtB,MAAM,IAAI,EAAgB,6CAA6C,EAGzE,GAAM,CACJ,KACA,OACA,MACA,SACA,UACA,UACA,WACA,cACA,YACA,YACA,UACA,iBACA,WACE,EAEJ,GAAI,CAAC,iBAAiB,CAAE,EAAG,MAAM,IAAI,EAAgB,mDAAmD,EACxG,GAAI,CAAC,iBAAiB,CAAI,EAAG,MAAM,IAAI,EAAgB,qDAAqD,EAC5G,GAAI,CAAC,iBAAiB,CAAG,EAAG,MAAM,IAAI,EAAgB,oDAAoD,EAC1G,GAAI,CAAC,cAAc,CAAM,EACvB,MAAM,IAAI,EAAgB,wEAAwE,EAEpG,GAAI,CAAC,qBAAqB,CAAO,GAAK,EAAU,EAC9C,MAAM,IAAI,EAAgB,wDAAwD,EAEpF,GAAI,CAAC,YAAY,CAAO,EAAG,MAAM,IAAI,EAAgB,kDAAkD,EACvG,GAAI,CAAC,qBAAqB,CAAQ,EAChC,MAAM,IAAI,EAAgB,6DAA6D,EAEzF,GAAI,CAAC,YAAY,CAAW,EAAG,MAAM,IAAI,EAAgB,qDAAqD,EAC9G,GAAI,CAAC,YAAY,CAAS,EAAG,MAAM,IAAI,EAAgB,mDAAmD,EAC1G,GAAI,CAAC,YAAY,CAAS,EAAG,MAAM,IAAI,EAAgB,mDAAmD,EAC1G,GAAI,IAAY,IAAA,IAAa,CAAC,gBAAgB,CAAO,EACnD,MAAM,IAAI,EAAgB,qDAAqD,EAGjF,GAAI,IAAW,UAAW,CACxB,GAAI,EAAW,EAAG,MAAM,IAAI,EAAgB,uDAAuD,EACnG,GAAI,CAAC,YAAY,CAAc,EAC7B,MAAM,IAAI,EAAgB,2DAA2D,EAEvF,GAAI,CAAC,iBAAiB,CAAO,EAC3B,MAAM,IAAI,EAAgB,qDAAqD,EAEjF,GAAI,IAAY,IAAA,GAAW,MAAM,IAAI,EAAgB,0DAA0D,CACjH,MAAO,GAAI,IAAmB,IAAA,IAAa,IAAY,IAAA,GACrD,MAAM,IAAI,EAAgB,gEAAgE,EAG5F,MAAO,CACL,WACA,cACA,YACA,KACA,MACA,OACA,UACA,SACA,YACA,UACA,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,EACtC,GAAI,IAAmB,IAAA,GAAiC,CAAC,EAAtB,CAAE,gBAAe,EACpD,GAAI,IAAY,IAAA,GAA0B,CAAC,EAAf,CAAE,SAAQ,CACxC,CACF,CAEA,SAAS,cAAc,EAA0C,CAC/D,MAAO,EAAE,KAAW,EACtB,CAEA,SAAS,KAAQ,EAAmB,EAAkC,CACpE,OAAO,EAAG,CAAC,CAAC,MAAO,GAAmB,CAEpC,MADI,aAAiB,EAAuB,EACtC,IAAI,EAAgB,GAAG,EAAU,SAAU,CAAE,OAAM,CAAC,CAC5D,CAAC,CACH,CAEA,SAAgB,+BAA+B,EAA2D,CACxG,IAAM,EAAW,IAAI,IACf,OAAU,GAAgC,CAC9C,GAAI,CACF,OAAO,eAAe,CAAK,CAC7B,OAAS,EAAO,CACd,IAAM,EAAK,EAAc,CAAK,GAAK,iBAAiB,EAAM,EAAE,EAAI,EAAM,GAAK,IAAA,GACrE,EAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC9D,EAA0B,CAAE,GAAI,IAAO,IAAA,GAAY,CAAC,EAAI,CAAE,IAAG,EAAI,QAAO,EACxE,EAAY,GAAG,GAAM,GAAG,QAAQ,IACtC,GAAI,CAAC,EAAS,IAAI,CAAS,EAAG,CAC5B,EAAS,IAAI,CAAS,EACtB,GAAI,CACF,EAAQ,kBAAkB,CAAK,CACjC,MAAQ,CAAC,CACX,CACA,MAAO,EACJ,GAAU,EACX,GAAI,GAAM,GACV,GAAI,EAAc,CAAK,GAAK,YAAY,EAAM,WAAW,EAAI,CAAE,YAAa,EAAM,WAAY,EAAI,CAAC,EACnG,GAAI,EAAc,CAAK,GAAK,YAAY,EAAM,cAAc,EAAI,CAAE,eAAgB,EAAM,cAAe,EAAI,CAAC,EAC5G,GAAI,EAAc,CAAK,GAAK,cAAc,EAAM,MAAM,EAAI,CAAE,OAAQ,EAAM,MAAO,EAAI,CAAC,CACxF,CACF,CACF,EACM,EAA2B,CAC/B,KAAM,EAAyB,KAAM,CACnC,QAAS,CAAC,cAAe,iBAAkB,QAAQ,CACrD,CAAC,CACH,EACM,EAAQ,EAAgB,CAC5B,OAAQ,CACN,KAAM,CACJ,OACA,OAAS,GAAW,CAClB,GAAI,CAAC,cAAc,CAAM,EAAG,MAAM,IAAI,EAAgB,qCAAqC,EAC3F,OAAO,eAAe,CAAM,CAC9B,CACF,CACF,EACA,KAAM,EAAQ,KACd,QACF,CAAC,EAEK,QAAW,IAAwE,CACvF,MAAM,eAA0C,CAC9C,IAAM,GAAW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aAAa,EAC/D,EAAS,EACT,EAAU,EACV,EAAa,EACjB,IAAK,IAAM,KAAS,EACd,EAAM,SAAW,SAAU,GAAU,EAChC,EAAM,SAAW,UAAW,GAAW,EACvC,EAAM,SAAW,gBAAe,GAAc,GAEzD,MAAO,CAAE,aAAY,SAAQ,SAAQ,CACvC,EACA,MAAM,OAAO,EAA2B,CACtC,MAAM,EAAQ,OAAO,OAAQ,CAAE,CACjC,EACA,MAAM,cAAc,EAA6C,CAE/D,IAAM,GADW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aACnC,CAAA,CAAQ,OACxB,GACE,EAAM,SAAW,UAAY,EAAM,aAAe,GAClD,EAAM,SAAW,YAAc,EAAM,gBAAkB,IAAM,CAClE,EAEA,OADA,EAAW,MAAM,EAAG,IAAM,EAAE,YAAc,EAAE,aAAe,EAAE,UAAY,EAAE,SAAS,EAC7E,EAAW,GAAK,EAAU,EAAW,EAAE,EAAI,IAAA,EACpD,EACA,MAAM,aAAa,EAA0C,CAC3D,IAAM,GAAW,MAAM,EAAQ,OAAO,MAAM,EAAA,CAAG,OAAO,aAAa,EAC/D,EACJ,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAI,EACA,EAAM,SAAW,UAAY,EAAM,YAAc,EAAK,EAAO,EAAM,YAC9D,EAAM,SAAW,YAAc,EAAM,gBAAkB,GAAK,IAAK,EAAO,EAAM,gBACnF,IAAS,IAAA,KAAc,IAAS,IAAA,IAAa,EAAO,KAAO,EAAO,EACxE,CACA,OAAO,CACT,EACA,MAAM,IAAI,EAA4C,CACpD,IAAM,EAAQ,MAAM,EAAQ,IAAI,OAAQ,CAAE,EAC1C,OAAO,GAAS,cAAc,CAAK,EAAI,EAAU,CAAK,EAAI,IAAA,EAC5D,EACA,MAAM,IAAI,EAAiC,CACzC,MAAM,EAAQ,IAAI,OAAQ,EAAU,CAAK,CAAC,CAC5C,CACF,GAEA,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAM,cACf,EACA,SAAyB,CACvB,OAAO,KAAK,gCAAmC,EAAM,QAAQ,CAAC,CAChE,EACA,IAAI,UAAW,CACb,OAAO,EAAM,QACf,EACA,KAAK,EAA4C,CAC/C,OAAO,KAAK,eAAgB,UAExB,GAAQ,SAAW,IAAA,GACf,MAAM,EAAM,OAAO,MAAM,EACzB,MAAM,EAAM,cAAc,OAAQ,SAAU,EAAO,MAAM,EAAA,CAE5D,OAAO,aAAa,CAAC,CACrB,MAAM,EAAG,IAAM,EAAE,UAAY,EAAE,SAAS,CAAC,CACzC,IAAI,CAAS,CACjB,CACH,EACA,UAAU,EAAkC,CAC1C,OAAO,EAAM,QAAQ,WAAc,EAAS,EAAG,CAAE,UAAW,EAAM,CAAC,CACrE,EACA,SAAY,EAA6C,CACvD,OAAO,KAAK,4BAA+B,EAAM,MAAM,CAAC,MAAM,EAAG,KAAO,IAAY,EAAG,QAAQ,CAAO,CAAC,CAAC,CAAC,CAC3G,EACA,MAAO,OAAO,eAA+B,CAC3C,MAAM,EAAM,QAAQ,CACtB,CACF,CACF"}
1
+ {"version":3,"file":"indexeddb.js","names":["CORRUPT","ENTRY_STATUSES","value","seen","valid","item","isPlainObject","PostmasterError","id","name","key","status","version","payload","attempts","availableAt","createdAt","updatedAt","failure","leaseExpiresAt","ownerId","record","fn","cause","operation","reported","reason","issue","signature","schema","table","vault","createIndexedDB","options","entries","vaultTx","queued","running","deadLetter","entry","candidates","now","a","b","normalize","next","wake","filter","listener"],"sources":["../src/indexeddb.ts"],"sourcesContent":["import { isPlainObject } from '@vielzeug/arsenal';\nimport { table } from '@vielzeug/vault';\nimport { createIndexedDB } from '@vielzeug/vault/indexeddb';\nimport { normalize } from './_store-utils.ts';\nimport { PostmasterError } from './errors.ts';\nimport type {\n EntryFilter,\n EntryStatus,\n JsonValue,\n PostmasterStats,\n PostmasterStore,\n StoredFailure,\n StoredJob,\n StoreTx,\n} from './types.ts';\n\nconst CORRUPT = Symbol('corrupt');\n\ntype CorruptRecord = {\n readonly [CORRUPT]: CorruptStoredJob;\n readonly availableAt?: number;\n readonly id: string;\n readonly leaseExpiresAt?: number;\n readonly status?: EntryStatus;\n};\n\ntype DatabaseJob = CorruptRecord | StoredJob;\n\ntype PostmasterSchema = {\n jobs: ReturnType<typeof table<DatabaseJob, 'id'>>;\n};\n\nexport interface CorruptStoredJob {\n readonly id?: string;\n readonly reason: string;\n}\n\ntype IndexedDbPostmasterStoreOptions = {\n readonly name: string;\n readonly onCorruptRecord?: (record: CorruptStoredJob) => void;\n};\n\nconst ENTRY_STATUSES: readonly EntryStatus[] = ['dead-letter', 'queued', 'running'];\n\nfunction isEntryStatus(value: unknown): value is EntryStatus {\n return typeof value === 'string' && ENTRY_STATUSES.includes(value as EntryStatus);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && (value as number) >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0;\n}\n\nfunction isJsonValue(value: unknown, seen = new Set<object>()): value is JsonValue {\n if (value === null || typeof value === 'boolean' || typeof value === 'string') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || seen.has(value)) return false;\n\n seen.add(value);\n const valid = Array.isArray(value)\n ? value.every((item) => isJsonValue(item, seen))\n : isPlainObject(value) && Object.values(value).every((item) => isJsonValue(item, seen));\n seen.delete(value);\n return valid;\n}\n\nfunction isStoredFailure(value: unknown): value is StoredFailure {\n return (\n isPlainObject(value) &&\n typeof value.message === 'string' &&\n isNonEmptyString(value.name) &&\n isTimestamp(value.occurredAt)\n );\n}\n\n/**\n * Validates that persisted data conforms to the {@link StoredJob} shape before\n * it re-enters Postmaster's in-memory world. Replaces the prior no-op cast and\n * enforces Vault's required-codec boundary on durable records.\n */\nfunction parseStoredJob(value: unknown): StoredJob {\n if (!isPlainObject(value)) {\n throw new PostmasterError('invalid stored job: expected a plain object');\n }\n\n const {\n id,\n name,\n key,\n status,\n version,\n payload,\n attempts,\n availableAt,\n createdAt,\n updatedAt,\n failure,\n leaseExpiresAt,\n ownerId,\n } = value;\n\n if (!isNonEmptyString(id)) throw new PostmasterError('invalid stored job: id must be a non-empty string');\n if (!isNonEmptyString(name)) throw new PostmasterError('invalid stored job: name must be a non-empty string');\n if (!isNonEmptyString(key)) throw new PostmasterError('invalid stored job: key must be a non-empty string');\n if (!isEntryStatus(status)) {\n throw new PostmasterError('invalid stored job: status must be one of dead-letter, queued, running');\n }\n if (!isNonNegativeInteger(version) || version < 1) {\n throw new PostmasterError('invalid stored job: version must be a positive integer');\n }\n if (!isJsonValue(payload)) throw new PostmasterError('invalid stored job: payload must be a JSON value');\n if (!isNonNegativeInteger(attempts)) {\n throw new PostmasterError('invalid stored job: attempts must be a non-negative integer');\n }\n if (!isTimestamp(availableAt)) throw new PostmasterError('invalid stored job: availableAt must be a timestamp');\n if (!isTimestamp(createdAt)) throw new PostmasterError('invalid stored job: createdAt must be a timestamp');\n if (!isTimestamp(updatedAt)) throw new PostmasterError('invalid stored job: updatedAt must be a timestamp');\n if (failure !== undefined && !isStoredFailure(failure)) {\n throw new PostmasterError('invalid stored job: failure must be a StoredFailure');\n }\n\n if (status === 'running') {\n if (attempts < 1) throw new PostmasterError('invalid stored job: running jobs must have an attempt');\n if (!isTimestamp(leaseExpiresAt)) {\n throw new PostmasterError('invalid stored job: running jobs must have a lease expiry');\n }\n if (!isNonEmptyString(ownerId)) {\n throw new PostmasterError('invalid stored job: running jobs must have an owner');\n }\n if (failure !== undefined) throw new PostmasterError('invalid stored job: running jobs must not have a failure');\n } else if (leaseExpiresAt !== undefined || ownerId !== undefined) {\n throw new PostmasterError('invalid stored job: only running jobs may have lease ownership');\n }\n\n return {\n attempts,\n availableAt,\n createdAt,\n id,\n key,\n name,\n payload,\n status,\n updatedAt,\n version,\n ...(failure !== undefined ? { failure } : {}),\n ...(leaseExpiresAt !== undefined ? { leaseExpiresAt } : {}),\n ...(ownerId !== undefined ? { ownerId } : {}),\n };\n}\n\nfunction isValidRecord(record: DatabaseJob): record is StoredJob {\n return !(CORRUPT in record);\n}\n\nfunction wrap<T>(operation: string, fn: () => Promise<T>): Promise<T> {\n return fn().catch((cause: unknown) => {\n if (cause instanceof PostmasterError) throw cause;\n throw new PostmasterError(`${operation} failed`, { cause });\n });\n}\n\nexport function createIndexedDbPostmasterStore(options: IndexedDbPostmasterStoreOptions): PostmasterStore {\n const reported = new Set<string>();\n const decode = (value: unknown): DatabaseJob => {\n try {\n return parseStoredJob(value);\n } catch (cause) {\n const id = isPlainObject(value) && isNonEmptyString(value.id) ? value.id : undefined;\n const reason = cause instanceof Error ? cause.message : String(cause);\n const issue: CorruptStoredJob = { ...(id === undefined ? {} : { id }), reason };\n const signature = `${id ?? ''}\\u0000${reason}`;\n if (!reported.has(signature)) {\n reported.add(signature);\n try {\n options.onCorruptRecord?.(issue);\n } catch {}\n }\n return {\n [CORRUPT]: issue,\n id: id ?? '',\n ...(isPlainObject(value) && isTimestamp(value.availableAt) ? { availableAt: value.availableAt } : {}),\n ...(isPlainObject(value) && isTimestamp(value.leaseExpiresAt) ? { leaseExpiresAt: value.leaseExpiresAt } : {}),\n ...(isPlainObject(value) && isEntryStatus(value.status) ? { status: value.status } : {}),\n };\n }\n };\n const schema: PostmasterSchema = {\n jobs: table<DatabaseJob, 'id'>('id', {\n indexes: ['availableAt', 'leaseExpiresAt', 'status'],\n }),\n };\n const vault = createIndexedDB({\n codecs: {\n jobs: {\n decode,\n encode: (record) => {\n if (!isValidRecord(record)) throw new PostmasterError('cannot persist a corrupt stored job');\n return parseStoredJob(record);\n },\n },\n },\n name: options.name,\n schema,\n });\n\n const buildTx = (vaultTx: Parameters<Parameters<typeof vault.batch>[1]>[0]): StoreTx => ({\n async countByStatus(): Promise<PostmasterStats> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let queued = 0;\n let running = 0;\n let deadLetter = 0;\n for (const entry of entries) {\n if (entry.status === 'queued') queued += 1;\n else if (entry.status === 'running') running += 1;\n else if (entry.status === 'dead-letter') deadLetter += 1;\n }\n return { deadLetter, queued, running };\n },\n async delete(id: string): Promise<void> {\n await vaultTx.delete('jobs', id);\n },\n async findClaimable(now: number): Promise<StoredJob | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n const candidates = entries.filter(\n (entry) =>\n (entry.status === 'queued' && entry.availableAt <= now) ||\n (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) <= now),\n );\n candidates.sort((a, b) => a.availableAt - b.availableAt || a.createdAt - b.createdAt);\n return candidates[0] ? normalize(candidates[0]) : undefined;\n },\n async findNextWake(now: number): Promise<number | undefined> {\n const entries = (await vaultTx.getAll('jobs')).filter(isValidRecord);\n let next: number | undefined;\n for (const entry of entries) {\n let wake: number | undefined;\n if (entry.status === 'queued' && entry.availableAt > now) wake = entry.availableAt;\n else if (entry.status === 'running' && (entry.leaseExpiresAt ?? 0) > now) wake = entry.leaseExpiresAt;\n if (wake !== undefined && (next === undefined || wake < next)) next = wake;\n }\n return next;\n },\n async get(id: string): Promise<StoredJob | undefined> {\n const entry = await vaultTx.get('jobs', id);\n return entry && isValidRecord(entry) ? normalize(entry) : undefined;\n },\n async put(entry: StoredJob): Promise<void> {\n await vaultTx.put('jobs', normalize(entry));\n },\n });\n\n return {\n get disposalSignal() {\n return vault.disposalSignal;\n },\n dispose(): Promise<void> {\n return wrap('disposing IndexedDB store', () => vault.dispose());\n },\n get disposed() {\n return vault.disposed;\n },\n list(filter?: EntryFilter): Promise<StoredJob[]> {\n return wrap('listing jobs', async () => {\n const entries =\n filter?.status === undefined\n ? await vault.getAll('jobs')\n : await vault.getAllByIndex('jobs', 'status', filter.status);\n return entries\n .filter(isValidRecord)\n .sort((a, b) => a.createdAt - b.createdAt)\n .map(normalize);\n });\n },\n subscribe(listener: () => void): () => void {\n return vault.observe('jobs', () => listener(), { immediate: false });\n },\n transact<T>(fn: (tx: StoreTx) => Promise<T>): Promise<T> {\n return wrap('executing transaction', () => vault.batch(['jobs'], async (vaultTx) => fn(buildTx(vaultTx))));\n },\n async [Symbol.asyncDispose](): Promise<void> {\n await vault.dispose();\n },\n };\n}\n\nexport type { IndexedDbPostmasterStoreOptions };\n"],"mappings":"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"}