@exabugs/dynamodb-client 1.26.0 → 1.27.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.
Files changed (146) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/__generated__/models/apiOperation.d.ts +1 -0
  3. package/dist/__generated__/models/apiOperation.d.ts.map +1 -1
  4. package/dist/__generated__/models/apiOperation.js +1 -0
  5. package/dist/__generated__/models/apiOperation.js.map +1 -1
  6. package/dist/__generated__/models/bulkOperationResult.d.ts +2 -0
  7. package/dist/__generated__/models/bulkOperationResult.d.ts.map +1 -1
  8. package/dist/__generated__/models/countParams.d.ts +31 -0
  9. package/dist/__generated__/models/countParams.d.ts.map +1 -0
  10. package/dist/__generated__/models/countParams.js +2 -0
  11. package/dist/__generated__/models/countParams.js.map +1 -0
  12. package/dist/__generated__/models/countResult.d.ts +37 -0
  13. package/dist/__generated__/models/countResult.d.ts.map +1 -0
  14. package/dist/__generated__/models/countResult.js +2 -0
  15. package/dist/__generated__/models/countResult.js.map +1 -0
  16. package/dist/__generated__/models/countResultConsumedCapacity.d.ts +35 -0
  17. package/dist/__generated__/models/countResultConsumedCapacity.d.ts.map +1 -0
  18. package/dist/__generated__/models/countResultConsumedCapacity.js +25 -0
  19. package/dist/__generated__/models/countResultConsumedCapacity.js.map +1 -0
  20. package/dist/__generated__/models/executeOperationBodyOp.d.ts +1 -0
  21. package/dist/__generated__/models/executeOperationBodyOp.d.ts.map +1 -1
  22. package/dist/__generated__/models/executeOperationBodyOp.js +1 -0
  23. package/dist/__generated__/models/executeOperationBodyOp.js.map +1 -1
  24. package/dist/__generated__/models/findResultPageInfo.d.ts +2 -0
  25. package/dist/__generated__/models/findResultPageInfo.d.ts.map +1 -1
  26. package/dist/__generated__/models/index.d.ts +3 -0
  27. package/dist/__generated__/models/index.d.ts.map +1 -1
  28. package/dist/__generated__/models/index.js +3 -0
  29. package/dist/__generated__/models/index.js.map +1 -1
  30. package/dist/client/Collection.d.ts +7 -0
  31. package/dist/client/Collection.d.ts.map +1 -1
  32. package/dist/client/Collection.js +20 -1
  33. package/dist/client/Collection.js.map +1 -1
  34. package/dist/scripts/repair-shadows.js +86 -42
  35. package/dist/scripts/repair-shadows.js.map +1 -1
  36. package/dist/scripts/utils/cliParser.d.ts +9 -22
  37. package/dist/scripts/utils/cliParser.d.ts.map +1 -1
  38. package/dist/scripts/utils/cliParser.js +14 -37
  39. package/dist/scripts/utils/cliParser.js.map +1 -1
  40. package/dist/scripts/utils/shadowAudit.d.ts +49 -0
  41. package/dist/scripts/utils/shadowAudit.d.ts.map +1 -0
  42. package/dist/scripts/utils/shadowAudit.js +84 -0
  43. package/dist/scripts/utils/shadowAudit.js.map +1 -0
  44. package/dist/scripts/utils/shadowRepair.d.ts +42 -0
  45. package/dist/scripts/utils/shadowRepair.d.ts.map +1 -0
  46. package/dist/scripts/utils/shadowRepair.js +110 -0
  47. package/dist/scripts/utils/shadowRepair.js.map +1 -0
  48. package/dist/server/handler.cjs +1237 -1122
  49. package/dist/server/handler.cjs.map +4 -4
  50. package/dist/server/handler.js +2 -2
  51. package/dist/server/handler.js.map +1 -1
  52. package/dist/server/media-handler.cjs +2 -2
  53. package/dist/server/media-process-handler-dlq.cjs +19 -3
  54. package/dist/server/media-process-handler-dlq.cjs.map +2 -2
  55. package/dist/server/media-process-handler.cjs +19 -3
  56. package/dist/server/media-process-handler.cjs.map +2 -2
  57. package/dist/server/operations/count.d.ts +3 -0
  58. package/dist/server/operations/count.d.ts.map +1 -0
  59. package/dist/server/operations/count.js +81 -0
  60. package/dist/server/operations/count.js.map +1 -0
  61. package/dist/server/operations/deleteMany.d.ts.map +1 -1
  62. package/dist/server/operations/deleteMany.js +2 -1
  63. package/dist/server/operations/deleteMany.js.map +1 -1
  64. package/dist/server/operations/deleteOne.d.ts.map +1 -1
  65. package/dist/server/operations/deleteOne.js +3 -12
  66. package/dist/server/operations/deleteOne.js.map +1 -1
  67. package/dist/server/operations/find/handler.d.ts.map +1 -1
  68. package/dist/server/operations/find/handler.js +4 -1
  69. package/dist/server/operations/find/handler.js.map +1 -1
  70. package/dist/server/operations/find/keyCondition.d.ts +38 -0
  71. package/dist/server/operations/find/keyCondition.d.ts.map +1 -0
  72. package/dist/server/operations/find/keyCondition.js +184 -0
  73. package/dist/server/operations/find/keyCondition.js.map +1 -0
  74. package/dist/server/operations/find/nearQuery.d.ts +4 -1
  75. package/dist/server/operations/find/nearQuery.d.ts.map +1 -1
  76. package/dist/server/operations/find/nearQuery.js +30 -42
  77. package/dist/server/operations/find/nearQuery.js.map +1 -1
  78. package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
  79. package/dist/server/operations/find/shadowQuery.js +16 -143
  80. package/dist/server/operations/find/shadowQuery.js.map +1 -1
  81. package/dist/server/operations/find/utils.d.ts.map +1 -1
  82. package/dist/server/operations/find/utils.js +0 -5
  83. package/dist/server/operations/find/utils.js.map +1 -1
  84. package/dist/server/operations/insertMany.d.ts.map +1 -1
  85. package/dist/server/operations/insertMany.js +1 -4
  86. package/dist/server/operations/insertMany.js.map +1 -1
  87. package/dist/server/operations/insertOne.d.ts.map +1 -1
  88. package/dist/server/operations/insertOne.js +2 -6
  89. package/dist/server/operations/insertOne.js.map +1 -1
  90. package/dist/server/operations/operationDispatcher.d.ts.map +1 -1
  91. package/dist/server/operations/operationDispatcher.js +3 -0
  92. package/dist/server/operations/operationDispatcher.js.map +1 -1
  93. package/dist/server/operations/updateMany.d.ts.map +1 -1
  94. package/dist/server/operations/updateMany.js +23 -17
  95. package/dist/server/operations/updateMany.js.map +1 -1
  96. package/dist/server/operations/updateOne.d.ts.map +1 -1
  97. package/dist/server/operations/updateOne.js +10 -21
  98. package/dist/server/operations/updateOne.js.map +1 -1
  99. package/dist/server/query/nearSearch.d.ts +37 -25
  100. package/dist/server/query/nearSearch.d.ts.map +1 -1
  101. package/dist/server/query/nearSearch.js +87 -125
  102. package/dist/server/query/nearSearch.js.map +1 -1
  103. package/dist/server/types.d.ts +7 -1
  104. package/dist/server/types.d.ts.map +1 -1
  105. package/dist/server/utils/bulkError.d.ts +12 -0
  106. package/dist/server/utils/bulkError.d.ts.map +1 -0
  107. package/dist/server/utils/bulkError.js +21 -0
  108. package/dist/server/utils/bulkError.js.map +1 -0
  109. package/dist/server/utils/chunking.d.ts +9 -1
  110. package/dist/server/utils/chunking.d.ts.map +1 -1
  111. package/dist/server/utils/chunking.js +20 -3
  112. package/dist/server/utils/chunking.js.map +1 -1
  113. package/dist/server/utils/filter.d.ts +3 -105
  114. package/dist/server/utils/filter.d.ts.map +1 -1
  115. package/dist/server/utils/filter.js +14 -218
  116. package/dist/server/utils/filter.js.map +1 -1
  117. package/dist/server/utils/updateOperators.d.ts +12 -1
  118. package/dist/server/utils/updateOperators.d.ts.map +1 -1
  119. package/dist/server/utils/updateOperators.js +53 -6
  120. package/dist/server/utils/updateOperators.js.map +1 -1
  121. package/docs/README.md +9 -12
  122. package/package.json +1 -1
  123. package/dist/scripts/operations/bulkRecordRepair.d.ts +0 -17
  124. package/dist/scripts/operations/bulkRecordRepair.d.ts.map +0 -1
  125. package/dist/scripts/operations/bulkRecordRepair.js +0 -76
  126. package/dist/scripts/operations/bulkRecordRepair.js.map +0 -1
  127. package/dist/scripts/operations/singleRecordRepair.d.ts +0 -18
  128. package/dist/scripts/operations/singleRecordRepair.d.ts.map +0 -1
  129. package/dist/scripts/operations/singleRecordRepair.js +0 -46
  130. package/dist/scripts/operations/singleRecordRepair.js.map +0 -1
  131. package/dist/scripts/utils/awsUtils.d.ts +0 -15
  132. package/dist/scripts/utils/awsUtils.d.ts.map +0 -1
  133. package/dist/scripts/utils/awsUtils.js +0 -31
  134. package/dist/scripts/utils/awsUtils.js.map +0 -1
  135. package/dist/scripts/utils/clientFactory.d.ts +0 -22
  136. package/dist/scripts/utils/clientFactory.d.ts.map +0 -1
  137. package/dist/scripts/utils/clientFactory.js +0 -36
  138. package/dist/scripts/utils/clientFactory.js.map +0 -1
  139. package/dist/scripts/utils/repairUtils.d.ts +0 -58
  140. package/dist/scripts/utils/repairUtils.d.ts.map +0 -1
  141. package/dist/scripts/utils/repairUtils.js +0 -52
  142. package/dist/scripts/utils/repairUtils.js.map +0 -1
  143. package/dist/server/utils/ttl.d.ts +0 -17
  144. package/dist/server/utils/ttl.d.ts.map +0 -1
  145. package/dist/server/utils/ttl.js +0 -64
  146. package/dist/server/utils/ttl.js.map +0 -1
@@ -1,30 +1,17 @@
1
1
  /**
2
- * コマンドライン引数解析ユーティリティ
3
- *
4
- * スクリプトのコマンドライン引数を解析する
5
- */
6
- /**
7
- * 修復スクリプトの設定
2
+ * repair-shadows の引数の解析
8
3
  */
9
4
  export interface RepairScriptConfig {
5
+ /** Records のテーブル名(必須。既定を持たない) */
6
+ table: string;
7
+ /** AWS のリージョン(必須。既定を持たない) */
8
+ region: string;
9
+ /** 対象のリソース(PK) */
10
10
  resource: string;
11
- recordId?: string;
12
- dryRun: boolean;
11
+ /** Records の Lambda の関数名。シャドーの設定(SHADOW_*)とテーブル名を読んで、確かめる */
12
+ lambda: string;
13
+ /** true のときだけ書く(既定は確認だけ) */
13
14
  repair: boolean;
14
15
  }
15
- /**
16
- * コマンドライン引数を解析する
17
- *
18
- * @param args - process.argv.slice(2)の結果
19
- * @returns 解析された設定
20
- * @throws {Error} 必須引数が不足している場合
21
- */
22
16
  export declare function parseRepairScriptArgs(args: string[]): RepairScriptConfig;
23
- /**
24
- * スクリプト設定を表示する
25
- *
26
- * @param config - スクリプト設定
27
- * @param apiUrl - Records API URL
28
- */
29
- export declare function displayScriptConfig(config: RepairScriptConfig, apiUrl: string): void;
30
17
  //# sourceMappingURL=cliParser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cliParser.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/cliParser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAqBxE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUpF"}
1
+ {"version":3,"file":"cliParser.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/cliParser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,EAAE,OAAO,CAAC;CACjB;AAYD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAQxE"}
@@ -1,44 +1,21 @@
1
1
  /**
2
- * コマンドライン引数解析ユーティリティ
3
- *
4
- * スクリプトのコマンドライン引数を解析する
5
- */
6
- /**
7
- * コマンドライン引数を解析する
8
- *
9
- * @param args - process.argv.slice(2)の結果
10
- * @returns 解析された設定
11
- * @throws {Error} 必須引数が不足している場合
2
+ * repair-shadows の引数の解析
12
3
  */
4
+ const USAGE = 'Usage: repair-shadows --table <table> --region <region> --lambda <records-function> --resource <resource> [--repair]';
5
+ function valueOf(args, name) {
6
+ const index = args.indexOf(name);
7
+ const value = index === -1 ? undefined : args[index + 1];
8
+ if (!value || value.startsWith('--'))
9
+ throw new Error(`${name} が必要です。\n${USAGE}`);
10
+ return value;
11
+ }
13
12
  export function parseRepairScriptArgs(args) {
14
- const resourceIndex = args.indexOf('--resource');
15
- const idIndex = args.indexOf('--id');
16
- const dryRun = args.includes('--dry-run');
17
- const repair = args.includes('--repair');
18
- if (resourceIndex === -1 || !args[resourceIndex + 1]) {
19
- throw new Error('Usage: pnpm --filter @exabugs/dynamodb-client tsx scripts/repair-shadows.ts --resource <resource> [--id <id>] [--dry-run|--repair]');
20
- }
21
- const resource = args[resourceIndex + 1];
22
- const recordId = idIndex !== -1 ? args[idIndex + 1] : undefined;
23
13
  return {
24
- resource,
25
- recordId,
26
- dryRun,
27
- repair,
14
+ table: valueOf(args, '--table'),
15
+ region: valueOf(args, '--region'),
16
+ lambda: valueOf(args, '--lambda'),
17
+ resource: valueOf(args, '--resource'),
18
+ repair: args.includes('--repair'),
28
19
  };
29
20
  }
30
- /**
31
- * スクリプト設定を表示する
32
- *
33
- * @param config - スクリプト設定
34
- * @param apiUrl - Records API URL
35
- */
36
- export function displayScriptConfig(config, apiUrl) {
37
- console.log(`Records API: ${apiUrl}`);
38
- console.log(`Resource: ${config.resource}`);
39
- console.log(`Mode: ${config.dryRun ? 'DRY RUN' : config.repair ? 'REPAIR' : 'DRY RUN (default)'}`);
40
- if (config.recordId) {
41
- console.log(`Target Record ID: ${config.recordId}`);
42
- }
43
- }
44
21
  //# sourceMappingURL=cliParser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cliParser.js","sourceRoot":"","sources":["../../../src/scripts/utils/cliParser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAc;IAClD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAEzC,IAAI,aAAa,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CACb,oIAAoI,CACrI,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhE,OAAO;QACL,QAAQ;QACR,QAAQ;QACR,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAA0B,EAAE,MAAc;IAC5E,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CACT,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,EAAE,CACtF,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,qBAAqB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"cliParser.js","sourceRoot":"","sources":["../../../src/scripts/utils/cliParser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,MAAM,KAAK,GACT,sHAAsH,CAAC;AAEzH,SAAS,OAAO,CAAC,IAAc,EAAE,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,KAAK,EAAE,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAc;IAClD,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;QAC/B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC;QACjC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC;QACjC,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC;QACrC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * シャドーの食い違いの判定(純粋関数。DynamoDB に触れない)
3
+ *
4
+ * テーブルから読んだ項目(本体とシャドー)を比べ、3 種類の食い違いを数える。
5
+ * - 孤立: 実在するが、本体のあるべき一覧に無いシャドー
6
+ * - 欠け: あるべきだが、実在しないシャドー
7
+ * - 一覧の食い違い: 本体の `__shadowKeys` が、あるべき一覧と違う
8
+ * - 本体の無いシャドー
9
+ */
10
+ import { type ShadowConfig } from '../../server/shadow/index.js';
11
+ import { generateMainRecordSK } from '../../shadows/index.js';
12
+ /** Query で読んだ 1 項目 */
13
+ export type TableItem = Record<string, unknown>;
14
+ /** 1 つの本体レコードの食い違い */
15
+ export interface RecordIssue {
16
+ id: string;
17
+ /** 読んだときの版(`__rev`。無ければ undefined) */
18
+ revision: number | undefined;
19
+ /** あるべきシャドーの SK(本体の `__shadowKeys` に書き直す値) */
20
+ expected: string[];
21
+ /** 孤立(削除する) */
22
+ orphans: string[];
23
+ /** 欠け(作る) */
24
+ missing: string[];
25
+ /** 本体の `__shadowKeys` が、あるべき一覧と違う */
26
+ listMismatch: boolean;
27
+ }
28
+ /** 本体の無いシャドー(id ごと) */
29
+ export interface BodylessIssue {
30
+ id: string;
31
+ shadows: string[];
32
+ }
33
+ export interface AuditResult {
34
+ bodies: number;
35
+ shadows: number;
36
+ records: RecordIssue[];
37
+ bodyless: BodylessIssue[];
38
+ }
39
+ /** シャドーの SK から、本体の id を取る(値に `#id#` が現れうるので、最後の区切りを使う) */
40
+ export declare function recordIdOfShadow(sk: string): string | null;
41
+ /**
42
+ * 項目を比べて、食い違いを返す
43
+ *
44
+ * @param items - 1 つのリソース(PK)の全項目
45
+ */
46
+ export declare function auditShadows(items: TableItem[], resource: string, config: ShadowConfig): AuditResult;
47
+ /** 本体の SK(確認・テスト用) */
48
+ export declare const mainSKOf: typeof generateMainRecordSK;
49
+ //# sourceMappingURL=shadowAudit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadowAudit.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/shadowAudit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,YAAY,EAAyB,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,sBAAsB;AACtB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,sBAAsB;AACtB,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,qCAAqC;IACrC,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,uBAAuB;AACvB,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAKD,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG1D;AAkBD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,GACnB,WAAW,CAiDb;AAED,sBAAsB;AACtB,eAAO,MAAM,QAAQ,6BAAuB,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * シャドーの食い違いの判定(純粋関数。DynamoDB に触れない)
3
+ *
4
+ * テーブルから読んだ項目(本体とシャドー)を比べ、3 種類の食い違いを数える。
5
+ * - 孤立: 実在するが、本体のあるべき一覧に無いシャドー
6
+ * - 欠け: あるべきだが、実在しないシャドー
7
+ * - 一覧の食い違い: 本体の `__shadowKeys` が、あるべき一覧と違う
8
+ * - 本体の無いシャドー
9
+ */
10
+ import { generateShadowRecords } from '../../server/shadow/index.js';
11
+ import { generateMainRecordSK } from '../../shadows/index.js';
12
+ const BODY_PREFIX = 'id#';
13
+ const ID_SEPARATOR = '#id#';
14
+ /** シャドーの SK から、本体の id を取る(値に `#id#` が現れうるので、最後の区切りを使う) */
15
+ export function recordIdOfShadow(sk) {
16
+ const index = sk.lastIndexOf(ID_SEPARATOR);
17
+ return index >= 0 ? sk.slice(index + ID_SEPARATOR.length) : null;
18
+ }
19
+ function sameSet(a, b) {
20
+ if (a.length !== b.length)
21
+ return false;
22
+ const set = new Set(a);
23
+ return set.size === new Set(b).size && b.every((x) => set.has(x));
24
+ }
25
+ /** 本体の `data` から、あるべきシャドーの SK を作る(Records の書き込みと同じ関数) */
26
+ function expectedShadowKeys(id, data, resource, config) {
27
+ return generateShadowRecords({ ...data, id }, resource, config).map((s) => s.SK);
28
+ }
29
+ /**
30
+ * 項目を比べて、食い違いを返す
31
+ *
32
+ * @param items - 1 つのリソース(PK)の全項目
33
+ */
34
+ export function auditShadows(items, resource, config) {
35
+ const bodies = new Map();
36
+ const shadowsById = new Map();
37
+ let shadowCount = 0;
38
+ for (const item of items) {
39
+ const sk = item.SK;
40
+ if (sk.startsWith(BODY_PREFIX)) {
41
+ bodies.set(sk.slice(BODY_PREFIX.length), item);
42
+ continue;
43
+ }
44
+ const id = recordIdOfShadow(sk);
45
+ if (id === null)
46
+ continue;
47
+ shadowCount++;
48
+ const list = shadowsById.get(id) ?? [];
49
+ list.push(sk);
50
+ shadowsById.set(id, list);
51
+ }
52
+ const records = [];
53
+ for (const [id, body] of bodies) {
54
+ const data = body.data ?? {};
55
+ const expected = expectedShadowKeys(id, data, resource, config);
56
+ const actual = shadowsById.get(id) ?? [];
57
+ const actualSet = new Set(actual);
58
+ const expectedSet = new Set(expected);
59
+ const orphans = actual.filter((sk) => !expectedSet.has(sk));
60
+ const missing = expected.filter((sk) => !actualSet.has(sk));
61
+ const list = Array.isArray(body.__shadowKeys) ? body.__shadowKeys : [];
62
+ const listMismatch = !sameSet(list, expected);
63
+ if (orphans.length > 0 || missing.length > 0 || listMismatch) {
64
+ const rev = body.__rev;
65
+ records.push({
66
+ id,
67
+ revision: typeof rev === 'number' ? rev : undefined,
68
+ expected,
69
+ orphans,
70
+ missing,
71
+ listMismatch,
72
+ });
73
+ }
74
+ }
75
+ const bodyless = [];
76
+ for (const [id, shadows] of shadowsById) {
77
+ if (!bodies.has(id))
78
+ bodyless.push({ id, shadows });
79
+ }
80
+ return { bodies: bodies.size, shadows: shadowCount, records, bodyless };
81
+ }
82
+ /** 本体の SK(確認・テスト用) */
83
+ export const mainSKOf = generateMainRecordSK;
84
+ //# sourceMappingURL=shadowAudit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadowAudit.js","sourceRoot":"","sources":["../../../src/scripts/utils/shadowAudit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * シャドーの食い違いの確認・修復(テーブルを直接読み書きする運用の道具)
3
+ *
4
+ * Records の HTTP は `__shadowKeys` を返さず、`updateMany` は古い一覧との差分しか書かない。
5
+ * そのため、孤立・欠け・本体の無いシャドーは HTTP 経由では直せない。テーブルを直接読んで比べる。
6
+ * アプリのコードから呼ばない(scripts/dynamodb-access-allowlist.json の permanent)。
7
+ *
8
+ * 修復は、食い違いのあるレコードだけ、1 レコード 1 トランザクション。本体の `data`・`updatedAt` は変えない。
9
+ */
10
+ import { DynamoDBDocumentClient, TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
11
+ import type { ShadowConfig } from '../../server/shadow/index.js';
12
+ import { type AuditResult, type BodylessIssue, type RecordIssue, type TableItem } from './shadowAudit.js';
13
+ /** 1 つのリソース(PK)の全項目を、強い整合性で最後まで読む */
14
+ export declare function readResource(doc: DynamoDBDocumentClient, table: string, resource: string): Promise<TableItem[]>;
15
+ type TransactItem = NonNullable<ConstructorParameters<typeof TransactWriteCommand>[0]['TransactItems']>[number];
16
+ /** 食い違いのある本体レコードの修復(本体の一覧と版だけを更新し、シャドーを足し引きする) */
17
+ export declare function repairItemsOfRecord(table: string, resource: string, issue: RecordIssue): TransactItem[];
18
+ /** 本体の無いシャドーの削除(同じトランザクションで、本体が無いことを確かめる) */
19
+ export declare function repairItemsOfBodyless(table: string, resource: string, issue: BodylessIssue): TransactItem[];
20
+ export interface RepairOutcome {
21
+ repaired: number;
22
+ /** 条件に外れた(修復中に書き込まれた)・項目数が多すぎるなどで飛ばした。再実行で直す */
23
+ skipped: Array<{
24
+ id: string;
25
+ reason: string;
26
+ }>;
27
+ }
28
+ export interface RunOptions {
29
+ doc: DynamoDBDocumentClient;
30
+ table: string;
31
+ resource: string;
32
+ config: ShadowConfig;
33
+ /** true のときだけ書く(既定は読み取りだけ) */
34
+ repair: boolean;
35
+ }
36
+ /** 確認(と、repair が true なら修復)。結果を返す */
37
+ export declare function runShadowRepair(options: RunOptions): Promise<{
38
+ audit: AuditResult;
39
+ outcome?: RepairOutcome;
40
+ }>;
41
+ export {};
42
+ //# sourceMappingURL=shadowRepair.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadowRepair.d.ts","sourceRoot":"","sources":["../../../src/scripts/utils/shadowRepair.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,sBAAsB,EAAgB,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAC;AAK1B,qCAAqC;AACrC,wBAAsB,YAAY,CAChC,GAAG,EAAE,sBAAsB,EAC3B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,EAAE,CAAC,CAiBtB;AAED,KAAK,YAAY,GAAG,WAAW,CAC7B,qBAAqB,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CACvE,CAAC,MAAM,CAAC,CAAC;AAEV,kDAAkD;AAClD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,WAAW,GACjB,YAAY,EAAE,CAyBhB;AAED,6CAA6C;AAC7C,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,GACnB,YAAY,EAAE,CAahB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AA6BD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,sBAAsB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,qCAAqC;AACrC,wBAAsB,eAAe,CACnC,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,CAAA;CAAE,CAAC,CAS1D"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * シャドーの食い違いの確認・修復(テーブルを直接読み書きする運用の道具)
3
+ *
4
+ * Records の HTTP は `__shadowKeys` を返さず、`updateMany` は古い一覧との差分しか書かない。
5
+ * そのため、孤立・欠け・本体の無いシャドーは HTTP 経由では直せない。テーブルを直接読んで比べる。
6
+ * アプリのコードから呼ばない(scripts/dynamodb-access-allowlist.json の permanent)。
7
+ *
8
+ * 修復は、食い違いのあるレコードだけ、1 レコード 1 トランザクション。本体の `data`・`updatedAt` は変えない。
9
+ */
10
+ import { QueryCommand, TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
11
+ import { nextRevision, unchangedCondition } from '../../server/utils/revision.js';
12
+ import { auditShadows, mainSKOf, } from './shadowAudit.js';
13
+ /** TransactWriteItems の項目数の上限 */
14
+ const MAX_TRANSACTION_ITEMS = 100;
15
+ /** 1 つのリソース(PK)の全項目を、強い整合性で最後まで読む */
16
+ export async function readResource(doc, table, resource) {
17
+ const items = [];
18
+ let startKey;
19
+ do {
20
+ const out = await doc.send(new QueryCommand({
21
+ TableName: table,
22
+ KeyConditionExpression: 'PK = :pk',
23
+ ExpressionAttributeValues: { ':pk': resource },
24
+ ConsistentRead: true,
25
+ ExclusiveStartKey: startKey,
26
+ }));
27
+ items.push(...(out.Items ?? []));
28
+ startKey = out.LastEvaluatedKey;
29
+ } while (startKey);
30
+ return items;
31
+ }
32
+ /** 食い違いのある本体レコードの修復(本体の一覧と版だけを更新し、シャドーを足し引きする) */
33
+ export function repairItemsOfRecord(table, resource, issue) {
34
+ const condition = unchangedCondition(issue.revision);
35
+ const items = [
36
+ {
37
+ Update: {
38
+ TableName: table,
39
+ Key: { PK: resource, SK: mainSKOf(issue.id) },
40
+ UpdateExpression: 'SET #sk = :sk, #rev = :next',
41
+ ConditionExpression: condition.ConditionExpression,
42
+ ExpressionAttributeNames: { ...condition.ExpressionAttributeNames, '#sk': '__shadowKeys' },
43
+ ExpressionAttributeValues: {
44
+ ...condition.ExpressionAttributeValues,
45
+ ':sk': issue.expected,
46
+ ':next': nextRevision(issue.revision),
47
+ },
48
+ },
49
+ },
50
+ ];
51
+ for (const sk of issue.orphans) {
52
+ items.push({ Delete: { TableName: table, Key: { PK: resource, SK: sk } } });
53
+ }
54
+ for (const sk of issue.missing) {
55
+ items.push({ Put: { TableName: table, Item: { PK: resource, SK: sk, data: {} } } });
56
+ }
57
+ return items;
58
+ }
59
+ /** 本体の無いシャドーの削除(同じトランザクションで、本体が無いことを確かめる) */
60
+ export function repairItemsOfBodyless(table, resource, issue) {
61
+ return [
62
+ {
63
+ ConditionCheck: {
64
+ TableName: table,
65
+ Key: { PK: resource, SK: mainSKOf(issue.id) },
66
+ ConditionExpression: 'attribute_not_exists(PK)',
67
+ },
68
+ },
69
+ ...issue.shadows.map((sk) => ({
70
+ Delete: { TableName: table, Key: { PK: resource, SK: sk } },
71
+ })),
72
+ ];
73
+ }
74
+ async function executeAll(doc, groups) {
75
+ const outcome = { repaired: 0, skipped: [] };
76
+ for (const { id, items } of groups) {
77
+ if (items.length > MAX_TRANSACTION_ITEMS) {
78
+ outcome.skipped.push({
79
+ id,
80
+ reason: `項目が ${items.length} 件で、1 トランザクションに収まらない`,
81
+ });
82
+ continue;
83
+ }
84
+ try {
85
+ await doc.send(new TransactWriteCommand({ TransactItems: items }));
86
+ outcome.repaired++;
87
+ }
88
+ catch (error) {
89
+ if (error.name === 'TransactionCanceledException') {
90
+ outcome.skipped.push({ id, reason: '条件に外れた(修復中に書き込まれた)' });
91
+ continue;
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+ return outcome;
97
+ }
98
+ /** 確認(と、repair が true なら修復)。結果を返す */
99
+ export async function runShadowRepair(options) {
100
+ const { doc, table, resource, config, repair } = options;
101
+ const audit = auditShadows(await readResource(doc, table, resource), resource, config);
102
+ if (!repair)
103
+ return { audit };
104
+ const outcome = await executeAll(doc, [
105
+ ...audit.records.map((r) => ({ id: r.id, items: repairItemsOfRecord(table, resource, r) })),
106
+ ...audit.bodyless.map((b) => ({ id: b.id, items: repairItemsOfBodyless(table, resource, b) })),
107
+ ]);
108
+ return { audit, outcome };
109
+ }
110
+ //# sourceMappingURL=shadowRepair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadowRepair.js","sourceRoot":"","sources":["../../../src/scripts/utils/shadowRepair.ts"],"names":[],"mappings":"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"}