@procedures/ics 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +12 -3
- package/dist/.tsbuildinfo +1 -1
- package/dist/days.d.ts +11 -0
- package/dist/days.d.ts.map +1 -1
- package/dist/days.js +27 -0
- package/dist/days.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/procedures.d.ts +14 -2
- package/dist/procedures.d.ts.map +1 -1
- package/dist/procedures.js +21 -4
- package/dist/procedures.js.map +1 -1
- package/package.json +2 -2
- package/src/days.ts +28 -0
- package/src/index.ts +1 -1
- package/src/procedures.ts +34 -5
package/dist/days.d.ts
CHANGED
|
@@ -15,6 +15,17 @@ export declare function dateTime(date: string, label: string): number;
|
|
|
15
15
|
* - A date that is not valid, or a result outside the years 0000 to 9999, throws a `RangeError`.
|
|
16
16
|
*/
|
|
17
17
|
export declare function shiftDay(date: string, days: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* This function gives the date `months` months after a date (`YYYY-MM-DD`). A negative number gives
|
|
20
|
+
* an earlier date. The number of months must be an integer.
|
|
21
|
+
*
|
|
22
|
+
* - When the day is not in the month of the result, the result is the last day of that month: one
|
|
23
|
+
* month after `2026-01-31` is `2026-02-28`.
|
|
24
|
+
* - For the arithmetic of `Date.UTC`, where the 31st goes into the next month, add the days to the
|
|
25
|
+
* 1st: `shiftDay(shiftMonth("2026-01-01", 1), 30)` is `2026-03-03`.
|
|
26
|
+
* - A date that is not valid, or a result outside the years 0000 to 9999, throws a `RangeError`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function shiftMonth(date: string, months: number): string;
|
|
18
29
|
/**
|
|
19
30
|
* This function gives the number of whole days from the date `from` to the date `to`
|
|
20
31
|
* (`YYYY-MM-DD`). It is negative when `to` is before `from`, and 0 for the same date.
|
package/dist/days.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"days.d.ts","sourceRoot":"","sources":["../src/days.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO5D;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wGAAwG;AACxG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;CAAO,GAAG,MAAM,CAG1I"}
|
|
1
|
+
{"version":3,"file":"days.d.ts","sourceRoot":"","sources":["../src/days.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO5D;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAQD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wGAAwG;AACxG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;CAAO,GAAG,MAAM,CAG1I"}
|
package/dist/days.js
CHANGED
|
@@ -33,6 +33,33 @@ export function shiftDay(date, days) {
|
|
|
33
33
|
throw new RangeError(`shiftDay: ${date} plus ${String(days)} days is not from the year 0000 to 9999`);
|
|
34
34
|
return text.slice(0, 10);
|
|
35
35
|
}
|
|
36
|
+
/** This function tells if a year has a 29th of February, in the Gregorian calendar (the year 0000 has one). */
|
|
37
|
+
const isLeapYear = (year) => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
38
|
+
/** The number of days of each month of a year that is not a leap year. */
|
|
39
|
+
const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
40
|
+
/**
|
|
41
|
+
* This function gives the date `months` months after a date (`YYYY-MM-DD`). A negative number gives
|
|
42
|
+
* an earlier date. The number of months must be an integer.
|
|
43
|
+
*
|
|
44
|
+
* - When the day is not in the month of the result, the result is the last day of that month: one
|
|
45
|
+
* month after `2026-01-31` is `2026-02-28`.
|
|
46
|
+
* - For the arithmetic of `Date.UTC`, where the 31st goes into the next month, add the days to the
|
|
47
|
+
* 1st: `shiftDay(shiftMonth("2026-01-01", 1), 30)` is `2026-03-03`.
|
|
48
|
+
* - A date that is not valid, or a result outside the years 0000 to 9999, throws a `RangeError`.
|
|
49
|
+
*/
|
|
50
|
+
export function shiftMonth(date, months) {
|
|
51
|
+
if (!Number.isSafeInteger(months))
|
|
52
|
+
throw new RangeError(`shiftMonth: the number of months ${String(months)} is not an integer`);
|
|
53
|
+
dateTime(date, "shiftMonth");
|
|
54
|
+
const total = Number(date.slice(0, 4)) * 12 + Number(date.slice(5, 7)) - 1 + months;
|
|
55
|
+
const year = Math.floor(total / 12);
|
|
56
|
+
if (!(year >= 0 && year <= 9999))
|
|
57
|
+
throw new RangeError(`shiftMonth: ${date} plus ${String(months)} months is not from the year 0000 to 9999`);
|
|
58
|
+
const month = total - year * 12;
|
|
59
|
+
const last = month === 1 && isLeapYear(year) ? 29 : MONTH_DAYS[month];
|
|
60
|
+
const day = Math.min(Number(date.slice(8, 10)), last);
|
|
61
|
+
return `${String(year).padStart(4, "0")}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
62
|
+
}
|
|
36
63
|
/**
|
|
37
64
|
* This function gives the number of whole days from the date `from` to the date `to`
|
|
38
65
|
* (`YYYY-MM-DD`). It is negative when `to` is before `from`, and 0 for the same date.
|
package/dist/days.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"days.js","sourceRoot":"","sources":["../src/days.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,GAAG,GAAG,UAAU,CAAC;AAEvB,0BAA0B;AAC1B,MAAM,IAAI,GAAG,qBAAqB,CAAC;AAEnC;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAa;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAC5E,gGAAgG;IAChG,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7E,MAAM,IAAI,UAAU,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACjG,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAY;IACjD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,gCAAgC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACxH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,GAAG,CAAC;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,aAAa,IAAI,SAAS,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACjI,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,EAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,GAAG,GAAG,CAAC;AAC7E,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAO,GAA+E,EAAE;IAChI,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IACrD,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAChI,CAAC"}
|
|
1
|
+
{"version":3,"file":"days.js","sourceRoot":"","sources":["../src/days.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ export * from "./procedures.js";
|
|
|
3
3
|
export * from "./ics.js";
|
|
4
4
|
export * from "./write.js";
|
|
5
5
|
export { localDate, localTime, zonedOffset } from "./zone.js";
|
|
6
|
-
export { daysBetween, shiftDay, weekdayName, weekdayOf } from "./days.js";
|
|
6
|
+
export { daysBetween, shiftDay, shiftMonth, weekdayName, weekdayOf } from "./days.js";
|
|
7
7
|
export * from "./types.js";
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAE3B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtF,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,6 @@ export * from "./ics.js";
|
|
|
5
5
|
export * from "./write.js";
|
|
6
6
|
// The calendar days: the date of an instant in a zone, and the arithmetic of dates
|
|
7
7
|
export { localDate, localTime, zonedOffset } from "./zone.js";
|
|
8
|
-
export { daysBetween, shiftDay, weekdayName, weekdayOf } from "./days.js";
|
|
8
|
+
export { daysBetween, shiftDay, shiftMonth, weekdayName, weekdayOf } from "./days.js";
|
|
9
9
|
export * from "./types.js";
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,mFAAmF;AACnF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,mFAAmF;AACnF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtF,cAAc,YAAY,CAAC"}
|
package/dist/procedures.d.ts
CHANGED
|
@@ -5,11 +5,23 @@ import { type AnyProcedure } from "@procedures/client";
|
|
|
5
5
|
export declare const icsParseProcedure: AnyProcedure;
|
|
6
6
|
export declare const icsOccurrencesProcedure: AnyProcedure;
|
|
7
7
|
export declare const icsWriteProcedure: AnyProcedure;
|
|
8
|
+
/** The part of `fetch` that `fetchCalendar` uses. A test or a host gives its own with the option `fetch`. */
|
|
9
|
+
export type FetchText = (url: string, init: {
|
|
10
|
+
headers: Record<string, string>;
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
ok: boolean;
|
|
14
|
+
status: number;
|
|
15
|
+
text(): Promise<string>;
|
|
16
|
+
}>;
|
|
8
17
|
/**
|
|
9
18
|
* This function gets the text of a calendar feed. The address of a private feed is a secret, so
|
|
10
|
-
* an error never includes it.
|
|
19
|
+
* an error never includes it. An error of the request includes its system error code. The option
|
|
20
|
+
* `fetch` replaces the global `fetch`.
|
|
11
21
|
*/
|
|
12
|
-
export declare function fetchCalendar(url: string, timeoutMs: number, signal?: AbortSignal
|
|
22
|
+
export declare function fetchCalendar(url: string, timeoutMs: number, signal?: AbortSignal, options?: {
|
|
23
|
+
readonly fetch?: FetchText | undefined;
|
|
24
|
+
}): Promise<string>;
|
|
13
25
|
export declare const icsFetchProcedure: AnyProcedure;
|
|
14
26
|
export declare const icsProcedures: AnyProcedure[];
|
|
15
27
|
//# sourceMappingURL=procedures.d.ts.map
|
package/dist/procedures.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA+B,KAAK,YAAY,EAAyB,MAAM,oBAAoB,CAAC;AA+C3G,eAAO,MAAM,iBAAiB,EAAE,YAUN,CAAC;AAiB3B,eAAO,MAAM,uBAAuB,EAAE,YAcZ,CAAC;AAM3B,eAAO,MAAM,iBAAiB,EAAE,YAUN,CAAC;AAY3B
|
|
1
|
+
{"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAA+B,KAAK,YAAY,EAAyB,MAAM,oBAAoB,CAAC;AA+C3G,eAAO,MAAM,iBAAiB,EAAE,YAUN,CAAC;AAiB3B,eAAO,MAAM,uBAAuB,EAAE,YAcZ,CAAC;AAM3B,eAAO,MAAM,iBAAiB,EAAE,YAUN,CAAC;AAY3B,6GAA6G;AAC7G,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KAC3D,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAAO,GACvD,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED,eAAO,MAAM,iBAAiB,EAAE,YAaN,CAAC;AAE3B,eAAO,MAAM,aAAa,EAAE,YAAY,EAAuF,CAAC"}
|
package/dist/procedures.js
CHANGED
|
@@ -91,18 +91,35 @@ const FetchInputSchema = z.object({
|
|
|
91
91
|
url: z.url().describe("The address of the calendar feed. A private feed address is a secret: no error repeats it."),
|
|
92
92
|
timeoutMs: z.number().int().positive().max(120_000).default(20_000).describe("The time limit, in milliseconds"),
|
|
93
93
|
});
|
|
94
|
+
/**
|
|
95
|
+
* The system error code of a failed request (`ECONNREFUSED`, `ENOTFOUND`, `UND_ERR_SOCKET`), or
|
|
96
|
+
* undefined. The `fetch` of Node puts it in the field `cause` of its `TypeError`. The function
|
|
97
|
+
* gives only a code of capital letters, digits and underscores, never a message, because a
|
|
98
|
+
* message can include the secret address.
|
|
99
|
+
*/
|
|
100
|
+
function errorCodeOf(error) {
|
|
101
|
+
for (const each of [error?.cause, error]) {
|
|
102
|
+
const code = each?.code;
|
|
103
|
+
if (typeof code === "string" && /^[A-Z][A-Z0-9_]{1,40}$/.test(code))
|
|
104
|
+
return code;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
94
108
|
/**
|
|
95
109
|
* This function gets the text of a calendar feed. The address of a private feed is a secret, so
|
|
96
|
-
* an error never includes it.
|
|
110
|
+
* an error never includes it. An error of the request includes its system error code. The option
|
|
111
|
+
* `fetch` replaces the global `fetch`.
|
|
97
112
|
*/
|
|
98
|
-
export async function fetchCalendar(url, timeoutMs, signal) {
|
|
113
|
+
export async function fetchCalendar(url, timeoutMs, signal, options = {}) {
|
|
99
114
|
const signals = signal ? [signal, AbortSignal.timeout(timeoutMs)] : [AbortSignal.timeout(timeoutMs)];
|
|
115
|
+
const fetchText = options.fetch ?? fetch;
|
|
100
116
|
let response;
|
|
101
117
|
try {
|
|
102
|
-
response = await
|
|
118
|
+
response = await fetchText(url, { signal: AbortSignal.any(signals), headers: { accept: "text/calendar, */*" } });
|
|
103
119
|
}
|
|
104
120
|
catch (error) {
|
|
105
|
-
const
|
|
121
|
+
const code = errorCodeOf(error);
|
|
122
|
+
const reason = error.name === "TimeoutError" ? `no answer in ${timeoutMs} ms` : `the request failed${code === undefined ? "" : ` (${code})`}`;
|
|
106
123
|
throw new Error(`The calendar feed did not answer: ${reason}`);
|
|
107
124
|
}
|
|
108
125
|
if (!response.ok)
|
package/dist/procedures.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedures.js","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"procedures.js","sourceRoot":"","sources":["../src/procedures.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/ics",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.1",
|
|
5
5
|
"description": "An iCalendar (RFC 5545) reader and writer without dependencies: the events of a calendar, their occurrences in a time window with the recurrences, and a calendar from events.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ics",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"provenance": true
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@procedures/client": "0.
|
|
62
|
+
"@procedures/client": "0.8.1",
|
|
63
63
|
"zod": "^4.6.5"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
package/src/days.ts
CHANGED
|
@@ -36,6 +36,34 @@ export function shiftDay(date: string, days: number): string {
|
|
|
36
36
|
return text.slice(0, 10);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** This function tells if a year has a 29th of February, in the Gregorian calendar (the year 0000 has one). */
|
|
40
|
+
const isLeapYear = (year: number): boolean => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
41
|
+
|
|
42
|
+
/** The number of days of each month of a year that is not a leap year. */
|
|
43
|
+
const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] as const;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* This function gives the date `months` months after a date (`YYYY-MM-DD`). A negative number gives
|
|
47
|
+
* an earlier date. The number of months must be an integer.
|
|
48
|
+
*
|
|
49
|
+
* - When the day is not in the month of the result, the result is the last day of that month: one
|
|
50
|
+
* month after `2026-01-31` is `2026-02-28`.
|
|
51
|
+
* - For the arithmetic of `Date.UTC`, where the 31st goes into the next month, add the days to the
|
|
52
|
+
* 1st: `shiftDay(shiftMonth("2026-01-01", 1), 30)` is `2026-03-03`.
|
|
53
|
+
* - A date that is not valid, or a result outside the years 0000 to 9999, throws a `RangeError`.
|
|
54
|
+
*/
|
|
55
|
+
export function shiftMonth(date: string, months: number): string {
|
|
56
|
+
if (!Number.isSafeInteger(months)) throw new RangeError(`shiftMonth: the number of months ${String(months)} is not an integer`);
|
|
57
|
+
dateTime(date, "shiftMonth");
|
|
58
|
+
const total = Number(date.slice(0, 4)) * 12 + Number(date.slice(5, 7)) - 1 + months;
|
|
59
|
+
const year = Math.floor(total / 12);
|
|
60
|
+
if (!(year >= 0 && year <= 9999)) throw new RangeError(`shiftMonth: ${date} plus ${String(months)} months is not from the year 0000 to 9999`);
|
|
61
|
+
const month = total - year * 12;
|
|
62
|
+
const last = month === 1 && isLeapYear(year) ? 29 : MONTH_DAYS[month]!;
|
|
63
|
+
const day = Math.min(Number(date.slice(8, 10)), last);
|
|
64
|
+
return `${String(year).padStart(4, "0")}-${String(month + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
39
67
|
/**
|
|
40
68
|
* This function gives the number of whole days from the date `from` to the date `to`
|
|
41
69
|
* (`YYYY-MM-DD`). It is negative when `to` is before `from`, and 0 for the same date.
|
package/src/index.ts
CHANGED
|
@@ -5,5 +5,5 @@ export * from "./ics.js";
|
|
|
5
5
|
export * from "./write.js";
|
|
6
6
|
// The calendar days: the date of an instant in a zone, and the arithmetic of dates
|
|
7
7
|
export { localDate, localTime, zonedOffset } from "./zone.js";
|
|
8
|
-
export { daysBetween, shiftDay, weekdayName, weekdayOf } from "./days.js";
|
|
8
|
+
export { daysBetween, shiftDay, shiftMonth, weekdayName, weekdayOf } from "./days.js";
|
|
9
9
|
export * from "./types.js";
|
package/src/procedures.ts
CHANGED
|
@@ -118,17 +118,46 @@ const FetchInputSchema = z.object({
|
|
|
118
118
|
});
|
|
119
119
|
type FetchInput = z.infer<typeof FetchInputSchema>;
|
|
120
120
|
|
|
121
|
+
/** The part of `fetch` that `fetchCalendar` uses. A test or a host gives its own with the option `fetch`. */
|
|
122
|
+
export type FetchText = (
|
|
123
|
+
url: string,
|
|
124
|
+
init: { headers: Record<string, string>; signal: AbortSignal }
|
|
125
|
+
) => Promise<{ ok: boolean; status: number; text(): Promise<string> }>;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The system error code of a failed request (`ECONNREFUSED`, `ENOTFOUND`, `UND_ERR_SOCKET`), or
|
|
129
|
+
* undefined. The `fetch` of Node puts it in the field `cause` of its `TypeError`. The function
|
|
130
|
+
* gives only a code of capital letters, digits and underscores, never a message, because a
|
|
131
|
+
* message can include the secret address.
|
|
132
|
+
*/
|
|
133
|
+
function errorCodeOf(error: unknown): string | undefined {
|
|
134
|
+
for (const each of [(error as { cause?: unknown } | null)?.cause, error]) {
|
|
135
|
+
const code = (each as { code?: unknown } | null | undefined)?.code;
|
|
136
|
+
if (typeof code === "string" && /^[A-Z][A-Z0-9_]{1,40}$/.test(code)) return code;
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
121
141
|
/**
|
|
122
142
|
* This function gets the text of a calendar feed. The address of a private feed is a secret, so
|
|
123
|
-
* an error never includes it.
|
|
143
|
+
* an error never includes it. An error of the request includes its system error code. The option
|
|
144
|
+
* `fetch` replaces the global `fetch`.
|
|
124
145
|
*/
|
|
125
|
-
export async function fetchCalendar(
|
|
146
|
+
export async function fetchCalendar(
|
|
147
|
+
url: string,
|
|
148
|
+
timeoutMs: number,
|
|
149
|
+
signal?: AbortSignal,
|
|
150
|
+
options: { readonly fetch?: FetchText | undefined } = {}
|
|
151
|
+
): Promise<string> {
|
|
126
152
|
const signals = signal ? [signal, AbortSignal.timeout(timeoutMs)] : [AbortSignal.timeout(timeoutMs)];
|
|
127
|
-
|
|
153
|
+
const fetchText: FetchText = options.fetch ?? fetch;
|
|
154
|
+
let response: Awaited<ReturnType<FetchText>>;
|
|
128
155
|
try {
|
|
129
|
-
response = await
|
|
156
|
+
response = await fetchText(url, { signal: AbortSignal.any(signals), headers: { accept: "text/calendar, */*" } });
|
|
130
157
|
} catch (error) {
|
|
131
|
-
const
|
|
158
|
+
const code = errorCodeOf(error);
|
|
159
|
+
const reason =
|
|
160
|
+
(error as { name?: string }).name === "TimeoutError" ? `no answer in ${timeoutMs} ms` : `the request failed${code === undefined ? "" : ` (${code})`}`;
|
|
132
161
|
throw new Error(`The calendar feed did not answer: ${reason}`);
|
|
133
162
|
}
|
|
134
163
|
if (!response.ok) throw new Error(`The calendar feed gave HTTP ${response.status}`);
|