@kensio/yulin 1.21.12 → 1.21.14

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 (89) hide show
  1. package/dist/service/dynamodb/command/authorize/sim-dynamodb-attributes.d.ts +27 -0
  2. package/dist/service/dynamodb/command/authorize/sim-dynamodb-attributes.js +35 -0
  3. package/dist/service/dynamodb/command/authorize/sim-dynamodb-authorizer.d.ts +2 -1
  4. package/dist/service/dynamodb/command/authorize/sim-dynamodb-authorizer.js +10 -4
  5. package/dist/service/dynamodb/command/authorize/sim-dynamodb-leading-keys.d.ts +33 -0
  6. package/dist/service/dynamodb/command/authorize/sim-dynamodb-leading-keys.js +45 -0
  7. package/dist/service/dynamodb/command/authorize/sim-dynamodb-reached.d.ts +17 -0
  8. package/dist/service/dynamodb/command/authorize/sim-dynamodb-reached.js +11 -0
  9. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-get-item.js +5 -0
  10. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-read-limit.d.ts +6 -0
  11. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-read-limit.js +16 -0
  12. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-reads.d.ts +2 -0
  13. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-reads.js +14 -22
  14. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-tables.d.ts +10 -2
  15. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-tables.js +1 -1
  16. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-write-item.js +11 -1
  17. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-write.d.ts +6 -0
  18. package/dist/service/dynamodb/command/batch/sim-dynamodb-batch-write.js +8 -8
  19. package/dist/service/dynamodb/command/item/sim-dynamodb-condition-check.d.ts +5 -1
  20. package/dist/service/dynamodb/command/item/sim-dynamodb-condition-check.js +9 -2
  21. package/dist/service/dynamodb/command/item/sim-dynamodb-delete-item.js +8 -1
  22. package/dist/service/dynamodb/command/item/sim-dynamodb-get-item.js +10 -2
  23. package/dist/service/dynamodb/command/item/sim-dynamodb-put-item.js +6 -1
  24. package/dist/service/dynamodb/command/item/sim-dynamodb-update-expressions.d.ts +2 -0
  25. package/dist/service/dynamodb/command/item/sim-dynamodb-update-expressions.js +1 -1
  26. package/dist/service/dynamodb/command/item/sim-dynamodb-update-item.js +8 -1
  27. package/dist/service/dynamodb/command/item/sim-dynamodb-update-plan.d.ts +8 -6
  28. package/dist/service/dynamodb/command/item/sim-dynamodb-update-plan.js +14 -13
  29. package/dist/service/dynamodb/command/item/sim-dynamodb-update-touched.d.ts +10 -0
  30. package/dist/service/dynamodb/command/item/sim-dynamodb-update-touched.js +16 -0
  31. package/dist/service/dynamodb/command/query/sim-dynamodb-query-expressions.d.ts +2 -0
  32. package/dist/service/dynamodb/command/query/sim-dynamodb-query-expressions.js +6 -1
  33. package/dist/service/dynamodb/command/query/sim-dynamodb-query.js +9 -1
  34. package/dist/service/dynamodb/command/scan/sim-dynamodb-scan-expressions.d.ts +2 -0
  35. package/dist/service/dynamodb/command/scan/sim-dynamodb-scan-expressions.js +2 -2
  36. package/dist/service/dynamodb/command/scan/sim-dynamodb-scan.js +1 -1
  37. package/dist/service/dynamodb/command/table/sim-dynamodb-table-access.d.ts +16 -6
  38. package/dist/service/dynamodb/command/table/sim-dynamodb-table-access.js +18 -8
  39. package/dist/service/dynamodb/command/table/sim-dynamodb-table-reach.d.ts +25 -0
  40. package/dist/service/dynamodb/command/table/sim-dynamodb-table-reach.js +27 -0
  41. package/dist/service/dynamodb/command/transact/sim-dynamodb-transact-gets.js +1 -1
  42. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-expression.d.ts +9 -1
  43. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-expression.js +2 -2
  44. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-grammar.js +1 -1
  45. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-operand-parser.d.ts +3 -2
  46. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-operand-parser.js +3 -3
  47. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-parser.d.ts +2 -1
  48. package/dist/service/dynamodb/expression/condition/sim-dynamodb-condition-parser.js +1 -1
  49. package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-expression.js +1 -1
  50. package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.d.ts +3 -2
  51. package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-operands.js +8 -6
  52. package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-parser.d.ts +2 -1
  53. package/dist/service/dynamodb/expression/key-condition/sim-dynamodb-key-condition-parser.js +1 -1
  54. package/dist/service/dynamodb/expression/projection/sim-dynamodb-projection-expression.d.ts +9 -1
  55. package/dist/service/dynamodb/expression/projection/sim-dynamodb-projection-expression.js +5 -5
  56. package/dist/service/dynamodb/expression/sim-dynamodb-document-path-parser.d.ts +3 -3
  57. package/dist/service/dynamodb/expression/sim-dynamodb-document-path-parser.js +8 -4
  58. package/dist/service/dynamodb/expression/sim-dynamodb-expression-attributes.d.ts +33 -0
  59. package/dist/service/dynamodb/expression/sim-dynamodb-expression-attributes.js +40 -0
  60. package/dist/service/dynamodb/expression/sim-dynamodb-expression-parameters.d.ts +6 -0
  61. package/dist/service/dynamodb/expression/sim-dynamodb-expression-parameters.js +7 -0
  62. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-clause.d.ts +3 -3
  63. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-clause.js +3 -3
  64. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-expression.js +1 -1
  65. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-operand-parser.d.ts +3 -2
  66. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-operand-parser.js +3 -3
  67. package/dist/service/dynamodb/expression/update/sim-dynamodb-update-parser.d.ts +2 -1
  68. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-all-values-string-operator.d.ts +4 -1
  69. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-all-values-string-operator.js +6 -1
  70. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-any-value-string-operator.d.ts +4 -1
  71. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-for-any-value-string-operator.js +6 -1
  72. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-scalar-string-operator.d.ts +4 -1
  73. package/dist/service/iam/authorize/match/condition/negated/sim-iam-negated-scalar-string-operator.js +6 -1
  74. package/dist/service/iam/authorize/match/condition/null/sim-iam-null.d.ts +23 -0
  75. package/dist/service/iam/authorize/match/condition/null/sim-iam-null.js +59 -0
  76. package/dist/service/iam/authorize/match/condition/numeric/less-than-equals/sim-iam-number-lte.d.ts +4 -1
  77. package/dist/service/iam/authorize/match/condition/numeric/less-than-equals/sim-iam-number-lte.js +6 -1
  78. package/dist/service/iam/authorize/match/condition/sim-iam-condition-operator-parser.js +2 -0
  79. package/dist/service/iam/authorize/match/condition/sim-iam-condition-operator.d.ts +9 -2
  80. package/dist/service/iam/authorize/match/condition/sim-iam-policy-condition-matcher.js +1 -1
  81. package/dist/service/iam/authorize/match/condition/string/all-values/sim-iam-for-all-values-string-condition-operator.d.ts +8 -1
  82. package/dist/service/iam/authorize/match/condition/string/all-values/sim-iam-for-all-values-string-condition-operator.js +10 -1
  83. package/dist/service/iam/authorize/match/condition/string/any-value/sim-iam-for-any-value-string-condition-operator.d.ts +4 -1
  84. package/dist/service/iam/authorize/match/condition/string/any-value/sim-iam-for-any-value-string-condition-operator.js +6 -1
  85. package/dist/service/iam/authorize/match/condition/string/sim-iam-scalar-string-condition-operator.d.ts +4 -1
  86. package/dist/service/iam/authorize/match/condition/string/sim-iam-scalar-string-condition-operator.js +6 -1
  87. package/docs/services/dynamodb/README.md +127 -0
  88. package/docs/services/iam/README.md +23 -3
  89. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { SimDynamoDbProjection } from "../../expression/projection/sim-dynamodb-projection.js";
1
+ import type { SimDynamoDbProjection } from "../../expression/projection/sim-dynamodb-projection.js";
2
2
  import type { SimDynamoDbItem } from "../../item/sim-dynamodb-item.js";
3
3
  import { SimDynamoDbConditionCheck } from "./sim-dynamodb-condition-check.js";
4
4
  import { type SimDynamoDbUpdateExpressionInput } from "./sim-dynamodb-update-expressions.js";
@@ -10,6 +10,12 @@ interface SimDynamoDbUpdatePlanInput extends SimDynamoDbUpdateExpressionInput {
10
10
  */
11
11
  export declare class SimDynamoDbUpdatePlan {
12
12
  readonly check: SimDynamoDbConditionCheck;
13
+ /**
14
+ * The top-level attributes both expressions named, for
15
+ * `dynamodb:Attributes`. They share one set of placeholders, so the update
16
+ * and the condition guarding it are gathered together.
17
+ */
18
+ readonly attributeNames: readonly string[];
13
19
  private readonly update;
14
20
  private constructor();
15
21
  /**
@@ -24,11 +30,7 @@ export declare class SimDynamoDbUpdatePlan {
24
30
  */
25
31
  assertLeavesKeyAlone(keyAttributeNames: readonly string[]): void;
26
32
  /**
27
- * The parts of an item this update touched, for the reporting modes that
28
- * answer with those and nothing else.
29
- *
30
- * A request that says nothing to change touched nothing, so the projection it
31
- * answers with finds nothing in either item.
33
+ * The parts of an item this update touched.
32
34
  */
33
35
  touched(): SimDynamoDbProjection;
34
36
  /**
@@ -1,5 +1,4 @@
1
- import { SimDynamoDbProjection } from "../../expression/projection/sim-dynamodb-projection.js";
2
- import { updateExpressionName } from "../../expression/update/sim-dynamodb-update-refusal.js";
1
+ import { simDynamoDbTouchedBy } from "./sim-dynamodb-update-touched.js";
3
2
  import { SimDynamoDbConditionCheck } from "./sim-dynamodb-condition-check.js";
4
3
  import { readSimDynamoDbUpdateExpressions, } from "./sim-dynamodb-update-expressions.js";
5
4
  /**
@@ -7,10 +6,17 @@ import { readSimDynamoDbUpdateExpressions, } from "./sim-dynamodb-update-express
7
6
  */
8
7
  export class SimDynamoDbUpdatePlan {
9
8
  check;
9
+ /**
10
+ * The top-level attributes both expressions named, for
11
+ * `dynamodb:Attributes`. They share one set of placeholders, so the update
12
+ * and the condition guarding it are gathered together.
13
+ */
14
+ attributeNames;
10
15
  update;
11
16
  constructor(properties) {
12
17
  this.update = properties.update;
13
18
  this.check = properties.check;
19
+ this.attributeNames = properties.attributeNames;
14
20
  }
15
21
  /**
16
22
  * Read the expressions a request carries, before anything is looked up.
@@ -21,15 +27,18 @@ export class SimDynamoDbUpdatePlan {
21
27
  static read(input, operation) {
22
28
  const expression = input.UpdateExpression;
23
29
  if (expression === undefined) {
30
+ const check = SimDynamoDbConditionCheck.read(input, operation);
24
31
  return new this({
25
32
  update: undefined,
26
- check: SimDynamoDbConditionCheck.read(input, operation),
33
+ check,
34
+ attributeNames: check.attributeNames,
27
35
  });
28
36
  }
29
37
  const read = readSimDynamoDbUpdateExpressions(input, expression);
30
38
  return new this({
31
39
  update: read.update,
32
40
  check: SimDynamoDbConditionCheck.of(read.condition, input, operation),
41
+ attributeNames: read.attributes,
33
42
  });
34
43
  }
35
44
  /**
@@ -39,18 +48,10 @@ export class SimDynamoDbUpdatePlan {
39
48
  this.update?.assertLeavesKeyAlone(keyAttributeNames);
40
49
  }
41
50
  /**
42
- * The parts of an item this update touched, for the reporting modes that
43
- * answer with those and nothing else.
44
- *
45
- * A request that says nothing to change touched nothing, so the projection it
46
- * answers with finds nothing in either item.
51
+ * The parts of an item this update touched.
47
52
  */
48
53
  touched() {
49
- return (this.update?.touched() ??
50
- new SimDynamoDbProjection({
51
- expressionName: updateExpressionName,
52
- paths: [],
53
- }));
54
+ return simDynamoDbTouchedBy(this.update);
54
55
  }
55
56
  /**
56
57
  * The item this update makes of the one that was there.
@@ -0,0 +1,10 @@
1
+ import { SimDynamoDbProjection } from "../../expression/projection/sim-dynamodb-projection.js";
2
+ import type { SimDynamoDbUpdate } from "../../expression/update/sim-dynamodb-update.js";
3
+ /**
4
+ * The parts of an item an update touched, for the reporting modes that answer
5
+ * with those and nothing else.
6
+ *
7
+ * A request that says nothing to change touched nothing, so the projection it
8
+ * answers with finds nothing in either item.
9
+ */
10
+ export declare function simDynamoDbTouchedBy(update: SimDynamoDbUpdate | undefined): SimDynamoDbProjection;
@@ -0,0 +1,16 @@
1
+ import { SimDynamoDbProjection } from "../../expression/projection/sim-dynamodb-projection.js";
2
+ import { updateExpressionName } from "../../expression/update/sim-dynamodb-update-refusal.js";
3
+ /**
4
+ * The parts of an item an update touched, for the reporting modes that answer
5
+ * with those and nothing else.
6
+ *
7
+ * A request that says nothing to change touched nothing, so the projection it
8
+ * answers with finds nothing in either item.
9
+ */
10
+ export function simDynamoDbTouchedBy(update) {
11
+ return (update?.touched() ??
12
+ new SimDynamoDbProjection({
13
+ expressionName: updateExpressionName,
14
+ paths: [],
15
+ }));
16
+ }
@@ -9,6 +9,8 @@ export interface SimDynamoDbQueryExpressions {
9
9
  readonly terms: SimDynamoDbKeyConditionTerms;
10
10
  readonly filter: SimDynamoDbFilter | undefined;
11
11
  readonly projection: SimDynamoDbProjection | undefined;
12
+ /** The top-level attributes the expressions named, for `dynamodb:Attributes`. */
13
+ readonly attributes: readonly string[];
12
14
  }
13
15
  /**
14
16
  * Read every expression of a query against one set of placeholders.
@@ -21,7 +21,12 @@ export function readSimDynamoDbQueryExpressions(input) {
21
21
  const filter = filterIn(input.FilterExpression, parameters);
22
22
  const projection = projectionIn(input.ProjectionExpression, parameters);
23
23
  parameters.assertAllUsed();
24
- return { terms, filter, projection };
24
+ return {
25
+ terms,
26
+ filter,
27
+ projection,
28
+ attributes: parameters.attributes.topLevel,
29
+ };
25
30
  }
26
31
  /**
27
32
  * Read the filter a query drops read items by, if it names one.
@@ -2,6 +2,7 @@ import { SimDynamoDbItemPage } from "../item/sim-dynamodb-item-page.js";
2
2
  import { SimDynamoDbReadAnswer } from "../read/sim-dynamodb-read-answer.js";
3
3
  import { assertSimDynamoDbConsistentReadAnswerable } from "../read/sim-dynamodb-consistent-read.js";
4
4
  import { SimDynamoDbSelect } from "../read/sim-dynamodb-select.js";
5
+ import { simDynamoDbLeadingKeyOf } from "../authorize/sim-dynamodb-leading-keys.js";
5
6
  import { readSimDynamoDbQueryExpressions } from "./sim-dynamodb-query-expressions.js";
6
7
  import { refuseSimDynamoDbQuerySegment } from "./sim-dynamodb-query-segment.js";
7
8
  import { readSimDynamoDbQueryStartKey } from "./sim-dynamodb-query-start-key.js";
@@ -30,7 +31,14 @@ export class SimDynamoDbQuery {
30
31
  refuseUnsimulatedQueryInput(input);
31
32
  refuseSimDynamoDbQuerySegment(input);
32
33
  const expressions = readSimDynamoDbQueryExpressions(input);
33
- const table = this.access.required("dynamodb:Query", input.TableName, options?.caller);
34
+ // The one partition key the query reads is what authorization needs, and
35
+ // reading it needs the view rather than the table, so it is read again
36
+ // here against whichever of the two the request names.
37
+ const table = this.access.required("dynamodb:Query", input.TableName, options?.caller, {
38
+ leadingKeys: (reached) => simDynamoDbLeadingKeyOf(expressions.terms.forTable(reached.view(input.IndexName))
39
+ .partitionKeyValue),
40
+ attributes: expressions.attributes,
41
+ });
34
42
  // What is being read is settled here: the table, or one of its indexes. An
35
43
  // IndexName the table does not have is refused rather than read as the
36
44
  // table. Everything after this asks the view rather than the table, so a
@@ -7,6 +7,8 @@ import type { SimScanCommandInput } from "./scan.command.js";
7
7
  export interface SimDynamoDbScanExpressions {
8
8
  readonly filter: SimDynamoDbFilter | undefined;
9
9
  readonly projection: SimDynamoDbProjection | undefined;
10
+ /** The top-level attributes the expressions named, for `dynamodb:Attributes`. */
11
+ readonly attributes: readonly string[];
10
12
  }
11
13
  /**
12
14
  * Read both expressions of a scan against one set of placeholders.
@@ -22,13 +22,13 @@ export function readSimDynamoDbScanExpressions(input) {
22
22
  if (input.FilterExpression === undefined &&
23
23
  input.ProjectionExpression === undefined) {
24
24
  SimDynamoDbExpressionParameters.assertNoneWithout(input);
25
- return { filter: undefined, projection: undefined };
25
+ return { filter: undefined, projection: undefined, attributes: [] };
26
26
  }
27
27
  const parameters = new SimDynamoDbExpressionParameters(input);
28
28
  const filter = filterIn(input.FilterExpression, parameters);
29
29
  const projection = projectionIn(input.ProjectionExpression, parameters);
30
30
  parameters.assertAllUsed();
31
- return { filter, projection };
31
+ return { filter, projection, attributes: parameters.attributes.topLevel };
32
32
  }
33
33
  /**
34
34
  * Read the filter a scan drops read items by, if it names one.
@@ -39,7 +39,7 @@ export class SimDynamoDbScan {
39
39
  // attribute, including a key attribute, and needs no key schema to check.
40
40
  const segment = readSimDynamoDbScanSegment(input);
41
41
  const expressions = readSimDynamoDbScanExpressions(input);
42
- const table = this.access.required("dynamodb:Scan", input.TableName, options?.caller);
42
+ const table = this.access.required("dynamodb:Scan", input.TableName, options?.caller, { attributes: expressions.attributes });
43
43
  // What is being read is settled here: the table, or one of its indexes.
44
44
  const view = table.view(input.IndexName);
45
45
  const scan = view.scan();
@@ -4,6 +4,7 @@ import type { SimDynamoDbTable } from "../../table/sim-dynamodb-table.js";
4
4
  import type { SimDynamoDbTableName } from "../../table/sim-dynamodb-table-name.js";
5
5
  import type { SimDynamoDbTableStore } from "../../table/sim-dynamodb-table-store.js";
6
6
  import type { SimDynamoDbAuthorizer } from "../authorize/sim-dynamodb-authorizer.js";
7
+ import type { SimDynamoDbTableReach } from "./sim-dynamodb-table-reach.js";
7
8
  interface SimDynamoDbTableAccessProperties {
8
9
  readonly tables: SimDynamoDbTableStore;
9
10
  readonly authorizer: SimDynamoDbAuthorizer;
@@ -14,9 +15,14 @@ interface SimDynamoDbTableAccessProperties {
14
15
  *
15
16
  * Every table command goes through the same two steps in the same order: read
16
17
  * the name or ARN the request carries, then authorize the caller against it
17
- * before anything looks the table up. Keeping them here is what makes that
18
- * order the same for all of them, so no command can accidentally tell an
19
- * unauthorized caller which table names are taken.
18
+ * before the command is told whether the table is there. Keeping them here is
19
+ * what makes that order the same for all of them, so no command can
20
+ * accidentally tell an unauthorized caller which table names are taken.
21
+ *
22
+ * A command reaching particular items hands over how to read their partition
23
+ * key values, which authorization needs the table to read. The table is found
24
+ * first for that, and a caller refused against a table that is not there still
25
+ * hears AccessDenied rather than a missing table.
20
26
  */
21
27
  export declare class SimDynamoDbTableAccess {
22
28
  private readonly tables;
@@ -28,13 +34,17 @@ export declare class SimDynamoDbTableAccess {
28
34
  */
29
35
  reference(tableName: string | undefined): SimDynamoDbTableName;
30
36
  /**
31
- * Find the table a request names, refusing the caller before looking it up.
37
+ * Find the table a request names, refusing the caller before answering.
32
38
  */
33
- required(action: string, tableName: string | undefined, caller: SimAwsCaller | undefined): SimDynamoDbTable;
39
+ required(action: string, tableName: string | undefined, caller: SimAwsCaller | undefined, reach?: SimDynamoDbTableReach): SimDynamoDbTable;
34
40
  /**
35
41
  * Find a table by a name that has already been read.
42
+ *
43
+ * A caller with no permission hears AccessDenied whether or not the table is
44
+ * there, which keeps an unauthorized caller from finding out which table
45
+ * names are taken.
36
46
  */
37
- requiredByName(action: string, name: SimDynamoDbTableName, caller: SimAwsCaller | undefined): SimDynamoDbTable;
47
+ requiredByName(action: string, name: SimDynamoDbTableName, caller: SimAwsCaller | undefined, reach?: SimDynamoDbTableReach): SimDynamoDbTable;
38
48
  /**
39
49
  * Ensure the caller may perform an action that names no particular table.
40
50
  */
@@ -1,13 +1,19 @@
1
1
  import { SimDynamoDbResourceNotFoundException } from "../../error/dynamodb.error.js";
2
2
  import { readSimDynamoDbTableReference } from "../../table/sim-dynamodb-table-reference.js";
3
+ import { simDynamoDbReachedIn } from "./sim-dynamodb-table-reach.js";
3
4
  /**
4
5
  * How a command reaches the table a request names.
5
6
  *
6
7
  * Every table command goes through the same two steps in the same order: read
7
8
  * the name or ARN the request carries, then authorize the caller against it
8
- * before anything looks the table up. Keeping them here is what makes that
9
- * order the same for all of them, so no command can accidentally tell an
10
- * unauthorized caller which table names are taken.
9
+ * before the command is told whether the table is there. Keeping them here is
10
+ * what makes that order the same for all of them, so no command can
11
+ * accidentally tell an unauthorized caller which table names are taken.
12
+ *
13
+ * A command reaching particular items hands over how to read their partition
14
+ * key values, which authorization needs the table to read. The table is found
15
+ * first for that, and a caller refused against a table that is not there still
16
+ * hears AccessDenied rather than a missing table.
11
17
  */
12
18
  export class SimDynamoDbTableAccess {
13
19
  tables;
@@ -25,17 +31,21 @@ export class SimDynamoDbTableAccess {
25
31
  return readSimDynamoDbTableReference(tableName, this.accountRegionScope);
26
32
  }
27
33
  /**
28
- * Find the table a request names, refusing the caller before looking it up.
34
+ * Find the table a request names, refusing the caller before answering.
29
35
  */
30
- required(action, tableName, caller) {
31
- return this.requiredByName(action, this.reference(tableName), caller);
36
+ required(action, tableName, caller, reach = {}) {
37
+ return this.requiredByName(action, this.reference(tableName), caller, reach);
32
38
  }
33
39
  /**
34
40
  * Find a table by a name that has already been read.
41
+ *
42
+ * A caller with no permission hears AccessDenied whether or not the table is
43
+ * there, which keeps an unauthorized caller from finding out which table
44
+ * names are taken.
35
45
  */
36
- requiredByName(action, name, caller) {
37
- this.authorizer.authorizeTable(action, name.value, caller);
46
+ requiredByName(action, name, caller, reach = {}) {
38
47
  const table = this.tables.find(name);
48
+ this.authorizer.authorizeTable(action, name.value, caller, simDynamoDbReachedIn(reach, table));
39
49
  if (table === undefined) {
40
50
  throw new SimDynamoDbResourceNotFoundException(`No DynamoDB Table named ${name.value}`);
41
51
  }
@@ -0,0 +1,25 @@
1
+ import type { SimDynamoDbReached } from "../authorize/sim-dynamodb-reached.js";
2
+ import type { SimDynamoDbLeadingKeys } from "../authorize/sim-dynamodb-leading-keys.js";
3
+ import type { SimDynamoDbTable } from "../../table/sim-dynamodb-table.js";
4
+ /**
5
+ * What one command's request reaches, for the condition keys authorization
6
+ * supplies.
7
+ *
8
+ * The partition key values need the table to read them, so they arrive as a
9
+ * function of it. The attribute names are read from the request's own
10
+ * parameters before the table is reached, so they arrive as they are.
11
+ */
12
+ export interface SimDynamoDbTableReach {
13
+ readonly leadingKeys?: SimDynamoDbLeadingKeys | undefined;
14
+ readonly attributes?: readonly string[] | undefined;
15
+ }
16
+ /**
17
+ * Resolve what a request reaches against the table it named.
18
+ *
19
+ * Authorization runs ahead of the checks a command makes on what it was given,
20
+ * as it does on AWS. A request whose key or key condition is malformed is
21
+ * authorized carrying no values and refused by the check that follows, so
22
+ * whatever reading them throws is dropped here. A table that is not there
23
+ * leaves the values unread, since the key schema is what reads them.
24
+ */
25
+ export declare function simDynamoDbReachedIn(reach: SimDynamoDbTableReach, table: SimDynamoDbTable | undefined): SimDynamoDbReached;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Resolve what a request reaches against the table it named.
3
+ *
4
+ * Authorization runs ahead of the checks a command makes on what it was given,
5
+ * as it does on AWS. A request whose key or key condition is malformed is
6
+ * authorized carrying no values and refused by the check that follows, so
7
+ * whatever reading them throws is dropped here. A table that is not there
8
+ * leaves the values unread, since the key schema is what reads them.
9
+ */
10
+ export function simDynamoDbReachedIn(reach, table) {
11
+ return {
12
+ leadingKeys: table === undefined ? undefined : leadingKeysIn(reach, table),
13
+ attributes: reach.attributes,
14
+ };
15
+ }
16
+ /**
17
+ * Read the partition key values a request reaches, or none where they cannot
18
+ * be read.
19
+ */
20
+ function leadingKeysIn(reach, table) {
21
+ try {
22
+ return reach.leadingKeys?.(table);
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
@@ -23,7 +23,7 @@ export class SimDynamoDbTransactRead {
23
23
  * Read the Get one action of a transactional read carries.
24
24
  */
25
25
  static of(request) {
26
- return new this(request.TableName, readSimDynamoDbKey(request.Key), readSimDynamoDbProjection(request));
26
+ return new this(request.TableName, readSimDynamoDbKey(request.Key), readSimDynamoDbProjection(request).projection);
27
27
  }
28
28
  /**
29
29
  * The primary key this Get reads, as the table marshals it.
@@ -4,13 +4,21 @@ import type { SimDynamoDbCondition } from "./sim-dynamodb-condition.js";
4
4
  interface SimDynamoDbConditionRequest extends SimDynamoDbExpressionParameterInput {
5
5
  readonly ConditionExpression?: string | undefined;
6
6
  }
7
+ /**
8
+ * What a request's ConditionExpression said, once it has been read.
9
+ */
10
+ export interface SimDynamoDbConditionRead {
11
+ readonly condition: SimDynamoDbCondition | undefined;
12
+ /** The top-level attributes the expression named, for `dynamodb:Attributes`. */
13
+ readonly attributes: readonly string[];
14
+ }
7
15
  /**
8
16
  * Read the condition a write is guarded by, if it names one.
9
17
  *
10
18
  * A request with no ConditionExpression is an unconditional write, so there is
11
19
  * nothing to check.
12
20
  */
13
- export declare function readSimDynamoDbCondition(request: SimDynamoDbConditionRequest): SimDynamoDbCondition | undefined;
21
+ export declare function readSimDynamoDbCondition(request: SimDynamoDbConditionRequest): SimDynamoDbConditionRead;
14
22
  /**
15
23
  * Read one ConditionExpression against placeholders that have already been
16
24
  * gathered.
@@ -11,12 +11,12 @@ export function readSimDynamoDbCondition(request) {
11
11
  const expression = request.ConditionExpression;
12
12
  if (expression === undefined) {
13
13
  SimDynamoDbExpressionParameters.assertNoneWithout(request);
14
- return undefined;
14
+ return { condition: undefined, attributes: [] };
15
15
  }
16
16
  const parameters = new SimDynamoDbExpressionParameters(request);
17
17
  const condition = parseSimDynamoDbCondition(expression, parameters);
18
18
  parameters.assertAllUsed();
19
- return condition;
19
+ return { condition, attributes: parameters.attributes.topLevel };
20
20
  }
21
21
  /**
22
22
  * Read one ConditionExpression against placeholders that have already been
@@ -10,7 +10,7 @@ import { SimDynamoDbConditionParser } from "./sim-dynamodb-condition-parser.js";
10
10
  export function simDynamoDbConditionParser(expressionName, expression, parameters) {
11
11
  return new SimDynamoDbConditionParser({
12
12
  tokens: SimDynamoDbExpressionTokens.of(expressionName, expression, "the expression says nothing, and an expression cannot be empty"),
13
- names: parameters.names,
13
+ attributes: parameters.attributes,
14
14
  values: parameters.values,
15
15
  });
16
16
  }
@@ -1,11 +1,12 @@
1
1
  import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
2
2
  import type { SimDynamoDbDocumentPath } from "../sim-dynamodb-document-path.js";
3
+ import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
3
4
  import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
4
5
  import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
5
6
  import { type SimDynamoDbConditionOperand, SimDynamoDbPathOperand } from "./sim-dynamodb-condition-operand.js";
6
7
  interface SimDynamoDbConditionOperandParserProperties {
7
8
  readonly tokens: SimDynamoDbExpressionTokens;
8
- readonly names: SimDynamoDbExpressionPlaceholders<string>;
9
+ readonly attributes: SimDynamoDbExpressionAttributes;
9
10
  readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
10
11
  }
11
12
  /**
@@ -17,7 +18,7 @@ interface SimDynamoDbConditionOperandParserProperties {
17
18
  */
18
19
  export declare class SimDynamoDbConditionOperandParser {
19
20
  private readonly tokens;
20
- private readonly names;
21
+ private readonly attributes;
21
22
  private readonly values;
22
23
  private readonly read;
23
24
  constructor(properties: SimDynamoDbConditionOperandParserProperties);
@@ -15,12 +15,12 @@ const sizeFunctionName = "size";
15
15
  */
16
16
  export class SimDynamoDbConditionOperandParser {
17
17
  tokens;
18
- names;
18
+ attributes;
19
19
  values;
20
20
  read = [];
21
21
  constructor(properties) {
22
22
  this.tokens = properties.tokens;
23
- this.names = properties.names;
23
+ this.attributes = properties.attributes;
24
24
  this.values = properties.values;
25
25
  }
26
26
  /**
@@ -87,7 +87,7 @@ export class SimDynamoDbConditionOperandParser {
87
87
  path() {
88
88
  const path = new SimDynamoDbDocumentPathParser({
89
89
  tokens: this.tokens,
90
- names: this.names,
90
+ attributes: this.attributes,
91
91
  }).parse();
92
92
  this.read.push(path);
93
93
  return new SimDynamoDbPathOperand(path);
@@ -1,11 +1,12 @@
1
1
  import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
2
2
  import type { SimDynamoDbDocumentPath } from "../sim-dynamodb-document-path.js";
3
+ import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
3
4
  import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
4
5
  import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
5
6
  import { type SimDynamoDbCondition } from "./sim-dynamodb-condition.js";
6
7
  interface SimDynamoDbConditionParserProperties {
7
8
  readonly tokens: SimDynamoDbExpressionTokens;
8
- readonly names: SimDynamoDbExpressionPlaceholders<string>;
9
+ readonly attributes: SimDynamoDbExpressionAttributes;
9
10
  readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
10
11
  }
11
12
  /**
@@ -21,7 +21,7 @@ export class SimDynamoDbConditionParser {
21
21
  constructor(properties) {
22
22
  const operands = new SimDynamoDbConditionOperandParser({
23
23
  tokens: properties.tokens,
24
- names: properties.names,
24
+ attributes: properties.attributes,
25
25
  values: properties.values,
26
26
  });
27
27
  this.tokens = properties.tokens;
@@ -22,7 +22,7 @@ export function readSimDynamoDbKeyCondition(request, parameters) {
22
22
  }
23
23
  const terms = new SimDynamoDbKeyConditionParser({
24
24
  tokens: SimDynamoDbExpressionTokens.of(keyConditionExpressionName, expression, "the expression says nothing, and an expression cannot be empty"),
25
- names: parameters.names,
25
+ attributes: parameters.attributes,
26
26
  values: parameters.values,
27
27
  }).parse();
28
28
  return new SimDynamoDbKeyConditionTerms(terms);
@@ -1,10 +1,11 @@
1
1
  import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
2
+ import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
2
3
  import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
3
4
  import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
4
5
  import { type SimDynamoDbKeyConditionRefusals } from "./sim-dynamodb-key-condition-refusals.js";
5
6
  interface SimDynamoDbKeyConditionOperandsProperties {
6
7
  readonly tokens: SimDynamoDbExpressionTokens;
7
- readonly names: SimDynamoDbExpressionPlaceholders<string>;
8
+ readonly attributes: SimDynamoDbExpressionAttributes;
8
9
  readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
9
10
  readonly refusals: SimDynamoDbKeyConditionRefusals;
10
11
  }
@@ -17,7 +18,7 @@ interface SimDynamoDbKeyConditionOperandsProperties {
17
18
  */
18
19
  export declare class SimDynamoDbKeyConditionOperands {
19
20
  private readonly tokens;
20
- private readonly names;
21
+ private readonly attributes;
21
22
  private readonly values;
22
23
  private readonly refusals;
23
24
  constructor(properties: SimDynamoDbKeyConditionOperandsProperties);
@@ -22,12 +22,12 @@ const keyComparators = new Set([
22
22
  */
23
23
  export class SimDynamoDbKeyConditionOperands {
24
24
  tokens;
25
- names;
25
+ attributes;
26
26
  values;
27
27
  refusals;
28
28
  constructor(properties) {
29
29
  this.tokens = properties.tokens;
30
- this.names = properties.names;
30
+ this.attributes = properties.attributes;
31
31
  this.values = properties.values;
32
32
  this.refusals = properties.refusals;
33
33
  }
@@ -77,9 +77,11 @@ export class SimDynamoDbKeyConditionOperands {
77
77
  * The attribute a name token stands for, which may be a placeholder.
78
78
  */
79
79
  nameOf(kind, text) {
80
- if (kind === "name") {
81
- return text;
82
- }
83
- return this.names.required(text);
80
+ const name = kind === "name" ? text : this.attributes.required(text);
81
+ // A key condition reads no document paths, so the attributes it reaches
82
+ // are noted here rather than by the path parser. A key is scalar, and the
83
+ // attribute a term names is always a top-level one.
84
+ this.attributes.reach(name);
85
+ return name;
84
86
  }
85
87
  }
@@ -1,10 +1,11 @@
1
1
  import type { SimDynamoDbValue } from "../../item/sim-dynamodb-value.js";
2
+ import type { SimDynamoDbExpressionAttributes } from "../sim-dynamodb-expression-attributes.js";
2
3
  import type { SimDynamoDbExpressionPlaceholders } from "../sim-dynamodb-expression-placeholders.js";
3
4
  import type { SimDynamoDbExpressionTokens } from "../sim-dynamodb-expression-tokens.js";
4
5
  import type { SimDynamoDbKeyConditionTerm } from "./sim-dynamodb-key-condition-term.js";
5
6
  interface SimDynamoDbKeyConditionParserProperties {
6
7
  readonly tokens: SimDynamoDbExpressionTokens;
7
- readonly names: SimDynamoDbExpressionPlaceholders<string>;
8
+ readonly attributes: SimDynamoDbExpressionAttributes;
8
9
  readonly values: SimDynamoDbExpressionPlaceholders<SimDynamoDbValue>;
9
10
  }
10
11
  /**
@@ -27,7 +27,7 @@ export class SimDynamoDbKeyConditionParser {
27
27
  this.refusals = refusals;
28
28
  this.operands = new SimDynamoDbKeyConditionOperands({
29
29
  tokens: properties.tokens,
30
- names: properties.names,
30
+ attributes: properties.attributes,
31
31
  values: properties.values,
32
32
  refusals,
33
33
  });
@@ -4,6 +4,14 @@ import { SimDynamoDbProjection } from "./sim-dynamodb-projection.js";
4
4
  interface SimDynamoDbProjectionRequest extends SimDynamoDbExpressionParameterInput {
5
5
  readonly ProjectionExpression?: string | undefined;
6
6
  }
7
+ /**
8
+ * What a request's ProjectionExpression said, once it has been read.
9
+ */
10
+ export interface SimDynamoDbProjectionRead {
11
+ readonly projection: SimDynamoDbProjection | undefined;
12
+ /** The top-level attributes the expression named, for `dynamodb:Attributes`. */
13
+ readonly attributes: readonly string[];
14
+ }
7
15
  /**
8
16
  * Read the projection a request asks for, if it asks for one.
9
17
  *
@@ -15,7 +23,7 @@ interface SimDynamoDbProjectionRequest extends SimDynamoDbExpressionParameterInp
15
23
  * carry a filter alongside its projection, and reads both against one set of
16
24
  * placeholders through `parseSimDynamoDbProjection`.
17
25
  */
18
- export declare function readSimDynamoDbProjection(request: SimDynamoDbProjectionRequest): SimDynamoDbProjection | undefined;
26
+ export declare function readSimDynamoDbProjection(request: SimDynamoDbProjectionRequest): SimDynamoDbProjectionRead;
19
27
  /**
20
28
  * Read one ProjectionExpression against placeholders that have already been
21
29
  * gathered.