kintone-migrator 0.35.3 → 0.35.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.
package/dist/index.mjs CHANGED
@@ -6599,6 +6599,13 @@ const VALID_ENTITY_TYPES$5 = /* @__PURE__ */ new Set([
6599
6599
  function isNotificationEntityType(value) {
6600
6600
  return VALID_ENTITY_TYPES$5.has(value);
6601
6601
  }
6602
+ /**
6603
+ * Normalizes a reminder timezone read at a boundary (kintone API or config
6604
+ * file) to the domain form: `null` and `""` mean unset (`undefined`).
6605
+ */
6606
+ function normalizeReminderTimezone(value) {
6607
+ return value === null || value === "" ? void 0 : value;
6608
+ }
6602
6609
  //#endregion
6603
6610
  //#region src/core/domain/notification/services/configParser.ts
6604
6611
  const REMINDER_OFFSET_MIN = -1e4;
@@ -6694,10 +6701,13 @@ function parseReminderConfig(raw) {
6694
6701
  if (!isRecord(raw)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must be an object");
6695
6702
  if (!Array.isArray(raw.notifications)) throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, "\"reminder\" must have a \"notifications\" array");
6696
6703
  const notifications = raw.notifications.map((item, i) => parseReminderNotification(item, i));
6697
- return {
6698
- timezone: typeof raw.timezone === "string" ? raw.timezone : "Asia/Tokyo",
6704
+ const rawTimezone = raw.timezone ?? null;
6705
+ if (rawTimezone !== null && typeof rawTimezone !== "string") throw new BusinessRuleError(NotificationErrorCode.NtInvalidConfigStructure, `"reminder" has non-string "timezone": ${String(rawTimezone)}`);
6706
+ const timezone = normalizeReminderTimezone(rawTimezone);
6707
+ return timezone !== void 0 ? {
6708
+ timezone,
6699
6709
  notifications
6700
- };
6710
+ } : { notifications };
6701
6711
  }
6702
6712
  const NotificationConfigParser = { parse: (parsed) => {
6703
6713
  const obj = validateParsedConfig(parsed, NotificationErrorCode.NtInvalidConfigStructure, "Notification");
@@ -6746,8 +6756,7 @@ async function applyNotification({ container }) {
6746
6756
  if (config.reminder !== void 0) {
6747
6757
  const currentReminder = await container.notificationConfigurator.getReminderNotifications();
6748
6758
  await container.notificationConfigurator.updateReminderNotifications({
6749
- timezone: config.reminder.timezone,
6750
- notifications: config.reminder.notifications,
6759
+ ...config.reminder,
6751
6760
  revision: currentReminder.revision
6752
6761
  });
6753
6762
  }
@@ -8245,8 +8254,11 @@ var KintoneNotificationConfigurator = class {
8245
8254
  preview: true
8246
8255
  });
8247
8256
  const notifications = response.notifications.map(fromKintoneReminderNotification);
8257
+ const rawTimezone = response.timezone ?? null;
8258
+ if (rawTimezone !== null && typeof rawTimezone !== "string") throw new SystemError(SystemErrorCode.ExternalApiError, `Unexpected reminder timezone from kintone API: ${String(rawTimezone)}`);
8259
+ const timezone = normalizeReminderTimezone(rawTimezone);
8248
8260
  return {
8249
- timezone: response.timezone,
8261
+ ...timezone !== void 0 ? { timezone } : {},
8250
8262
  notifications,
8251
8263
  revision: response.revision
8252
8264
  };
@@ -8258,9 +8270,9 @@ var KintoneNotificationConfigurator = class {
8258
8270
  try {
8259
8271
  const requestParams = {
8260
8272
  app: this.appId,
8261
- timezone: params.timezone,
8262
8273
  notifications: params.notifications.map(toKintoneReminderNotification)
8263
8274
  };
8275
+ if (params.timezone !== void 0) requestParams.timezone = params.timezone;
8264
8276
  if (params.revision !== void 0) requestParams.revision = params.revision;
8265
8277
  return { revision: (await this.client.app.updateReminderNotifications(requestParams)).revision };
8266
8278
  } catch (error) {
@@ -9564,11 +9576,11 @@ const NotificationDiffDetector = { detect: (local, remote) => {
9564
9576
  entries.push(...comparePerRecordSection(localPerRecord, remotePerRecord));
9565
9577
  if (local.reminder && remote.reminder) {
9566
9578
  entries.push(...compareReminderSection(local.reminder.notifications, remote.reminder.notifications));
9567
- if (local.reminder.timezone !== remote.reminder.timezone) entries.push({
9579
+ if (local.reminder.timezone !== void 0 && local.reminder.timezone !== remote.reminder.timezone) entries.push({
9568
9580
  type: "modified",
9569
9581
  section: "reminder",
9570
9582
  name: "timezone",
9571
- details: `${remote.reminder.timezone} -> ${local.reminder.timezone}`
9583
+ details: `${remote.reminder.timezone ?? "(unset)"} -> ${local.reminder.timezone}`
9572
9584
  });
9573
9585
  } else if (local.reminder && !remote.reminder) entries.push({
9574
9586
  type: "added",
@@ -9585,28 +9597,46 @@ const NotificationDiffDetector = { detect: (local, remote) => {
9585
9597
  return buildDiffResult(entries);
9586
9598
  } };
9587
9599
  //#endregion
9588
- //#region src/core/application/notification/detectNotificationDiff.ts
9589
- async function detectNotificationDiff({ container }) {
9590
- const [storageResult, generalResult, perRecordResult, reminderResult] = await Promise.all([
9591
- container.notificationStorage.get(),
9600
+ //#region src/core/application/notification/loadNotificationRemote.ts
9601
+ /**
9602
+ * Fetches the three remote sub-configs (general / perRecord / reminder) and
9603
+ * bundles them into a single {@link NotificationRemote}.
9604
+ *
9605
+ * The three getters each carry the app (preview) revision; since the revision is
9606
+ * app-scoped and the three are fetched at (essentially) the same moment, the
9607
+ * general getter's revision is used as the observed remote revision for the
9608
+ * TOCTOU guard. kintone always returns all three sections, so the bundled config
9609
+ * always has `general` / `perRecord` / `reminder` defined (an unset reminder
9610
+ * timezone stays absent).
9611
+ */
9612
+ async function loadNotificationRemote(container) {
9613
+ const [general, perRecord, reminder] = await Promise.all([
9592
9614
  container.notificationConfigurator.getGeneralNotifications(),
9593
9615
  container.notificationConfigurator.getPerRecordNotifications(),
9594
9616
  container.notificationConfigurator.getReminderNotifications()
9595
9617
  ]);
9596
- if (!storageResult.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Notification config file not found");
9597
- const localConfig = parseNotificationConfigText(container.configCodec, storageResult.content);
9598
- const remoteConfig = {
9599
- general: {
9600
- notifyToCommenter: generalResult.notifyToCommenter,
9601
- notifications: generalResult.notifications
9618
+ return {
9619
+ config: {
9620
+ general: {
9621
+ notifyToCommenter: general.notifyToCommenter,
9622
+ notifications: general.notifications
9623
+ },
9624
+ perRecord: perRecord.notifications,
9625
+ reminder: {
9626
+ ...reminder.timezone !== void 0 ? { timezone: reminder.timezone } : {},
9627
+ notifications: reminder.notifications
9628
+ }
9602
9629
  },
9603
- perRecord: perRecordResult.notifications,
9604
- reminder: {
9605
- timezone: reminderResult.timezone,
9606
- notifications: reminderResult.notifications
9607
- }
9630
+ revision: general.revision
9608
9631
  };
9609
- return NotificationDiffDetector.detect(localConfig, remoteConfig);
9632
+ }
9633
+ //#endregion
9634
+ //#region src/core/application/notification/detectNotificationDiff.ts
9635
+ async function detectNotificationDiff({ container }) {
9636
+ const [storageResult, remote] = await Promise.all([container.notificationStorage.get(), loadNotificationRemote(container)]);
9637
+ if (!storageResult.exists) throw new ValidationError(ValidationErrorCode.InvalidInput, "Notification config file not found");
9638
+ const localConfig = parseNotificationConfigText(container.configCodec, storageResult.content);
9639
+ return NotificationDiffDetector.detect(localConfig, remote.config);
9610
9640
  }
9611
9641
  //#endregion
9612
9642
  //#region src/core/domain/plugin/services/diffDetector.ts
@@ -11209,7 +11239,7 @@ const NotificationConfigSerializer = { serialize: (config) => {
11209
11239
  };
11210
11240
  if (config.perRecord !== void 0) serialized.perRecord = config.perRecord.map(serializePerRecordNotification);
11211
11241
  if (config.reminder !== void 0) serialized.reminder = {
11212
- timezone: config.reminder.timezone,
11242
+ ...config.reminder.timezone !== void 0 ? { timezone: config.reminder.timezone } : {},
11213
11243
  notifications: config.reminder.notifications.map(serializeReminderNotification)
11214
11244
  };
11215
11245
  return serialized;
@@ -11217,22 +11247,7 @@ const NotificationConfigSerializer = { serialize: (config) => {
11217
11247
  //#endregion
11218
11248
  //#region src/core/application/notification/captureNotification.ts
11219
11249
  async function captureNotification({ container }) {
11220
- const [general, perRecord, reminder] = await Promise.all([
11221
- container.notificationConfigurator.getGeneralNotifications(),
11222
- container.notificationConfigurator.getPerRecordNotifications(),
11223
- container.notificationConfigurator.getReminderNotifications()
11224
- ]);
11225
- const config = {
11226
- general: {
11227
- notifyToCommenter: general.notifyToCommenter,
11228
- notifications: general.notifications
11229
- },
11230
- perRecord: perRecord.notifications,
11231
- reminder: {
11232
- timezone: reminder.timezone,
11233
- notifications: reminder.notifications
11234
- }
11235
- };
11250
+ const { config } = await loadNotificationRemote(container);
11236
11251
  return {
11237
11252
  configText: stringifyConfig(container.configCodec, NotificationConfigSerializer.serialize(config)),
11238
11253
  hasExistingConfig: (await container.notificationStorage.get()).exists
@@ -13800,7 +13815,8 @@ var capture_default$8 = createCaptureCommand({
13800
13815
  * conflict-resolution namespace:
13801
13816
  *
13802
13817
  * - **reminder** = `code` stable key (`compareReminderSection`, diffDetector
13803
- * reminder map). Plus the `timezone` scalar as a single whole-entity 3-way.
13818
+ * reminder map). Plus the `timezone` scalar as a single whole-entity 3-way
13819
+ * when the local config manages it (sets a timezone).
13804
13820
  * - **perRecord** = group by `filterCond`, then within a group match by index
13805
13821
  * (`filterCond#i` composite key — `comparePerRecordSection`). `perRecordLabel`
13806
13822
  * is display-only and is NOT used as a match key.
@@ -13863,7 +13879,7 @@ function computeNotificationThreeWayMerge(base, local, remote) {
13863
13879
  const perRecord = classifyThreeWay(buildPerRecordMap(base.perRecord), buildPerRecordMap(local.perRecord), buildPerRecordMap(remote.perRecord), isPerRecordEqual);
13864
13880
  const reminder = classifyThreeWay(buildReminderMap(base.reminder), buildReminderMap(local.reminder), buildReminderMap(remote.reminder), isReminderEqual);
13865
13881
  const generalScalar = computeSingleThreeWayMerge(base.general?.notifyToCommenter ?? false, local.general?.notifyToCommenter ?? false, remote.general?.notifyToCommenter ?? false, (a, b) => a === b);
13866
- const reminderTimezone = computeSingleThreeWayMerge(base.reminder?.timezone ?? "", local.reminder?.timezone ?? "", remote.reminder?.timezone ?? "", (a, b) => a === b);
13882
+ const reminderTimezone = local.reminder?.timezone !== void 0 ? computeSingleThreeWayMerge(base.reminder?.timezone ?? null, local.reminder.timezone, remote.reminder?.timezone ?? null, (a, b) => a === b) : void 0;
13867
13883
  const entries = [
13868
13884
  ...general.entries,
13869
13885
  ...perRecord.entries,
@@ -13874,12 +13890,12 @@ function computeNotificationThreeWayMerge(base, local, remote) {
13874
13890
  ...perRecord.conflicts.map((e) => ({ key: e.key })),
13875
13891
  ...reminder.conflicts.map((e) => ({ key: e.key })),
13876
13892
  ...scalarConflictKey(generalScalar, GENERAL_SCALAR_KEY),
13877
- ...scalarConflictKey(reminderTimezone, REMINDER_TIMEZONE_KEY)
13893
+ ...reminderTimezone !== void 0 ? scalarConflictKey(reminderTimezone, REMINDER_TIMEZONE_KEY) : []
13878
13894
  ];
13879
13895
  return {
13880
13896
  entries,
13881
13897
  generalScalar,
13882
- reminderTimezone,
13898
+ ...reminderTimezone !== void 0 ? { reminderTimezone } : {},
13883
13899
  conflicts,
13884
13900
  hasConflict: conflicts.length > 0
13885
13901
  };
@@ -13929,7 +13945,7 @@ function collectReminderNotifications(entries, resolution) {
13929
13945
  */
13930
13946
  function resolveNotificationMerge(merge, resolution) {
13931
13947
  const notifyToCommenter = resolveSingleMerge(merge.generalScalar, resolution.get(GENERAL_SCALAR_KEY), NotificationErrorCode.NtUnresolvedConflict);
13932
- const timezone = resolveSingleMerge(merge.reminderTimezone, resolution.get(REMINDER_TIMEZONE_KEY), NotificationErrorCode.NtUnresolvedConflict);
13948
+ const timezone = merge.reminderTimezone !== void 0 ? resolveSingleMerge(merge.reminderTimezone, resolution.get(REMINDER_TIMEZONE_KEY), NotificationErrorCode.NtUnresolvedConflict) : null;
13933
13949
  return {
13934
13950
  general: {
13935
13951
  notifyToCommenter,
@@ -13937,7 +13953,7 @@ function resolveNotificationMerge(merge, resolution) {
13937
13953
  },
13938
13954
  perRecord: collectPerRecordNotifications(merge.entries, resolution),
13939
13955
  reminder: {
13940
- timezone,
13956
+ ...timezone !== null ? { timezone } : {},
13941
13957
  notifications: collectReminderNotifications(merge.entries, resolution)
13942
13958
  }
13943
13959
  };
@@ -13956,37 +13972,6 @@ const NotificationStateParser = { parse: (parsed) => ({ config: NotificationConf
13956
13972
  //#endregion
13957
13973
  //#region src/core/application/notification/loadNotificationThreeWayInputs.ts
13958
13974
  /**
13959
- * Fetches the three remote sub-configs (general / perRecord / reminder) and
13960
- * bundles them into a single {@link NotificationRemote}.
13961
- *
13962
- * The three getters each carry the app (preview) revision; since the revision is
13963
- * app-scoped and the three are fetched at (essentially) the same moment, the
13964
- * general getter's revision is used as the observed remote revision for the
13965
- * TOCTOU guard. kintone always returns all three sections, so the bundled config
13966
- * always has `general` / `perRecord` / `reminder` defined.
13967
- */
13968
- async function loadNotificationRemote(container) {
13969
- const [general, perRecord, reminder] = await Promise.all([
13970
- container.notificationConfigurator.getGeneralNotifications(),
13971
- container.notificationConfigurator.getPerRecordNotifications(),
13972
- container.notificationConfigurator.getReminderNotifications()
13973
- ]);
13974
- return {
13975
- config: {
13976
- general: {
13977
- notifyToCommenter: general.notifyToCommenter,
13978
- notifications: general.notifications
13979
- },
13980
- perRecord: perRecord.notifications,
13981
- reminder: {
13982
- timezone: reminder.timezone,
13983
- notifications: reminder.notifications
13984
- }
13985
- },
13986
- revision: general.revision
13987
- };
13988
- }
13989
- /**
13990
13975
  * Loads the four inputs of a 3-way notification sync (base snapshot, base app
13991
13976
  * revision, local YAML, remote config + revision) via the generic
13992
13977
  * {@link loadThreeWayInputs}. Notification bundles three sub-configs into one
@@ -14089,7 +14074,7 @@ function buildThreeWay(merge) {
14089
14074
  }
14090
14075
  }
14091
14076
  pushScalar(merge.generalScalar, "general:notifyToCommenter", "notifyToCommenter", localChanges, remoteDrift, conflicts, extras);
14092
- pushScalar(merge.reminderTimezone, "reminder:timezone", "timezone", localChanges, remoteDrift, conflicts, extras);
14077
+ if (merge.reminderTimezone !== void 0) pushScalar(merge.reminderTimezone, "reminder:timezone", "timezone", localChanges, remoteDrift, conflicts, extras);
14093
14078
  return {
14094
14079
  mode: "three-way",
14095
14080
  localChanges,
@@ -14312,7 +14297,7 @@ async function pushNotification({ container, input }) {
14312
14297
  return false;
14313
14298
  };
14314
14299
  const isDriftKind = (kind) => kind === "remoteOnly" || kind === "conflict";
14315
- if (merge.entries.some((e) => isManaged(e.key) && isDriftKind(e.change.kind)) || local.general !== void 0 && isDriftKind(merge.generalScalar.change.kind) || local.reminder !== void 0 && isDriftKind(merge.reminderTimezone.change.kind)) throw buildDriftConflict(NOTIFICATION_PULL_COMMAND);
14300
+ if (merge.entries.some((e) => isManaged(e.key) && isDriftKind(e.change.kind)) || local.general !== void 0 && isDriftKind(merge.generalScalar.change.kind) || merge.reminderTimezone !== void 0 && isDriftKind(merge.reminderTimezone.change.kind)) throw buildDriftConflict(NOTIFICATION_PULL_COMMAND);
14316
14301
  }
14317
14302
  const sendRevision = !(input.force || firstTime);
14318
14303
  let revision = remote.revision;
@@ -14338,11 +14323,14 @@ async function pushNotification({ container, input }) {
14338
14323
  }
14339
14324
  if (local.reminder !== void 0) {
14340
14325
  revision = (await container.notificationConfigurator.updateReminderNotifications({
14341
- timezone: local.reminder.timezone,
14342
- notifications: local.reminder.notifications,
14326
+ ...local.reminder,
14343
14327
  ...sendRevision ? { revision } : {}
14344
14328
  })).revision;
14345
- newBase.reminder = local.reminder;
14329
+ const timezone = local.reminder.timezone ?? remote.config.reminder?.timezone;
14330
+ newBase.reminder = {
14331
+ ...timezone !== void 0 ? { timezone } : {},
14332
+ notifications: local.reminder.notifications
14333
+ };
14346
14334
  }
14347
14335
  await saveNotificationSnapshotAndRevision(container, newBase, revision);
14348
14336
  return {