@machinemetrics/mm-erp-sdk 0.1.8-beta.2 → 0.1.8-beta.4

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.
Files changed (27) hide show
  1. package/dist/{config-152LkbTv.js → config-qat9zgOl.js} +2 -2
  2. package/dist/{config-152LkbTv.js.map → config-qat9zgOl.js.map} +1 -1
  3. package/dist/{connector-factory-wivcyMhC.js → connector-factory-C2czCs9v.js} +2 -2
  4. package/dist/{connector-factory-wivcyMhC.js.map → connector-factory-C2czCs9v.js.map} +1 -1
  5. package/dist/{hashed-cache-manager-BnviJzB7.js → hashed-cache-manager-CzyFSt2B.js} +4 -4
  6. package/dist/{hashed-cache-manager-BnviJzB7.js.map → hashed-cache-manager-CzyFSt2B.js.map} +1 -1
  7. package/dist/{index-DNqHWa8F.js → index-B9wo8pld.js} +2 -2
  8. package/dist/{index-DNqHWa8F.js.map → index-B9wo8pld.js.map} +1 -1
  9. package/dist/{logger-HAWySEbs.js → logger-Db8CkwR6.js} +11 -83
  10. package/dist/{logger-HAWySEbs.js.map → logger-Db8CkwR6.js.map} +1 -1
  11. package/dist/mm-erp-sdk.js +24 -7
  12. package/dist/mm-erp-sdk.js.map +1 -1
  13. package/dist/services/data-sync-service/jobs/clean-up-expired-cache.js +4 -4
  14. package/dist/services/data-sync-service/jobs/from-erp.js +4 -4
  15. package/dist/services/data-sync-service/jobs/retry-failed-labor-tickets.js +3 -3
  16. package/dist/services/data-sync-service/jobs/run-migrations.js +1 -1
  17. package/dist/services/data-sync-service/jobs/to-erp.js +3 -3
  18. package/dist/services/reporting-service/logger.d.ts.map +1 -1
  19. package/dist/utils/index.d.ts +1 -1
  20. package/dist/utils/index.d.ts.map +1 -1
  21. package/dist/utils/timezone.d.ts +7 -0
  22. package/dist/utils/timezone.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/services/reporting-service/logger.ts +11 -94
  25. package/src/utils/index.ts +1 -1
  26. package/src/utils/mm-labor-ticket-helpers.ts +2 -2
  27. package/src/utils/timezone.ts +28 -0
@@ -1,7 +1,7 @@
1
- import "../../../config-152LkbTv.js";
2
- import { H as HashedCacheManager } from "../../../hashed-cache-manager-BnviJzB7.js";
3
- import { S as SQLiteCoordinator } from "../../../index-DNqHWa8F.js";
4
- import { l as logger } from "../../../logger-HAWySEbs.js";
1
+ import "../../../config-qat9zgOl.js";
2
+ import { H as HashedCacheManager } from "../../../hashed-cache-manager-CzyFSt2B.js";
3
+ import { S as SQLiteCoordinator } from "../../../index-B9wo8pld.js";
4
+ import { l as logger } from "../../../logger-Db8CkwR6.js";
5
5
  logger.level = process.env.LOG_LEVEL || "info";
6
6
  const main = async () => {
7
7
  const cacheManager = new HashedCacheManager();
@@ -1,7 +1,7 @@
1
- import "../../../config-152LkbTv.js";
2
- import { l as logger } from "../../../logger-HAWySEbs.js";
3
- import { S as SQLiteCoordinator } from "../../../index-DNqHWa8F.js";
4
- import { c as createConnectorFromPath } from "../../../connector-factory-wivcyMhC.js";
1
+ import "../../../config-qat9zgOl.js";
2
+ import { l as logger } from "../../../logger-Db8CkwR6.js";
3
+ import { S as SQLiteCoordinator } from "../../../index-B9wo8pld.js";
4
+ import { c as createConnectorFromPath } from "../../../connector-factory-C2czCs9v.js";
5
5
  logger.level = process.env.LOG_LEVEL || "info";
6
6
  const main = async () => {
7
7
  try {
@@ -1,6 +1,6 @@
1
- import "../../../config-152LkbTv.js";
2
- import { l as logger } from "../../../logger-HAWySEbs.js";
3
- import { c as createConnectorFromPath } from "../../../connector-factory-wivcyMhC.js";
1
+ import "../../../config-qat9zgOl.js";
2
+ import { l as logger } from "../../../logger-Db8CkwR6.js";
3
+ import { c as createConnectorFromPath } from "../../../connector-factory-C2czCs9v.js";
4
4
  logger.level = process.env.LOG_LEVEL || "info";
5
5
  const main = async () => {
6
6
  try {
@@ -1,5 +1,5 @@
1
1
  import knex from "knex";
2
- import { l as logger } from "../../../logger-HAWySEbs.js";
2
+ import { l as logger } from "../../../logger-Db8CkwR6.js";
3
3
  import { c as config } from "../../../knexfile-1qKKIORB.js";
4
4
  logger.level = process.env.LOG_LEVEL || "info";
5
5
  const db = knex(config.local);
@@ -1,6 +1,6 @@
1
- import "../../../config-152LkbTv.js";
2
- import { l as logger } from "../../../logger-HAWySEbs.js";
3
- import { c as createConnectorFromPath } from "../../../connector-factory-wivcyMhC.js";
1
+ import "../../../config-qat9zgOl.js";
2
+ import { l as logger } from "../../../logger-Db8CkwR6.js";
3
+ import { c as createConnectorFromPath } from "../../../connector-factory-C2czCs9v.js";
4
4
  logger.level = process.env.LOG_LEVEL || "info";
5
5
  const main = async () => {
6
6
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/services/reporting-service/logger.ts"],"names":[],"mappings":"AA+DA,QAAA,MAAM,MAAM,0BAaV,CAAC;AA+EH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,SAuChE,CAAC;AAKF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/services/reporting-service/logger.ts"],"names":[],"mappings":"AA+DA,QAAA,MAAM,MAAM,0BAaV,CAAC;AAGH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,SAgChE,CAAC;AAKF,eAAe,MAAM,CAAC"}
@@ -11,7 +11,7 @@ export { addNewFieldFromExternalSource, addNewFieldFromLookupField, } from "./da
11
11
  * Timezone and time-related utilities
12
12
  */
13
13
  export { getTimezoneOffsetAndPersist } from "./time-utils";
14
- export { formatDateWithTZOffset, convertToLocalTime } from "./timezone";
14
+ export { formatDateWithTZOffset, convertToLocalTime, toISOWithOffset } from "./timezone";
15
15
  export { applyTimezoneOffsetsToFields } from "./time-utils";
16
16
  export * from "./time-utils";
17
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAC5D,cAAc,cAAc,CAAC;AAE7B;;GAEG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAC5F,YAAY,EAAE,oBAAoB,EAAE,MAAM,qDAAqD,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAEpF;;GAEG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAG9E,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,qCAAqC,CAAC;AAE7C;;GAEG;AACH,cAAc,oDAAoD,CAAC;AACnE,cAAc,oDAAoD,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEjF;;GAEG;AACH,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D;;GAEG;AACH,cAAc,2BAA2B,CAAC;AAE1C;;GAEG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE;;GAEG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAC5D,cAAc,cAAc,CAAC;AAE7B;;GAEG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAC5F,YAAY,EAAE,oBAAoB,EAAE,MAAM,qDAAqD,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAEpF;;GAEG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,YAAY,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAG9E,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,qCAAqC,CAAC;AAE7C;;GAEG;AACH,cAAc,oDAAoD,CAAC;AACnE,cAAc,oDAAoD,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEjF;;GAEG;AACH,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D;;GAEG;AACH,cAAc,2BAA2B,CAAC;AAE1C;;GAEG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sDAAsD,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE;;GAEG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -18,4 +18,11 @@ export declare const convertToLocalTime: (zuluTime: string | Date | null | undef
18
18
  * @returns The formatted date string in format: YYYY-MM-DDTHH:mm:ss+/-HH:MM
19
19
  */
20
20
  export declare const formatDateWithTZOffset: (date: string | null | undefined, timezoneOffset: number) => string | undefined;
21
+ /**
22
+ * Formats a Date object as an ISO string with the specified timezone offset
23
+ * @param date The Date object to format (should be a Date that has been shifted by convertToLocalTime)
24
+ * @param timezoneOffset The timezone offset in hours
25
+ * @returns ISO string with offset in format: YYYY-MM-DDTHH:mm:ss.SSS±HH:MM
26
+ */
27
+ export declare const toISOWithOffset: (date: Date, timezoneOffset: number) => string;
21
28
  //# sourceMappingURL=timezone.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../src/utils/timezone.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,MAAM,CA6CxD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,EAC1C,gBAAgB,MAAM,KACrB,IAAI,GAAG,SAIT,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,gBAAgB,MAAM,KACrB,MAAM,GAAG,SAgBX,CAAC"}
1
+ {"version":3,"file":"timezone.d.ts","sourceRoot":"","sources":["../../src/utils/timezone.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,MAAM,CA6CxD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,EAC1C,gBAAgB,MAAM,KACrB,IAAI,GAAG,SAIT,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAC/B,gBAAgB,MAAM,KACrB,MAAM,GAAG,SAgBX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,IAAI,EAAE,gBAAgB,MAAM,KAAG,MAoBpE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@machinemetrics/mm-erp-sdk",
3
3
  "description": "A library for syncing data between MachineMetrics and ERP systems",
4
- "version": "0.1.8-beta.2",
4
+ "version": " 0.1.8-beta.4",
5
5
  "license": "MIT",
6
6
  "author": "machinemetrics",
7
7
  "main": "dist/mm-erp-sdk.js",
@@ -76,105 +76,22 @@ const logger = createLogger({
76
76
  ],
77
77
  });
78
78
 
79
- // Helper function to create a file transport with shared configuration
80
- const createFileTransport = (): DailyRotateFile => {
81
- return new DailyRotateFile({
82
- filename: path.join(logDirectory, "%DATE%.log"),
83
- datePattern: "YYYY-MM-DD",
84
- zippedArchive: true,
85
- maxSize: "20m",
86
- maxFiles: "14d",
87
- format: logFormat,
88
- });
89
- };
90
-
91
- // Rotate mitigation helper: attaches rotate handler to transport and recursively attaches to replacements
92
- function attachRotateMitigation(
93
- transport: DailyRotateFile,
94
- opts: { logLevel: string; nodeEnv: string }
95
- ) {
96
- const { logLevel, nodeEnv } = opts;
97
- let isRefreshing = false;
98
- transport.on("rotate", (_old: string, _new: string) => {
99
- if (isRefreshing) return;
100
- isRefreshing = true;
101
- (logger as any).silent = true;
102
-
103
- const REFRESH_TIMEOUT_MS = 10000;
104
- let timeout: NodeJS.Timeout | null = setTimeout(() => {
105
- (logger as any).silent = false;
106
- isRefreshing = false;
107
- console.warn(
108
- '[logger] Refresh timeout: resuming logging after 10s without "new" event.'
109
- );
110
- }, REFRESH_TIMEOUT_MS);
111
-
112
- // Close and clear existing file transports
113
- const existing = (logger.transports || []).filter(
114
- (t: any) => t instanceof DailyRotateFile
115
- );
116
- for (const t of existing) {
117
- const s = (t as any).logStream;
118
- if (s && typeof s.end === "function") {
119
- try {
120
- s.end();
121
- } catch {}
122
- }
123
- }
124
- logger.clear();
125
-
126
- // Create replacement, attach mitigation for future rotations
127
- const next = createFileTransport();
128
- next.on("new", () => {
129
- if (timeout) {
130
- clearTimeout(timeout);
131
- timeout = null;
132
- }
133
- (logger as any).silent = false;
134
- isRefreshing = false;
135
- });
136
- attachRotateMitigation(next, opts);
137
-
138
- logger.add(next);
139
- if (nodeEnv !== "production") {
140
- logger.add(
141
- new transports.Console({
142
- format: format.combine(
143
- format.timestamp(),
144
- format.splat(),
145
- baseFormat,
146
- format.colorize({ all: true })
147
- ),
148
- })
149
- );
150
- }
151
- logger.level = logLevel;
152
- });
153
- }
154
-
155
79
  // Function to reconfigure the logger once CoreConfiguration is available
156
80
  export const configureLogger = (logLevel: string, nodeEnv: string) => {
157
- // Remove existing transports (safely): close any DailyRotateFile streams first
158
- try {
159
- const existingFileTransports = (logger.transports || []).filter(
160
- (t: any) => t instanceof DailyRotateFile
161
- );
162
- for (const t of existingFileTransports) {
163
- const s = (t as any).logStream;
164
- if (s && typeof s.end === "function") {
165
- try {
166
- s.end();
167
- } catch {}
168
- }
169
- }
170
- } catch {}
171
-
81
+ // Remove existing transports
172
82
  logger.clear();
173
83
 
174
84
  // Add file transport
175
- const fileTransport = createFileTransport();
176
- attachRotateMitigation(fileTransport, { logLevel, nodeEnv });
177
- logger.add(fileTransport);
85
+ logger.add(
86
+ new DailyRotateFile({
87
+ filename: path.join(logDirectory, "%DATE%.log"),
88
+ datePattern: "YYYY-MM-DD",
89
+ zippedArchive: true,
90
+ maxSize: "20m",
91
+ maxFiles: "14d",
92
+ format: logFormat,
93
+ })
94
+ );
178
95
 
179
96
  // Add console transport in non-production environments
180
97
  if (nodeEnv !== "production") {
@@ -15,7 +15,7 @@ export {
15
15
  * Timezone and time-related utilities
16
16
  */
17
17
  export { getTimezoneOffsetAndPersist } from "./time-utils";
18
- export { formatDateWithTZOffset, convertToLocalTime } from "./timezone";
18
+ export { formatDateWithTZOffset, convertToLocalTime, toISOWithOffset } from "./timezone";
19
19
  export { applyTimezoneOffsetsToFields } from "./time-utils";
20
20
  export * from "./time-utils";
21
21
 
@@ -1,4 +1,4 @@
1
- import { convertToLocalTime } from "./timezone";
1
+ import { convertToLocalTime, toISOWithOffset } from "./timezone";
2
2
  import { MMReceiveLaborTicket } from "../services/mm-api-service/types/receive-types";
3
3
 
4
4
  /**
@@ -22,7 +22,7 @@ export function convertLaborTicketToLocalTimezone(
22
22
 
23
23
  timeFields.forEach((field) => {
24
24
  const localTime = convertToLocalTime(laborTicket[field], timezoneOffset);
25
- laborTicket[field] = localTime?.toISOString() || null;
25
+ laborTicket[field] = localTime ? toISOWithOffset(localTime, timezoneOffset) : null;
26
26
  });
27
27
  return laborTicket;
28
28
  }
@@ -94,3 +94,31 @@ export const formatDateWithTZOffset = (
94
94
  // Append the timezone offset
95
95
  return `${isoDate}${sign}${hours}:${minutes}`;
96
96
  };
97
+
98
+ /**
99
+ * Formats a Date object as an ISO string with the specified timezone offset
100
+ * @param date The Date object to format (should be a Date that has been shifted by convertToLocalTime)
101
+ * @param timezoneOffset The timezone offset in hours
102
+ * @returns ISO string with offset in format: YYYY-MM-DDTHH:mm:ss.SSS±HH:MM
103
+ */
104
+ export const toISOWithOffset = (date: Date, timezoneOffset: number): string => {
105
+ const sign = timezoneOffset >= 0 ? "+" : "-";
106
+ const abs = Math.abs(timezoneOffset);
107
+ const hours = Math.floor(abs);
108
+ const minutes = Math.round((abs - hours) * 60);
109
+ const pad2 = (n: number) => n.toString().padStart(2, "0");
110
+ const pad3 = (n: number) => n.toString().padStart(3, "0");
111
+
112
+ // Use UTC getters since convertToLocalTime shifts the Date's internal timestamp
113
+ // The UTC components of the shifted Date represent the local wall time
114
+ const yyyy = date.getUTCFullYear();
115
+ const MM = pad2(date.getUTCMonth() + 1);
116
+ const dd = pad2(date.getUTCDate());
117
+ const HH = pad2(date.getUTCHours());
118
+ const mm = pad2(date.getUTCMinutes());
119
+ const ss = pad2(date.getUTCSeconds());
120
+ const SSS = pad3(date.getUTCMilliseconds());
121
+ const off = `${sign}${pad2(hours)}:${pad2(minutes)}`;
122
+
123
+ return `${yyyy}-${MM}-${dd}T${HH}:${mm}:${ss}.${SSS}${off}`;
124
+ };