payload 3.70.0 → 3.71.0-internal-debug.cd77e5d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collections/config/types.d.ts +9 -2
- package/dist/collections/config/types.d.ts.map +1 -1
- package/dist/collections/config/types.js.map +1 -1
- package/dist/collections/operations/local/find.d.ts +7 -3
- package/dist/collections/operations/local/find.d.ts.map +1 -1
- package/dist/collections/operations/local/find.js.map +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/config/sanitize.js +6 -8
- package/dist/config/sanitize.js.map +1 -1
- package/dist/config/types.d.ts +7 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/fields/baseFields/timezone/baseField.d.ts +4 -1
- package/dist/fields/baseFields/timezone/baseField.d.ts.map +1 -1
- package/dist/fields/baseFields/timezone/baseField.js +2 -1
- package/dist/fields/baseFields/timezone/baseField.js.map +1 -1
- package/dist/fields/config/client.d.ts.map +1 -1
- package/dist/fields/config/client.js +10 -0
- package/dist/fields/config/client.js.map +1 -1
- package/dist/fields/config/sanitize.d.ts.map +1 -1
- package/dist/fields/config/sanitize.js +14 -1
- package/dist/fields/config/sanitize.js.map +1 -1
- package/dist/fields/config/types.d.ts +33 -2
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/config/types.js.map +1 -1
- package/dist/fields/hooks/afterRead/index.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/index.js +1 -0
- package/dist/fields/hooks/afterRead/index.js.map +1 -1
- package/dist/fields/hooks/afterRead/promise.d.ts +9 -1
- package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/promise.js +15 -2
- package/dist/fields/hooks/afterRead/promise.js.map +1 -1
- package/dist/fields/hooks/afterRead/traverseFields.d.ts +9 -1
- package/dist/fields/hooks/afterRead/traverseFields.d.ts.map +1 -1
- package/dist/fields/hooks/afterRead/traverseFields.js +2 -1
- package/dist/fields/hooks/afterRead/traverseFields.js.map +1 -1
- package/dist/index.bundled.d.ts +108 -23
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/queues/config/types/index.d.ts +8 -10
- package/dist/queues/config/types/index.d.ts.map +1 -1
- package/dist/queues/config/types/index.js.map +1 -1
- package/dist/queues/config/types/taskTypes.d.ts +16 -6
- package/dist/queues/config/types/taskTypes.d.ts.map +1 -1
- package/dist/queues/config/types/taskTypes.js.map +1 -1
- package/dist/queues/config/types/workflowTypes.d.ts +2 -2
- package/dist/queues/config/types/workflowTypes.d.ts.map +1 -1
- package/dist/queues/config/types/workflowTypes.js.map +1 -1
- package/dist/queues/errors/index.d.ts +5 -6
- package/dist/queues/errors/index.d.ts.map +1 -1
- package/dist/queues/errors/index.js +6 -5
- package/dist/queues/errors/index.js.map +1 -1
- package/dist/queues/operations/runJobs/index.d.ts +1 -1
- package/dist/queues/operations/runJobs/index.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/index.js +28 -6
- package/dist/queues/operations/runJobs/index.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js +5 -1
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js +1 -3
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/configToJSONSchema.d.ts.map +1 -1
- package/dist/utilities/configToJSONSchema.js +14 -1
- package/dist/utilities/configToJSONSchema.js.map +1 -1
- package/dist/utilities/isolateObjectProperty.d.ts.map +1 -1
- package/dist/utilities/isolateObjectProperty.js +7 -4
- package/dist/utilities/isolateObjectProperty.js.map +1 -1
- package/dist/utilities/isolateObjectProperty.spec.js +120 -0
- package/dist/utilities/isolateObjectProperty.spec.js.map +1 -0
- package/dist/utilities/optionsAreEqual.d.ts +7 -0
- package/dist/utilities/optionsAreEqual.d.ts.map +1 -0
- package/dist/utilities/optionsAreEqual.js +35 -0
- package/dist/utilities/optionsAreEqual.js.map +1 -0
- package/dist/utilities/optionsAreEqual.spec.js +319 -0
- package/dist/utilities/optionsAreEqual.spec.js.map +1 -0
- package/dist/utilities/validateTimezones.d.ts +20 -0
- package/dist/utilities/validateTimezones.d.ts.map +1 -0
- package/dist/utilities/validateTimezones.js +76 -0
- package/dist/utilities/validateTimezones.js.map +1 -0
- package/dist/utilities/validateTimezones.spec.js +493 -0
- package/dist/utilities/validateTimezones.spec.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { isolateObjectProperty } from './isolateObjectProperty.js';
|
|
3
|
+
describe('isolateObjectProperty', ()=>{
|
|
4
|
+
describe('basic isolation behavior', ()=>{
|
|
5
|
+
it('should isolate specified property from the original object', ()=>{
|
|
6
|
+
const original = {
|
|
7
|
+
a: 1,
|
|
8
|
+
b: 2
|
|
9
|
+
};
|
|
10
|
+
const proxy = isolateObjectProperty(original, 'a');
|
|
11
|
+
proxy.a = 100;
|
|
12
|
+
expect(proxy.a).toBe(100);
|
|
13
|
+
expect(original.a).toBe(1); // Original unchanged
|
|
14
|
+
});
|
|
15
|
+
it('should share non-isolated properties with the original object', ()=>{
|
|
16
|
+
const original = {
|
|
17
|
+
a: 1,
|
|
18
|
+
b: 2
|
|
19
|
+
};
|
|
20
|
+
const proxy = isolateObjectProperty(original, 'a');
|
|
21
|
+
proxy.b = 200;
|
|
22
|
+
expect(proxy.b).toBe(200);
|
|
23
|
+
expect(original.b).toBe(200); // Original also changed
|
|
24
|
+
});
|
|
25
|
+
it('should support isolating multiple properties', ()=>{
|
|
26
|
+
const original = {
|
|
27
|
+
a: 1,
|
|
28
|
+
b: 2,
|
|
29
|
+
c: 3
|
|
30
|
+
};
|
|
31
|
+
const proxy = isolateObjectProperty(original, [
|
|
32
|
+
'a',
|
|
33
|
+
'b'
|
|
34
|
+
]);
|
|
35
|
+
proxy.a = 100;
|
|
36
|
+
proxy.b = 200;
|
|
37
|
+
expect(proxy.a).toBe(100);
|
|
38
|
+
expect(proxy.b).toBe(200);
|
|
39
|
+
expect(original.a).toBe(1);
|
|
40
|
+
expect(original.b).toBe(2);
|
|
41
|
+
});
|
|
42
|
+
it('should support deleting isolated properties', ()=>{
|
|
43
|
+
const original = {
|
|
44
|
+
a: 1,
|
|
45
|
+
b: 2
|
|
46
|
+
};
|
|
47
|
+
const proxy = isolateObjectProperty(original, 'a');
|
|
48
|
+
delete proxy.a;
|
|
49
|
+
expect('a' in proxy).toBe(false);
|
|
50
|
+
expect('a' in original).toBe(true); // Original still has it
|
|
51
|
+
});
|
|
52
|
+
it('should support "in" operator for isolated properties', ()=>{
|
|
53
|
+
const original = {
|
|
54
|
+
a: 1,
|
|
55
|
+
b: 2
|
|
56
|
+
};
|
|
57
|
+
const proxy = isolateObjectProperty(original, 'a');
|
|
58
|
+
expect('a' in proxy).toBe(true);
|
|
59
|
+
expect('b' in proxy).toBe(true);
|
|
60
|
+
delete proxy.a;
|
|
61
|
+
expect('a' in proxy).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('private field access (Node 24+ compatibility)', ()=>{
|
|
65
|
+
/**
|
|
66
|
+
* Class with private fields to test that the proxy correctly handles
|
|
67
|
+
* getters/setters that access private fields (Node 24+ compatibility).
|
|
68
|
+
*/ class ObjectWithPrivateFields {
|
|
69
|
+
#privateValue;
|
|
70
|
+
constructor(value){
|
|
71
|
+
this.#privateValue = value;
|
|
72
|
+
}
|
|
73
|
+
get value() {
|
|
74
|
+
return this.#privateValue;
|
|
75
|
+
}
|
|
76
|
+
set value(newValue) {
|
|
77
|
+
this.#privateValue = newValue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
it('should allow reading properties via getters that access private fields when not isolated', ()=>{
|
|
81
|
+
const original = new ObjectWithPrivateFields('secret');
|
|
82
|
+
expect(original.value).toBe('secret');
|
|
83
|
+
});
|
|
84
|
+
it('should allow reading properties via getters that access private fields', ()=>{
|
|
85
|
+
const original = new ObjectWithPrivateFields('secret');
|
|
86
|
+
const proxy = isolateObjectProperty(original, 'nonExistentKey');
|
|
87
|
+
// This would throw "Cannot read private member" if receiver is wrong
|
|
88
|
+
expect(proxy.value).toBe('secret');
|
|
89
|
+
});
|
|
90
|
+
it('should allow writing properties via setters that access private fields', ()=>{
|
|
91
|
+
const original = new ObjectWithPrivateFields('secret');
|
|
92
|
+
const proxy = isolateObjectProperty(original, 'nonExistentKey');
|
|
93
|
+
// This would throw "Cannot write private member" if receiver is wrong
|
|
94
|
+
proxy.value = 'updated';
|
|
95
|
+
expect(proxy.value).toBe('updated');
|
|
96
|
+
expect(original.value).toBe('updated');
|
|
97
|
+
});
|
|
98
|
+
it('should work with Headers-like objects (simulating Request.headers)', ()=>{
|
|
99
|
+
// Simulate a Request-like object with headers
|
|
100
|
+
class MockRequest {
|
|
101
|
+
#headers;
|
|
102
|
+
constructor(){
|
|
103
|
+
this.#headers = new Headers({
|
|
104
|
+
'content-type': 'application/json'
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
get headers() {
|
|
108
|
+
return this.#headers;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const request = new MockRequest();
|
|
112
|
+
const proxy = isolateObjectProperty(request, 'nonExistentKey');
|
|
113
|
+
// This simulates what happens in createLocalReq when checking req.headers
|
|
114
|
+
expect(proxy.headers).toBeInstanceOf(Headers);
|
|
115
|
+
expect(proxy.headers.get('content-type')).toBe('application/json');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
//# sourceMappingURL=isolateObjectProperty.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/isolateObjectProperty.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { isolateObjectProperty } from './isolateObjectProperty.js'\n\ndescribe('isolateObjectProperty', () => {\n describe('basic isolation behavior', () => {\n it('should isolate specified property from the original object', () => {\n const original = { a: 1, b: 2 }\n const proxy = isolateObjectProperty(original, 'a')\n\n proxy.a = 100\n\n expect(proxy.a).toBe(100)\n expect(original.a).toBe(1) // Original unchanged\n })\n\n it('should share non-isolated properties with the original object', () => {\n const original = { a: 1, b: 2 }\n const proxy = isolateObjectProperty(original, 'a')\n\n proxy.b = 200\n\n expect(proxy.b).toBe(200)\n expect(original.b).toBe(200) // Original also changed\n })\n\n it('should support isolating multiple properties', () => {\n const original = { a: 1, b: 2, c: 3 }\n const proxy = isolateObjectProperty(original, ['a', 'b'])\n\n proxy.a = 100\n proxy.b = 200\n\n expect(proxy.a).toBe(100)\n expect(proxy.b).toBe(200)\n expect(original.a).toBe(1)\n expect(original.b).toBe(2)\n })\n\n it('should support deleting isolated properties', () => {\n const original: Record<string, any> = { a: 1, b: 2 }\n const proxy = isolateObjectProperty(original, 'a')\n\n delete proxy.a\n\n expect('a' in proxy).toBe(false)\n expect('a' in original).toBe(true) // Original still has it\n })\n\n it('should support \"in\" operator for isolated properties', () => {\n const original: Record<string, any> = { a: 1, b: 2 }\n const proxy = isolateObjectProperty(original, 'a')\n\n expect('a' in proxy).toBe(true)\n expect('b' in proxy).toBe(true)\n\n delete proxy.a\n expect('a' in proxy).toBe(false)\n })\n })\n\n describe('private field access (Node 24+ compatibility)', () => {\n /**\n * Class with private fields to test that the proxy correctly handles\n * getters/setters that access private fields (Node 24+ compatibility).\n */\n class ObjectWithPrivateFields {\n #privateValue: string\n\n constructor(value: string) {\n this.#privateValue = value\n }\n\n get value(): string {\n return this.#privateValue\n }\n\n set value(newValue: string) {\n this.#privateValue = newValue\n }\n }\n\n it('should allow reading properties via getters that access private fields when not isolated', () => {\n const original = new ObjectWithPrivateFields('secret')\n\n expect(original.value).toBe('secret')\n })\n\n it('should allow reading properties via getters that access private fields', () => {\n const original = new ObjectWithPrivateFields('secret')\n const proxy = isolateObjectProperty(original, 'nonExistentKey' as keyof typeof original)\n\n // This would throw \"Cannot read private member\" if receiver is wrong\n expect(proxy.value).toBe('secret')\n })\n\n it('should allow writing properties via setters that access private fields', () => {\n const original = new ObjectWithPrivateFields('secret')\n const proxy = isolateObjectProperty(original, 'nonExistentKey' as keyof typeof original)\n\n // This would throw \"Cannot write private member\" if receiver is wrong\n proxy.value = 'updated'\n\n expect(proxy.value).toBe('updated')\n expect(original.value).toBe('updated')\n })\n\n it('should work with Headers-like objects (simulating Request.headers)', () => {\n // Simulate a Request-like object with headers\n class MockRequest {\n #headers: Headers\n\n constructor() {\n this.#headers = new Headers({ 'content-type': 'application/json' })\n }\n\n get headers(): Headers {\n return this.#headers\n }\n }\n\n const request = new MockRequest()\n const proxy = isolateObjectProperty(request, 'nonExistentKey' as keyof typeof request)\n\n // This simulates what happens in createLocalReq when checking req.headers\n expect(proxy.headers).toBeInstanceOf(Headers)\n expect(proxy.headers.get('content-type')).toBe('application/json')\n })\n })\n})\n"],"names":["describe","expect","it","isolateObjectProperty","original","a","b","proxy","toBe","c","ObjectWithPrivateFields","value","newValue","MockRequest","Headers","headers","request","toBeInstanceOf","get"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Option } from '../fields/config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compares two arrays of options by their values.
|
|
4
|
+
* Returns true if both arrays contain the same values (order-independent).
|
|
5
|
+
*/
|
|
6
|
+
export declare const optionsAreEqual: (options1: Option[] | undefined, options2: Option[] | undefined) => boolean;
|
|
7
|
+
//# sourceMappingURL=optionsAreEqual.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optionsAreEqual.d.ts","sourceRoot":"","sources":["../../src/utilities/optionsAreEqual.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAYvD;;;GAGG;AACH,eAAO,MAAM,eAAe,aAChB,MAAM,EAAE,GAAG,SAAS,YACpB,MAAM,EAAE,GAAG,SAAS,KAC7B,OA2BF,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the value from an option-like object or string.
|
|
3
|
+
*/ const getOptionValue = (option)=>{
|
|
4
|
+
if (typeof option === 'string') {
|
|
5
|
+
return option;
|
|
6
|
+
}
|
|
7
|
+
return option.value;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Compares two arrays of options by their values.
|
|
11
|
+
* Returns true if both arrays contain the same values (order-independent).
|
|
12
|
+
*/ export const optionsAreEqual = (options1, options2)=>{
|
|
13
|
+
if (!options1 && !options2) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (!options1 || !options2) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
if (options1.length !== options2.length) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const values1 = new Set(options1.map(getOptionValue));
|
|
23
|
+
const values2 = new Set(options2.map(getOptionValue));
|
|
24
|
+
if (values1.size !== values2.size) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
for (const value of values1){
|
|
28
|
+
if (!values2.has(value)) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=optionsAreEqual.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/optionsAreEqual.ts"],"sourcesContent":["import type { Option } from '../fields/config/types.js'\n\n/**\n * Extracts the value from an option-like object or string.\n */\nconst getOptionValue = (option: Option): string => {\n if (typeof option === 'string') {\n return option\n }\n return option.value\n}\n\n/**\n * Compares two arrays of options by their values.\n * Returns true if both arrays contain the same values (order-independent).\n */\nexport const optionsAreEqual = (\n options1: Option[] | undefined,\n options2: Option[] | undefined,\n): boolean => {\n if (!options1 && !options2) {\n return true\n }\n\n if (!options1 || !options2) {\n return false\n }\n\n if (options1.length !== options2.length) {\n return false\n }\n\n const values1 = new Set(options1.map(getOptionValue))\n const values2 = new Set(options2.map(getOptionValue))\n\n if (values1.size !== values2.size) {\n return false\n }\n\n for (const value of values1) {\n if (!values2.has(value)) {\n return false\n }\n }\n\n return true\n}\n"],"names":["getOptionValue","option","value","optionsAreEqual","options1","options2","length","values1","Set","map","values2","size","has"],"mappings":"AAEA;;CAEC,GACD,MAAMA,iBAAiB,CAACC;IACtB,IAAI,OAAOA,WAAW,UAAU;QAC9B,OAAOA;IACT;IACA,OAAOA,OAAOC,KAAK;AACrB;AAEA;;;CAGC,GACD,OAAO,MAAMC,kBAAkB,CAC7BC,UACAC;IAEA,IAAI,CAACD,YAAY,CAACC,UAAU;QAC1B,OAAO;IACT;IAEA,IAAI,CAACD,YAAY,CAACC,UAAU;QAC1B,OAAO;IACT;IAEA,IAAID,SAASE,MAAM,KAAKD,SAASC,MAAM,EAAE;QACvC,OAAO;IACT;IAEA,MAAMC,UAAU,IAAIC,IAAIJ,SAASK,GAAG,CAACT;IACrC,MAAMU,UAAU,IAAIF,IAAIH,SAASI,GAAG,CAACT;IAErC,IAAIO,QAAQI,IAAI,KAAKD,QAAQC,IAAI,EAAE;QACjC,OAAO;IACT;IAEA,KAAK,MAAMT,SAASK,QAAS;QAC3B,IAAI,CAACG,QAAQE,GAAG,CAACV,QAAQ;YACvB,OAAO;QACT;IACF;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { optionsAreEqual } from './optionsAreEqual.js';
|
|
3
|
+
describe('optionsAreEqual', ()=>{
|
|
4
|
+
describe('with string options', ()=>{
|
|
5
|
+
it('should return true for identical string arrays', ()=>{
|
|
6
|
+
expect(optionsAreEqual([
|
|
7
|
+
'a',
|
|
8
|
+
'b',
|
|
9
|
+
'c'
|
|
10
|
+
], [
|
|
11
|
+
'a',
|
|
12
|
+
'b',
|
|
13
|
+
'c'
|
|
14
|
+
])).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
it('should return true for same values in different order', ()=>{
|
|
17
|
+
expect(optionsAreEqual([
|
|
18
|
+
'a',
|
|
19
|
+
'b',
|
|
20
|
+
'c'
|
|
21
|
+
], [
|
|
22
|
+
'c',
|
|
23
|
+
'a',
|
|
24
|
+
'b'
|
|
25
|
+
])).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should return false for different values', ()=>{
|
|
28
|
+
expect(optionsAreEqual([
|
|
29
|
+
'a',
|
|
30
|
+
'b'
|
|
31
|
+
], [
|
|
32
|
+
'a',
|
|
33
|
+
'c'
|
|
34
|
+
])).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('should return false for different lengths', ()=>{
|
|
37
|
+
expect(optionsAreEqual([
|
|
38
|
+
'a',
|
|
39
|
+
'b'
|
|
40
|
+
], [
|
|
41
|
+
'a',
|
|
42
|
+
'b',
|
|
43
|
+
'c'
|
|
44
|
+
])).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('with object options', ()=>{
|
|
48
|
+
it('should return true for identical object arrays', ()=>{
|
|
49
|
+
const options1 = [
|
|
50
|
+
{
|
|
51
|
+
label: 'Option A',
|
|
52
|
+
value: 'a'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Option B',
|
|
56
|
+
value: 'b'
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
const options2 = [
|
|
60
|
+
{
|
|
61
|
+
label: 'Option A',
|
|
62
|
+
value: 'a'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: 'Option B',
|
|
66
|
+
value: 'b'
|
|
67
|
+
}
|
|
68
|
+
];
|
|
69
|
+
expect(optionsAreEqual(options1, options2)).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
it('should return true for same values with different labels', ()=>{
|
|
72
|
+
const options1 = [
|
|
73
|
+
{
|
|
74
|
+
label: 'First Label',
|
|
75
|
+
value: 'a'
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
label: 'Second Label',
|
|
79
|
+
value: 'b'
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
const options2 = [
|
|
83
|
+
{
|
|
84
|
+
label: 'Different Label A',
|
|
85
|
+
value: 'a'
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: 'Different Label B',
|
|
89
|
+
value: 'b'
|
|
90
|
+
}
|
|
91
|
+
];
|
|
92
|
+
expect(optionsAreEqual(options1, options2)).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
it('should return true for same values in different order', ()=>{
|
|
95
|
+
const options1 = [
|
|
96
|
+
{
|
|
97
|
+
label: 'A',
|
|
98
|
+
value: 'a'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
label: 'B',
|
|
102
|
+
value: 'b'
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
const options2 = [
|
|
106
|
+
{
|
|
107
|
+
label: 'B',
|
|
108
|
+
value: 'b'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: 'A',
|
|
112
|
+
value: 'a'
|
|
113
|
+
}
|
|
114
|
+
];
|
|
115
|
+
expect(optionsAreEqual(options1, options2)).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
it('should return false for different values', ()=>{
|
|
118
|
+
const options1 = [
|
|
119
|
+
{
|
|
120
|
+
label: 'A',
|
|
121
|
+
value: 'a'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
label: 'B',
|
|
125
|
+
value: 'b'
|
|
126
|
+
}
|
|
127
|
+
];
|
|
128
|
+
const options2 = [
|
|
129
|
+
{
|
|
130
|
+
label: 'A',
|
|
131
|
+
value: 'a'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
label: 'C',
|
|
135
|
+
value: 'c'
|
|
136
|
+
}
|
|
137
|
+
];
|
|
138
|
+
expect(optionsAreEqual(options1, options2)).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe('with mixed string and object options', ()=>{
|
|
142
|
+
it('should return true when string and object have same value', ()=>{
|
|
143
|
+
const options1 = [
|
|
144
|
+
'a',
|
|
145
|
+
'b'
|
|
146
|
+
];
|
|
147
|
+
const options2 = [
|
|
148
|
+
{
|
|
149
|
+
label: 'A',
|
|
150
|
+
value: 'a'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
label: 'B',
|
|
154
|
+
value: 'b'
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
expect(optionsAreEqual(options1, options2)).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
it('should return false when values differ', ()=>{
|
|
160
|
+
const options1 = [
|
|
161
|
+
'a',
|
|
162
|
+
'b'
|
|
163
|
+
];
|
|
164
|
+
const options2 = [
|
|
165
|
+
{
|
|
166
|
+
label: 'A',
|
|
167
|
+
value: 'a'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
label: 'C',
|
|
171
|
+
value: 'c'
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
expect(optionsAreEqual(options1, options2)).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
describe('with timezone-like options', ()=>{
|
|
178
|
+
it('should return true for identical timezone options', ()=>{
|
|
179
|
+
const globalTimezones = [
|
|
180
|
+
{
|
|
181
|
+
label: 'New York',
|
|
182
|
+
value: 'America/New_York'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
label: 'Los Angeles',
|
|
186
|
+
value: 'America/Los_Angeles'
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
label: 'London',
|
|
190
|
+
value: 'Europe/London'
|
|
191
|
+
}
|
|
192
|
+
];
|
|
193
|
+
const fieldTimezones = [
|
|
194
|
+
{
|
|
195
|
+
label: 'New York',
|
|
196
|
+
value: 'America/New_York'
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
label: 'Los Angeles',
|
|
200
|
+
value: 'America/Los_Angeles'
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
label: 'London',
|
|
204
|
+
value: 'Europe/London'
|
|
205
|
+
}
|
|
206
|
+
];
|
|
207
|
+
expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
it('should return false for custom offset timezones vs IANA timezones', ()=>{
|
|
210
|
+
const globalTimezones = [
|
|
211
|
+
{
|
|
212
|
+
label: 'New York',
|
|
213
|
+
value: 'America/New_York'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
label: 'Los Angeles',
|
|
217
|
+
value: 'America/Los_Angeles'
|
|
218
|
+
}
|
|
219
|
+
];
|
|
220
|
+
const fieldTimezones = [
|
|
221
|
+
{
|
|
222
|
+
label: 'UTC+5:30',
|
|
223
|
+
value: '+05:30'
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
label: 'UTC-8',
|
|
227
|
+
value: '-08:00'
|
|
228
|
+
}
|
|
229
|
+
];
|
|
230
|
+
expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
it('should return false for mixed IANA and offset vs pure IANA', ()=>{
|
|
233
|
+
const globalTimezones = [
|
|
234
|
+
{
|
|
235
|
+
label: 'New York',
|
|
236
|
+
value: 'America/New_York'
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: 'London',
|
|
240
|
+
value: 'Europe/London'
|
|
241
|
+
}
|
|
242
|
+
];
|
|
243
|
+
const fieldTimezones = [
|
|
244
|
+
{
|
|
245
|
+
label: 'New York',
|
|
246
|
+
value: 'America/New_York'
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
label: 'UTC+5:30',
|
|
250
|
+
value: '+05:30'
|
|
251
|
+
}
|
|
252
|
+
];
|
|
253
|
+
expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false);
|
|
254
|
+
});
|
|
255
|
+
it('should return false for subset of global timezones', ()=>{
|
|
256
|
+
const globalTimezones = [
|
|
257
|
+
{
|
|
258
|
+
label: 'New York',
|
|
259
|
+
value: 'America/New_York'
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
label: 'Los Angeles',
|
|
263
|
+
value: 'America/Los_Angeles'
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
label: 'London',
|
|
267
|
+
value: 'Europe/London'
|
|
268
|
+
}
|
|
269
|
+
];
|
|
270
|
+
const fieldTimezones = [
|
|
271
|
+
{
|
|
272
|
+
label: 'New York',
|
|
273
|
+
value: 'America/New_York'
|
|
274
|
+
}
|
|
275
|
+
];
|
|
276
|
+
expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
describe('edge cases', ()=>{
|
|
280
|
+
it('should return true for both undefined', ()=>{
|
|
281
|
+
expect(optionsAreEqual(undefined, undefined)).toBe(true);
|
|
282
|
+
});
|
|
283
|
+
it('should return false for one undefined', ()=>{
|
|
284
|
+
expect(optionsAreEqual([
|
|
285
|
+
'a'
|
|
286
|
+
], undefined)).toBe(false);
|
|
287
|
+
expect(optionsAreEqual(undefined, [
|
|
288
|
+
'a'
|
|
289
|
+
])).toBe(false);
|
|
290
|
+
});
|
|
291
|
+
it('should return true for both empty arrays', ()=>{
|
|
292
|
+
expect(optionsAreEqual([], [])).toBe(true);
|
|
293
|
+
});
|
|
294
|
+
it('should return false for empty vs non-empty', ()=>{
|
|
295
|
+
expect(optionsAreEqual([], [
|
|
296
|
+
'a'
|
|
297
|
+
])).toBe(false);
|
|
298
|
+
expect(optionsAreEqual([
|
|
299
|
+
'a'
|
|
300
|
+
], [])).toBe(false);
|
|
301
|
+
});
|
|
302
|
+
it('should handle duplicate values in source (uses Set)', ()=>{
|
|
303
|
+
// If there are duplicates, the Set will dedupe them
|
|
304
|
+
// So ['a', 'a', 'b'] becomes Set{'a', 'b'} with size 2
|
|
305
|
+
// and ['a', 'b'] becomes Set{'a', 'b'} with size 2
|
|
306
|
+
// But the arrays have different lengths, so they're not equal
|
|
307
|
+
expect(optionsAreEqual([
|
|
308
|
+
'a',
|
|
309
|
+
'a',
|
|
310
|
+
'b'
|
|
311
|
+
], [
|
|
312
|
+
'a',
|
|
313
|
+
'b'
|
|
314
|
+
])).toBe(false);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
//# sourceMappingURL=optionsAreEqual.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/optionsAreEqual.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { optionsAreEqual } from './optionsAreEqual.js'\n\ndescribe('optionsAreEqual', () => {\n describe('with string options', () => {\n it('should return true for identical string arrays', () => {\n expect(optionsAreEqual(['a', 'b', 'c'], ['a', 'b', 'c'])).toBe(true)\n })\n\n it('should return true for same values in different order', () => {\n expect(optionsAreEqual(['a', 'b', 'c'], ['c', 'a', 'b'])).toBe(true)\n })\n\n it('should return false for different values', () => {\n expect(optionsAreEqual(['a', 'b'], ['a', 'c'])).toBe(false)\n })\n\n it('should return false for different lengths', () => {\n expect(optionsAreEqual(['a', 'b'], ['a', 'b', 'c'])).toBe(false)\n })\n })\n\n describe('with object options', () => {\n it('should return true for identical object arrays', () => {\n const options1 = [\n { label: 'Option A', value: 'a' },\n { label: 'Option B', value: 'b' },\n ]\n const options2 = [\n { label: 'Option A', value: 'a' },\n { label: 'Option B', value: 'b' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(true)\n })\n\n it('should return true for same values with different labels', () => {\n const options1 = [\n { label: 'First Label', value: 'a' },\n { label: 'Second Label', value: 'b' },\n ]\n const options2 = [\n { label: 'Different Label A', value: 'a' },\n { label: 'Different Label B', value: 'b' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(true)\n })\n\n it('should return true for same values in different order', () => {\n const options1 = [\n { label: 'A', value: 'a' },\n { label: 'B', value: 'b' },\n ]\n const options2 = [\n { label: 'B', value: 'b' },\n { label: 'A', value: 'a' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(true)\n })\n\n it('should return false for different values', () => {\n const options1 = [\n { label: 'A', value: 'a' },\n { label: 'B', value: 'b' },\n ]\n const options2 = [\n { label: 'A', value: 'a' },\n { label: 'C', value: 'c' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(false)\n })\n })\n\n describe('with mixed string and object options', () => {\n it('should return true when string and object have same value', () => {\n const options1 = ['a', 'b']\n const options2 = [\n { label: 'A', value: 'a' },\n { label: 'B', value: 'b' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(true)\n })\n\n it('should return false when values differ', () => {\n const options1 = ['a', 'b']\n const options2 = [\n { label: 'A', value: 'a' },\n { label: 'C', value: 'c' },\n ]\n expect(optionsAreEqual(options1, options2)).toBe(false)\n })\n })\n\n describe('with timezone-like options', () => {\n it('should return true for identical timezone options', () => {\n const globalTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'Los Angeles', value: 'America/Los_Angeles' },\n { label: 'London', value: 'Europe/London' },\n ]\n const fieldTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'Los Angeles', value: 'America/Los_Angeles' },\n { label: 'London', value: 'Europe/London' },\n ]\n expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(true)\n })\n\n it('should return false for custom offset timezones vs IANA timezones', () => {\n const globalTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'Los Angeles', value: 'America/Los_Angeles' },\n ]\n const fieldTimezones = [\n { label: 'UTC+5:30', value: '+05:30' },\n { label: 'UTC-8', value: '-08:00' },\n ]\n expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false)\n })\n\n it('should return false for mixed IANA and offset vs pure IANA', () => {\n const globalTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'London', value: 'Europe/London' },\n ]\n const fieldTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'UTC+5:30', value: '+05:30' },\n ]\n expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false)\n })\n\n it('should return false for subset of global timezones', () => {\n const globalTimezones = [\n { label: 'New York', value: 'America/New_York' },\n { label: 'Los Angeles', value: 'America/Los_Angeles' },\n { label: 'London', value: 'Europe/London' },\n ]\n const fieldTimezones = [{ label: 'New York', value: 'America/New_York' }]\n expect(optionsAreEqual(globalTimezones, fieldTimezones)).toBe(false)\n })\n })\n\n describe('edge cases', () => {\n it('should return true for both undefined', () => {\n expect(optionsAreEqual(undefined, undefined)).toBe(true)\n })\n\n it('should return false for one undefined', () => {\n expect(optionsAreEqual(['a'], undefined)).toBe(false)\n expect(optionsAreEqual(undefined, ['a'])).toBe(false)\n })\n\n it('should return true for both empty arrays', () => {\n expect(optionsAreEqual([], [])).toBe(true)\n })\n\n it('should return false for empty vs non-empty', () => {\n expect(optionsAreEqual([], ['a'])).toBe(false)\n expect(optionsAreEqual(['a'], [])).toBe(false)\n })\n\n it('should handle duplicate values in source (uses Set)', () => {\n // If there are duplicates, the Set will dedupe them\n // So ['a', 'a', 'b'] becomes Set{'a', 'b'} with size 2\n // and ['a', 'b'] becomes Set{'a', 'b'} with size 2\n // But the arrays have different lengths, so they're not equal\n expect(optionsAreEqual(['a', 'a', 'b'], ['a', 'b'])).toBe(false)\n })\n })\n})\n"],"names":["describe","expect","it","optionsAreEqual","toBe","options1","label","value","options2","globalTimezones","fieldTimezones","undefined"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Timezone } from '../config/types.js';
|
|
2
|
+
type ValidateTimezonesArgs = {
|
|
3
|
+
/**
|
|
4
|
+
* The source of the timezones for error messaging
|
|
5
|
+
*/
|
|
6
|
+
source?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Array of timezones to validate
|
|
9
|
+
*/
|
|
10
|
+
timezones: Timezone[] | undefined;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Validates that all provided timezones are supported by the current runtime's Intl API.
|
|
14
|
+
* Uses both Intl.DateTimeFormat and Intl.supportedValuesOf for comprehensive validation.
|
|
15
|
+
*
|
|
16
|
+
* @throws InvalidConfiguration if an unsupported timezone is found
|
|
17
|
+
*/
|
|
18
|
+
export declare const validateTimezones: ({ source, timezones }: ValidateTimezonesArgs) => void;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=validateTimezones.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateTimezones.d.ts","sourceRoot":"","sources":["../../src/utilities/validateTimezones.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAIlD,KAAK,qBAAqB,GAAG;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAA;CAClC,CAAA;AAoED;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,0BAA2B,qBAAqB,KAAG,IAahF,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { InvalidConfiguration } from '../errors/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates a UTC offset string.
|
|
4
|
+
* Only supports the ±HH:mm format (e.g., +05:30, -08:00).
|
|
5
|
+
*
|
|
6
|
+
* Valid ranges: hours -12 to +14, minutes 0-59
|
|
7
|
+
*
|
|
8
|
+
* @returns true if the offset is valid
|
|
9
|
+
*/ const isValidUtcOffset = (value)=>{
|
|
10
|
+
// Strict format check: only ±HH:mm
|
|
11
|
+
const match = value.match(/^([+-])(\d{2}):(\d{2})$/);
|
|
12
|
+
if (!match) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const sign = match[1] === '+' ? 1 : -1;
|
|
16
|
+
const hours = parseInt(match[2], 10);
|
|
17
|
+
const minutes = parseInt(match[3], 10);
|
|
18
|
+
// Minutes must be 0-59
|
|
19
|
+
if (minutes > 59) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
// Valid range: -12:00 (-720 min) to +14:00 (+840 min)
|
|
23
|
+
const totalMinutes = sign * (hours * 60 + minutes);
|
|
24
|
+
return totalMinutes >= -720 && totalMinutes <= 840;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a timezone is supported by the current runtime.
|
|
28
|
+
* Supports both IANA timezone names and UTC offset formats.
|
|
29
|
+
*
|
|
30
|
+
* For IANA names: Uses Intl.DateTimeFormat and Intl.supportedValuesOf
|
|
31
|
+
* For UTC offsets: Uses native Date API to validate (±HH:mm format only)
|
|
32
|
+
*/ const isTimezoneSupported = (timezoneValue)=>{
|
|
33
|
+
// UTC is always supported
|
|
34
|
+
if (timezoneValue === 'UTC') {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
// Check if it's a UTC offset format (starts with + or -)
|
|
38
|
+
if (timezoneValue.startsWith('+') || timezoneValue.startsWith('-')) {
|
|
39
|
+
return isValidUtcOffset(timezoneValue);
|
|
40
|
+
}
|
|
41
|
+
// For IANA timezone names, use Intl.DateTimeFormat as primary check
|
|
42
|
+
try {
|
|
43
|
+
new Intl.DateTimeFormat('en-US', {
|
|
44
|
+
timeZone: timezoneValue
|
|
45
|
+
});
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
// DateTimeFormat failed, timezone is not supported
|
|
49
|
+
}
|
|
50
|
+
// Secondary check: verify against supportedValuesOf if available
|
|
51
|
+
if (typeof Intl.supportedValuesOf === 'function') {
|
|
52
|
+
const supportedTimezones = Intl.supportedValuesOf('timeZone');
|
|
53
|
+
if (supportedTimezones.includes(timezoneValue)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Validates that all provided timezones are supported by the current runtime's Intl API.
|
|
61
|
+
* Uses both Intl.DateTimeFormat and Intl.supportedValuesOf for comprehensive validation.
|
|
62
|
+
*
|
|
63
|
+
* @throws InvalidConfiguration if an unsupported timezone is found
|
|
64
|
+
*/ export const validateTimezones = ({ source, timezones })=>{
|
|
65
|
+
if (!timezones?.length) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const timezone of timezones){
|
|
69
|
+
if (!isTimezoneSupported(timezone.value)) {
|
|
70
|
+
const sourceText = source ? ` in ${source}` : '';
|
|
71
|
+
throw new InvalidConfiguration(`Timezone ${timezone.value}${sourceText} is not supported by the current runtime via the Intl API.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=validateTimezones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/validateTimezones.ts"],"sourcesContent":["import type { Timezone } from '../config/types.js'\n\nimport { InvalidConfiguration } from '../errors/index.js'\n\ntype ValidateTimezonesArgs = {\n /**\n * The source of the timezones for error messaging\n */\n source?: string\n /**\n * Array of timezones to validate\n */\n timezones: Timezone[] | undefined\n}\n\n/**\n * Validates a UTC offset string.\n * Only supports the ±HH:mm format (e.g., +05:30, -08:00).\n *\n * Valid ranges: hours -12 to +14, minutes 0-59\n *\n * @returns true if the offset is valid\n */\nconst isValidUtcOffset = (value: string): boolean => {\n // Strict format check: only ±HH:mm\n const match = value.match(/^([+-])(\\d{2}):(\\d{2})$/)\n if (!match) {\n return false\n }\n\n const sign = match[1] === '+' ? 1 : -1\n const hours = parseInt(match[2]!, 10)\n const minutes = parseInt(match[3]!, 10)\n\n // Minutes must be 0-59\n if (minutes > 59) {\n return false\n }\n\n // Valid range: -12:00 (-720 min) to +14:00 (+840 min)\n const totalMinutes = sign * (hours * 60 + minutes)\n return totalMinutes >= -720 && totalMinutes <= 840\n}\n\n/**\n * Checks if a timezone is supported by the current runtime.\n * Supports both IANA timezone names and UTC offset formats.\n *\n * For IANA names: Uses Intl.DateTimeFormat and Intl.supportedValuesOf\n * For UTC offsets: Uses native Date API to validate (±HH:mm format only)\n */\nconst isTimezoneSupported = (timezoneValue: string): boolean => {\n // UTC is always supported\n if (timezoneValue === 'UTC') {\n return true\n }\n\n // Check if it's a UTC offset format (starts with + or -)\n if (timezoneValue.startsWith('+') || timezoneValue.startsWith('-')) {\n return isValidUtcOffset(timezoneValue)\n }\n\n // For IANA timezone names, use Intl.DateTimeFormat as primary check\n try {\n new Intl.DateTimeFormat('en-US', { timeZone: timezoneValue })\n return true\n } catch {\n // DateTimeFormat failed, timezone is not supported\n }\n\n // Secondary check: verify against supportedValuesOf if available\n if (typeof Intl.supportedValuesOf === 'function') {\n const supportedTimezones = Intl.supportedValuesOf('timeZone')\n if (supportedTimezones.includes(timezoneValue)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Validates that all provided timezones are supported by the current runtime's Intl API.\n * Uses both Intl.DateTimeFormat and Intl.supportedValuesOf for comprehensive validation.\n *\n * @throws InvalidConfiguration if an unsupported timezone is found\n */\nexport const validateTimezones = ({ source, timezones }: ValidateTimezonesArgs): void => {\n if (!timezones?.length) {\n return\n }\n\n for (const timezone of timezones) {\n if (!isTimezoneSupported(timezone.value)) {\n const sourceText = source ? ` in ${source}` : ''\n throw new InvalidConfiguration(\n `Timezone ${timezone.value}${sourceText} is not supported by the current runtime via the Intl API.`,\n )\n }\n }\n}\n"],"names":["InvalidConfiguration","isValidUtcOffset","value","match","sign","hours","parseInt","minutes","totalMinutes","isTimezoneSupported","timezoneValue","startsWith","Intl","DateTimeFormat","timeZone","supportedValuesOf","supportedTimezones","includes","validateTimezones","source","timezones","length","timezone","sourceText"],"mappings":"AAEA,SAASA,oBAAoB,QAAQ,qBAAoB;AAazD;;;;;;;CAOC,GACD,MAAMC,mBAAmB,CAACC;IACxB,mCAAmC;IACnC,MAAMC,QAAQD,MAAMC,KAAK,CAAC;IAC1B,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,MAAMC,OAAOD,KAAK,CAAC,EAAE,KAAK,MAAM,IAAI,CAAC;IACrC,MAAME,QAAQC,SAASH,KAAK,CAAC,EAAE,EAAG;IAClC,MAAMI,UAAUD,SAASH,KAAK,CAAC,EAAE,EAAG;IAEpC,uBAAuB;IACvB,IAAII,UAAU,IAAI;QAChB,OAAO;IACT;IAEA,sDAAsD;IACtD,MAAMC,eAAeJ,OAAQC,CAAAA,QAAQ,KAAKE,OAAM;IAChD,OAAOC,gBAAgB,CAAC,OAAOA,gBAAgB;AACjD;AAEA;;;;;;CAMC,GACD,MAAMC,sBAAsB,CAACC;IAC3B,0BAA0B;IAC1B,IAAIA,kBAAkB,OAAO;QAC3B,OAAO;IACT;IAEA,yDAAyD;IACzD,IAAIA,cAAcC,UAAU,CAAC,QAAQD,cAAcC,UAAU,CAAC,MAAM;QAClE,OAAOV,iBAAiBS;IAC1B;IAEA,oEAAoE;IACpE,IAAI;QACF,IAAIE,KAAKC,cAAc,CAAC,SAAS;YAAEC,UAAUJ;QAAc;QAC3D,OAAO;IACT,EAAE,OAAM;IACN,mDAAmD;IACrD;IAEA,iEAAiE;IACjE,IAAI,OAAOE,KAAKG,iBAAiB,KAAK,YAAY;QAChD,MAAMC,qBAAqBJ,KAAKG,iBAAiB,CAAC;QAClD,IAAIC,mBAAmBC,QAAQ,CAACP,gBAAgB;YAC9C,OAAO;QACT;IACF;IAEA,OAAO;AACT;AAEA;;;;;CAKC,GACD,OAAO,MAAMQ,oBAAoB,CAAC,EAAEC,MAAM,EAAEC,SAAS,EAAyB;IAC5E,IAAI,CAACA,WAAWC,QAAQ;QACtB;IACF;IAEA,KAAK,MAAMC,YAAYF,UAAW;QAChC,IAAI,CAACX,oBAAoBa,SAASpB,KAAK,GAAG;YACxC,MAAMqB,aAAaJ,SAAS,CAAC,IAAI,EAAEA,QAAQ,GAAG;YAC9C,MAAM,IAAInB,qBACR,CAAC,SAAS,EAAEsB,SAASpB,KAAK,GAAGqB,WAAW,0DAA0D,CAAC;QAEvG;IACF;AACF,EAAC"}
|