@photon-grove/evt 0.0.0-stage → 0.1.0

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 (124) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +122 -2
  3. package/dist/aggregate.d.ts +83 -0
  4. package/dist/aggregate.d.ts.map +1 -0
  5. package/dist/aggregate.js +92 -0
  6. package/dist/aggregate.js.map +1 -0
  7. package/dist/base64.d.ts +8 -0
  8. package/dist/base64.d.ts.map +1 -0
  9. package/dist/base64.js +67 -0
  10. package/dist/base64.js.map +1 -0
  11. package/dist/codec.d.ts +56 -0
  12. package/dist/codec.d.ts.map +1 -0
  13. package/dist/codec.js +90 -0
  14. package/dist/codec.js.map +1 -0
  15. package/dist/commit-id.d.ts +3 -0
  16. package/dist/commit-id.d.ts.map +1 -0
  17. package/dist/commit-id.js +43 -0
  18. package/dist/commit-id.js.map +1 -0
  19. package/dist/dynamodb/head.d.ts +34 -0
  20. package/dist/dynamodb/head.d.ts.map +1 -0
  21. package/dist/dynamodb/head.js +62 -0
  22. package/dist/dynamodb/head.js.map +1 -0
  23. package/dist/dynamodb/index.d.ts +2 -0
  24. package/dist/dynamodb/index.d.ts.map +1 -0
  25. package/dist/dynamodb/index.js +4 -0
  26. package/dist/dynamodb/index.js.map +1 -0
  27. package/dist/dynamodb/item.d.ts +68 -0
  28. package/dist/dynamodb/item.d.ts.map +1 -0
  29. package/dist/dynamodb/item.js +263 -0
  30. package/dist/dynamodb/item.js.map +1 -0
  31. package/dist/envelope.d.ts +15 -0
  32. package/dist/envelope.d.ts.map +1 -0
  33. package/dist/envelope.js +59 -0
  34. package/dist/envelope.js.map +1 -0
  35. package/dist/errors.d.ts +111 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +139 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/event.d.ts +47 -0
  40. package/dist/event.d.ts.map +1 -0
  41. package/dist/event.js +64 -0
  42. package/dist/event.js.map +1 -0
  43. package/dist/fields.d.ts +31 -0
  44. package/dist/fields.d.ts.map +1 -0
  45. package/dist/fields.js +105 -0
  46. package/dist/fields.js.map +1 -0
  47. package/dist/index.d.ts +14 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +16 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/json.d.ts +47 -0
  52. package/dist/json.d.ts.map +1 -0
  53. package/dist/json.js +458 -0
  54. package/dist/json.js.map +1 -0
  55. package/dist/memory/index.d.ts +2 -0
  56. package/dist/memory/index.d.ts.map +1 -0
  57. package/dist/memory/index.js +3 -0
  58. package/dist/memory/index.js.map +1 -0
  59. package/dist/memory/repository.d.ts +34 -0
  60. package/dist/memory/repository.d.ts.map +1 -0
  61. package/dist/memory/repository.js +219 -0
  62. package/dist/memory/repository.js.map +1 -0
  63. package/dist/metadata.d.ts +47 -0
  64. package/dist/metadata.d.ts.map +1 -0
  65. package/dist/metadata.js +75 -0
  66. package/dist/metadata.js.map +1 -0
  67. package/dist/repository.d.ts +102 -0
  68. package/dist/repository.d.ts.map +1 -0
  69. package/dist/repository.js +131 -0
  70. package/dist/repository.js.map +1 -0
  71. package/dist/retry.d.ts +25 -0
  72. package/dist/retry.d.ts.map +1 -0
  73. package/dist/retry.js +50 -0
  74. package/dist/retry.js.map +1 -0
  75. package/dist/snapshots.d.ts +21 -0
  76. package/dist/snapshots.d.ts.map +1 -0
  77. package/dist/snapshots.js +35 -0
  78. package/dist/snapshots.js.map +1 -0
  79. package/dist/store.d.ts +103 -0
  80. package/dist/store.d.ts.map +1 -0
  81. package/dist/store.js +246 -0
  82. package/dist/store.js.map +1 -0
  83. package/dist/testing/equal.d.ts +22 -0
  84. package/dist/testing/equal.d.ts.map +1 -0
  85. package/dist/testing/equal.js +121 -0
  86. package/dist/testing/equal.js.map +1 -0
  87. package/dist/testing/index.d.ts +3 -0
  88. package/dist/testing/index.d.ts.map +1 -0
  89. package/dist/testing/index.js +5 -0
  90. package/dist/testing/index.js.map +1 -0
  91. package/dist/testing/scenario.d.ts +136 -0
  92. package/dist/testing/scenario.d.ts.map +1 -0
  93. package/dist/testing/scenario.js +307 -0
  94. package/dist/testing/scenario.js.map +1 -0
  95. package/dist/utf8.d.ts +17 -0
  96. package/dist/utf8.d.ts.map +1 -0
  97. package/dist/utf8.js +82 -0
  98. package/dist/utf8.js.map +1 -0
  99. package/package.json +56 -4
  100. package/src/aggregate.ts +196 -0
  101. package/src/base64.ts +80 -0
  102. package/src/codec.ts +139 -0
  103. package/src/commit-id.ts +50 -0
  104. package/src/dynamodb/head.ts +93 -0
  105. package/src/dynamodb/index.ts +21 -0
  106. package/src/dynamodb/item.ts +332 -0
  107. package/src/envelope.ts +67 -0
  108. package/src/errors.ts +214 -0
  109. package/src/event.ts +117 -0
  110. package/src/fields.ts +134 -0
  111. package/src/globals.d.ts +39 -0
  112. package/src/index.ts +75 -0
  113. package/src/json.ts +546 -0
  114. package/src/memory/index.ts +3 -0
  115. package/src/memory/repository.ts +313 -0
  116. package/src/metadata.ts +120 -0
  117. package/src/repository.ts +247 -0
  118. package/src/retry.ts +74 -0
  119. package/src/snapshots.ts +42 -0
  120. package/src/store.ts +377 -0
  121. package/src/testing/equal.ts +146 -0
  122. package/src/testing/index.ts +14 -0
  123. package/src/testing/scenario.ts +406 -0
  124. package/src/utf8.ts +92 -0
package/dist/codec.js ADDED
@@ -0,0 +1,90 @@
1
+ // Payload codecs: how an application turns event data and aggregate state into stored bytes and
2
+ // back. evt stores the bytes verbatim, so a codec owns their format.
3
+ import { EvtError, messageOf } from './errors.js';
4
+ import { JsonNumber, parseJson, stringifyJson } from './json.js';
5
+ import { utf8Decode, utf8Encode } from './utf8.js';
6
+ /**
7
+ * A JSON codec written with evt's encoder (the one Go's `encoding/json` output is reproduced
8
+ * with). Plain objects encode in property order.
9
+ *
10
+ * Decoding gives plain objects, arrays and numbers, so `T` must be plain JSON: a `Map`, a `bigint`
11
+ * or a `Date` doesn't decode back to itself. A domain that must match a Go or Rust one byte for
12
+ * byte, with a map whose keys are written sorted, needs a codec of its own that decodes the map as
13
+ * a `Map`. An integer past `Number.MAX_SAFE_INTEGER` is refused rather than rounded.
14
+ *
15
+ * Encoding refuses a value decoding would refuse, and with a `schema`, each value is validated
16
+ * before it's encoded and after it's decoded, so an event or a snapshot that couldn't be read back
17
+ * fails its commit instead of every later load. The schema must not transform values: the value
18
+ * is encoded as given.
19
+ */
20
+ export function json(options = {}) {
21
+ const schema = options.schema;
22
+ return {
23
+ encode(value) {
24
+ if (schema) {
25
+ validate(schema, value, 'invalidArgument');
26
+ }
27
+ const text = stringifyJson(value);
28
+ readable(text);
29
+ return utf8Encode(text);
30
+ },
31
+ decode(bytes) {
32
+ const value = plainJson(parseJson(utf8Decode(bytes, 'payload')));
33
+ return schema ? validate(schema, value, 'invalidRecord') : value;
34
+ },
35
+ };
36
+ }
37
+ /**
38
+ * A JSON value as plain JavaScript: objects as plain objects, numbers as `number`. An integer past
39
+ * the safe range is refused, because `number` would round it.
40
+ */
41
+ export function plainJson(value) {
42
+ if (value instanceof JsonNumber) {
43
+ const number = Number(value.text);
44
+ if (value.isInteger && !Number.isSafeInteger(number)) {
45
+ throw new EvtError('invalidRecord', `the integer ${value.text} is past the integers a number holds; decode it with a codec ` +
46
+ 'of its own');
47
+ }
48
+ return number;
49
+ }
50
+ if (Array.isArray(value)) {
51
+ return value.map(plainJson);
52
+ }
53
+ if (value instanceof Map) {
54
+ const object = {};
55
+ for (const [key, entry] of value) {
56
+ // defineProperty, so a "__proto__" key is a plain property and never a prototype.
57
+ Object.defineProperty(object, key, {
58
+ value: plainJson(entry),
59
+ enumerable: true,
60
+ writable: true,
61
+ configurable: true,
62
+ });
63
+ }
64
+ return object;
65
+ }
66
+ return value;
67
+ }
68
+ // Refuses JSON that decode would refuse, such as an integer past the safe range, so the value
69
+ // fails its commit instead of every later load.
70
+ function readable(text) {
71
+ try {
72
+ plainJson(parseJson(text));
73
+ }
74
+ catch (error) {
75
+ throw new EvtError('invalidArgument', messageOf(error), { cause: error });
76
+ }
77
+ }
78
+ function validate(schema, value, code) {
79
+ const result = schema['~standard'].validate(value);
80
+ if ('then' in result && typeof result.then === 'function') {
81
+ throw new EvtError('invalidArgument', 'a codec schema must validate synchronously');
82
+ }
83
+ const settled = result;
84
+ if (settled.issues) {
85
+ const issues = settled.issues.map((issue) => issue.message).join('; ');
86
+ throw new EvtError(code, `the payload does not match its schema: ${issues}`);
87
+ }
88
+ return settled.value;
89
+ }
90
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../src/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Makes a ULID-format commit ID generator that reads `clock` (Unix milliseconds). */
2
+ export declare function commitIds(clock: () => number): () => string;
3
+ //# sourceMappingURL=commit-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-id.d.ts","sourceRoot":"","sources":["../src/commit-id.ts"],"names":[],"mappings":"AAQA,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,MAAM,GAAG,MAAM,MAAM,CAwB3D"}
@@ -0,0 +1,43 @@
1
+ // Commit IDs for commits whose command carries none: ULID-format identifiers, 26 Crockford base32
2
+ // characters for a 48-bit millisecond timestamp and 80 random bits. IDs one generator makes in one
3
+ // millisecond increase, so they sort by creation time.
4
+ const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
5
+ const ENTROPY_MAX = (1n << 80n) - 1n;
6
+ const TIMESTAMP_MASK = (1n << 48n) - 1n;
7
+ /** Makes a ULID-format commit ID generator that reads `clock` (Unix milliseconds). */
8
+ export function commitIds(clock) {
9
+ let lastMs = -1n;
10
+ let entropy = 0n;
11
+ return () => {
12
+ // A clock that steps backwards keeps the last timestamp, so IDs never decrease.
13
+ let ms = BigInt(Math.max(0, Math.floor(clock()))) & TIMESTAMP_MASK;
14
+ if (ms < lastMs) {
15
+ ms = lastMs;
16
+ }
17
+ if (ms === lastMs && entropy < ENTROPY_MAX) {
18
+ entropy++;
19
+ }
20
+ else {
21
+ // A new millisecond, or 2^80 IDs in this one.
22
+ if (ms === lastMs) {
23
+ ms = (ms + 1n) & TIMESTAMP_MASK;
24
+ }
25
+ lastMs = ms;
26
+ entropy = randomEntropy();
27
+ }
28
+ return encode((ms << 80n) | entropy);
29
+ };
30
+ }
31
+ function randomEntropy() {
32
+ const bytes = crypto.getRandomValues(new Uint8Array(10));
33
+ return bytes.reduce((value, byte) => (value << 8n) | BigInt(byte), 0n);
34
+ }
35
+ function encode(value) {
36
+ let text = '';
37
+ for (let i = 0; i < 26; i++) {
38
+ text = ALPHABET[Number(value & 31n)] + text;
39
+ value >>= 5n;
40
+ }
41
+ return text;
42
+ }
43
+ //# sourceMappingURL=commit-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-id.js","sourceRoot":"","sources":["../src/commit-id.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,mGAAmG;AACnG,uDAAuD;AAEvD,MAAM,QAAQ,GAAG,kCAAkC,CAAA;AACnD,MAAM,WAAW,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,EAAE,CAAA;AACpC,MAAM,cAAc,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,EAAE,CAAA;AAEvC,sFAAsF;AACtF,MAAM,UAAU,SAAS,CAAC,KAAmB;IAC3C,IAAI,MAAM,GAAG,CAAC,EAAE,CAAA;IAChB,IAAI,OAAO,GAAG,EAAE,CAAA;IAEhB,OAAO,GAAG,EAAE;QACV,gFAAgF;QAChF,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,cAAc,CAAA;QAClE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;YAChB,EAAE,GAAG,MAAM,CAAA;QACb,CAAC;QAED,IAAI,EAAE,KAAK,MAAM,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;YAC3C,OAAO,EAAE,CAAA;QACX,CAAC;aAAM,CAAC;YACN,8CAA8C;YAC9C,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;gBAClB,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,cAAc,CAAA;YACjC,CAAC;YACD,MAAM,GAAG,EAAE,CAAA;YACX,OAAO,GAAG,aAAa,EAAE,CAAA;QAC3B,CAAC;QAED,OAAO,MAAM,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;IACtC,CAAC,CAAA;AACH,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IAExD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;AACxE,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,IAAI,GAAG,EAAE,CAAA;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,CAAE,GAAG,IAAI,CAAA;QAC5C,KAAK,KAAK,EAAE,CAAA;IACd,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,34 @@
1
+ /** The update expression of a head update on a stream without retention. */
2
+ export declare const HEAD_UPDATE = "SET head = :last";
3
+ /** The update expression of a head update on a stream with retention, which raises `ttl` too. */
4
+ export declare const HEAD_UPDATE_RETAINED = "SET head = :last, #ttl = :t";
5
+ /** The condition of the head update of a stream the commit creates (first sequence 1). */
6
+ export declare const HEAD_CREATE_CONDITION = "attribute_not_exists(head)";
7
+ /** The condition of the head update of an append: the head is the sequence before the first. */
8
+ export declare const HEAD_APPEND_CONDITION = "head = :prev";
9
+ /** {@link HEAD_APPEND_CONDITION} with retention: `ttl` is raised, never lowered. */
10
+ export declare const HEAD_APPEND_RETAINED_CONDITION = "head = :prev AND (attribute_not_exists(#ttl) OR #ttl <= :t)";
11
+ /** An `Update` or `ConditionCheck` on a stream's head item. */
12
+ export interface HeadAction {
13
+ entityId: string;
14
+ /** The update expression, or null for a `ConditionCheck`. */
15
+ updateExpression: string | null;
16
+ conditionExpression: string;
17
+ /** `ExpressionAttributeNames`: placeholder and attribute name. */
18
+ names: [string, string][];
19
+ /** `ExpressionAttributeValues`: placeholder and number. */
20
+ values: [string, bigint][];
21
+ }
22
+ /**
23
+ * The head update of a stream whose commit writes events `first` to `last`. A first sequence of 1
24
+ * creates the head. `ttl` is the `:t` of the never-lower rule, given only for a stream with
25
+ * retention.
26
+ */
27
+ export declare function headUpdate(entityId: string, first: bigint, last: bigint, ttl?: number): HeadAction;
28
+ /**
29
+ * An action's size in the commit budget, by the rule for any update, delete or condition check:
30
+ * its key attributes plus its expression strings, name placeholders (the placeholder and the
31
+ * name), and attribute values (the placeholder and the number's text).
32
+ */
33
+ export declare function headActionSize(action: HeadAction): number;
34
+ //# sourceMappingURL=head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../src/dynamodb/head.ts"],"names":[],"mappings":"AAQA,4EAA4E;AAC5E,eAAO,MAAM,WAAW,qBAAqB,CAAA;AAE7C,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,gCAAgC,CAAA;AAEjE,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,+BAA+B,CAAA;AAEjE,gGAAgG;AAChG,eAAO,MAAM,qBAAqB,iBAAiB,CAAA;AAEnD,oFAAoF;AACpF,eAAO,MAAM,8BAA8B,gEACoB,CAAA;AAE/D,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,6DAA6D;IAC7D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,kEAAkE;IAClE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;IACzB,2DAA2D;IAC3D,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,UAAU,CA0BZ;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAazD"}
@@ -0,0 +1,62 @@
1
+ // The DynamoDB actions on a stream's head item (ADR 0007), independent of any SDK: the one source
2
+ // of the head's expression strings, which the writer builds its actions from and the commit
3
+ // budget sizes. The fence and snapshot-guard forms join them with the DynamoDB backend.
4
+ import { safeIntegerArgument } from '../fields.js';
5
+ import { utf8Length } from '../utf8.js';
6
+ import { HEAD_SORT_KEY, itemSize } from './item.js';
7
+ /** The update expression of a head update on a stream without retention. */
8
+ export const HEAD_UPDATE = 'SET head = :last';
9
+ /** The update expression of a head update on a stream with retention, which raises `ttl` too. */
10
+ export const HEAD_UPDATE_RETAINED = 'SET head = :last, #ttl = :t';
11
+ /** The condition of the head update of a stream the commit creates (first sequence 1). */
12
+ export const HEAD_CREATE_CONDITION = 'attribute_not_exists(head)';
13
+ /** The condition of the head update of an append: the head is the sequence before the first. */
14
+ export const HEAD_APPEND_CONDITION = 'head = :prev';
15
+ /** {@link HEAD_APPEND_CONDITION} with retention: `ttl` is raised, never lowered. */
16
+ export const HEAD_APPEND_RETAINED_CONDITION = 'head = :prev AND (attribute_not_exists(#ttl) OR #ttl <= :t)';
17
+ /**
18
+ * The head update of a stream whose commit writes events `first` to `last`. A first sequence of 1
19
+ * creates the head. `ttl` is the `:t` of the never-lower rule, given only for a stream with
20
+ * retention.
21
+ */
22
+ export function headUpdate(entityId, first, last, ttl) {
23
+ const create = first <= 1n;
24
+ const values = [[':last', last]];
25
+ const names = [];
26
+ if (!create) {
27
+ values.push([':prev', first - 1n]);
28
+ }
29
+ if (ttl !== undefined) {
30
+ names.push(['#ttl', 'ttl']);
31
+ values.push([':t', BigInt(safeIntegerArgument(ttl, 'ttl'))]);
32
+ }
33
+ let conditionExpression = HEAD_CREATE_CONDITION;
34
+ if (!create) {
35
+ conditionExpression =
36
+ ttl === undefined ? HEAD_APPEND_CONDITION : HEAD_APPEND_RETAINED_CONDITION;
37
+ }
38
+ return {
39
+ entityId,
40
+ updateExpression: ttl === undefined ? HEAD_UPDATE : HEAD_UPDATE_RETAINED,
41
+ conditionExpression,
42
+ names,
43
+ values,
44
+ };
45
+ }
46
+ /**
47
+ * An action's size in the commit budget, by the rule for any update, delete or condition check:
48
+ * its key attributes plus its expression strings, name placeholders (the placeholder and the
49
+ * name), and attribute values (the placeholder and the number's text).
50
+ */
51
+ export function headActionSize(action) {
52
+ const key = itemSize({ pk: { S: action.entityId }, sk: { N: HEAD_SORT_KEY.toString() } });
53
+ let size = key + utf8Length(action.updateExpression ?? '') + utf8Length(action.conditionExpression);
54
+ for (const [placeholder, name] of action.names) {
55
+ size += utf8Length(placeholder) + utf8Length(name);
56
+ }
57
+ for (const [placeholder, number] of action.values) {
58
+ size += utf8Length(placeholder) + number.toString().length;
59
+ }
60
+ return size;
61
+ }
62
+ //# sourceMappingURL=head.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head.js","sourceRoot":"","sources":["../../src/dynamodb/head.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,4FAA4F;AAC5F,wFAAwF;AAExF,OAAO,EAAC,mBAAmB,EAAC,MAAM,cAAc,CAAA;AAChD,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AACrC,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAC,MAAM,WAAW,CAAA;AAEjD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAA;AAE7C,iGAAiG;AACjG,MAAM,CAAC,MAAM,oBAAoB,GAAG,6BAA6B,CAAA;AAEjE,0FAA0F;AAC1F,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAEjE,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAA;AAEnD,oFAAoF;AACpF,MAAM,CAAC,MAAM,8BAA8B,GACzC,6DAA6D,CAAA;AAc/D;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,QAAgB,EAChB,KAAa,EACb,IAAY,EACZ,GAAY;IAEZ,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAuB,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IACpD,MAAM,KAAK,GAAuB,EAAE,CAAA;IAEpC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC,CAAA;IACpC,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,mBAAmB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,mBAAmB,GAAG,qBAAqB,CAAA;IAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,mBAAmB;YACjB,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,8BAA8B,CAAA;IAC9E,CAAC;IAED,OAAO;QACL,QAAQ;QACR,gBAAgB,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB;QACxE,mBAAmB;QACnB,KAAK;QACL,MAAM;KACP,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAC,EAAE,EAAE,EAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,EAAC,EAAE,EAAE,EAAE,EAAC,CAAC,EAAE,aAAa,CAAC,QAAQ,EAAE,EAAC,EAAC,CAAC,CAAA;IACnF,IAAI,IAAI,GACN,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAE1F,KAAK,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/C,IAAI,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;IACpD,CAAC;IACD,KAAK,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClD,IAAI,IAAI,UAAU,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAA;IAC5D,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { type AttributeValue, type Item, DEFAULT_VIEW_SORT_KEY, HEAD_SORT_KEY, SNAPSHOT_SORT_KEY, eventFromItem, eventItem, expiry, headFromItem, headItem, isSnapshotItem, itemSize, snapshotFromItem, snapshotItem, sortKey, viewItem, } from './item.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dynamodb/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,IAAI,EACT,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,QAAQ,GACT,MAAM,WAAW,CAAA"}
@@ -0,0 +1,4 @@
1
+ // @photon-grove/evt/dynamodb: the DynamoDB backend. So far it holds the item codec, which imports
2
+ // nothing from the AWS SDK.
3
+ export { DEFAULT_VIEW_SORT_KEY, HEAD_SORT_KEY, SNAPSHOT_SORT_KEY, eventFromItem, eventItem, expiry, headFromItem, headItem, isSnapshotItem, itemSize, snapshotFromItem, snapshotItem, sortKey, viewItem, } from './item.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dynamodb/index.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,4BAA4B;AAE5B,OAAO,EAGL,qBAAqB,EACrB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,QAAQ,GACT,MAAM,WAAW,CAAA"}
@@ -0,0 +1,68 @@
1
+ import { type SerializedEvent, type SerializedSnapshot } from '../event.js';
2
+ /** A DynamoDB attribute value, shaped like the SDK's `AttributeValue`. */
3
+ export type AttributeValue = {
4
+ S: string;
5
+ } | {
6
+ N: string;
7
+ } | {
8
+ B: Uint8Array;
9
+ } | {
10
+ BOOL: boolean;
11
+ } | {
12
+ NULL: boolean;
13
+ } | {
14
+ M: Item;
15
+ } | {
16
+ L: AttributeValue[];
17
+ } | {
18
+ SS: string[];
19
+ } | {
20
+ NS: string[];
21
+ } | {
22
+ BS: Uint8Array[];
23
+ };
24
+ /** A DynamoDB item. */
25
+ export type Item = Record<string, AttributeValue>;
26
+ /** The sort key of a stream's inline snapshot. */
27
+ export declare const SNAPSHOT_SORT_KEY = 0n;
28
+ /** The sort key of a stream's head item. */
29
+ export declare const HEAD_SORT_KEY = -1n;
30
+ /** The sort key of a single-item view row. */
31
+ export declare const DEFAULT_VIEW_SORT_KEY = "VIEW";
32
+ /** Encodes an event as an event-log item. `ttl` (Unix seconds) is written only when positive. */
33
+ export declare function eventItem(event: SerializedEvent, ttl?: number): Item;
34
+ /** Encodes a stream's inline snapshot item. `ttl` is written only when positive. */
35
+ export declare function snapshotItem(snapshot: SerializedSnapshot, ttl?: number): Item;
36
+ /** Encodes a stream's head item. `ttl` is written only when positive. */
37
+ export declare function headItem(entityId: string, head: bigint, ttl?: number): Item;
38
+ /** Encodes a single-item view row: `pk = {entityType}#{entityId}`, `sk = "VIEW"`. */
39
+ export declare function viewItem(entityType: string, entityId: string, payload: Uint8Array): Item;
40
+ /**
41
+ * Decodes an event-log item. Missing attributes other than the key are empty, and `metadata` must
42
+ * be present and not blank. A JSON `null` metadata is the zero value, as in Go.
43
+ */
44
+ export declare function eventFromItem(item: Item): SerializedEvent;
45
+ /** Decodes a stream's inline snapshot item. */
46
+ export declare function snapshotFromItem(item: Item): SerializedSnapshot;
47
+ /** Decodes a head item into its head and its `ttl`, if it has one. */
48
+ export declare function headFromItem(item: Item): {
49
+ head: bigint;
50
+ ttl: number | undefined;
51
+ };
52
+ /** Whether an item is a stream's inline snapshot (`sk = 0`). */
53
+ export declare function isSnapshotItem(item: Item): boolean;
54
+ /** An item's numeric sort key, if it has one. */
55
+ export declare function sortKey(item: Item): bigint | undefined;
56
+ /**
57
+ * The `ttl` of an item written at `nowMs` (Unix milliseconds) under a retention of `retentionMs`:
58
+ * their sum in whole Unix seconds, rounded down after adding, as Go's `Time.Add(...).Unix()` is.
59
+ * Undefined, so no `ttl` is written, for a zero retention. A retention with a fraction of a
60
+ * millisecond is refused, because Go would count it.
61
+ */
62
+ export declare function expiry(nowMs: number, retentionMs: number): number | undefined;
63
+ /**
64
+ * The size DynamoDB counts for an item: each attribute's name plus its value, in UTF-8 bytes. The
65
+ * commit budget measures every action with it.
66
+ */
67
+ export declare function itemSize(item: Item): number;
68
+ //# sourceMappingURL=item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/dynamodb/item.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAC,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAU,MAAM,aAAa,CAAA;AAalF,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GACtB;IAAC,CAAC,EAAE,MAAM,CAAA;CAAC,GACX;IAAC,CAAC,EAAE,MAAM,CAAA;CAAC,GACX;IAAC,CAAC,EAAE,UAAU,CAAA;CAAC,GACf;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GACf;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GACf;IAAC,CAAC,EAAE,IAAI,CAAA;CAAC,GACT;IAAC,CAAC,EAAE,cAAc,EAAE,CAAA;CAAC,GACrB;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAC,GACd;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAC,GACd;IAAC,EAAE,EAAE,UAAU,EAAE,CAAA;CAAC,CAAA;AAEtB,uBAAuB;AACvB,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;AAEjD,kDAAkD;AAClD,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAEnC,4CAA4C;AAC5C,eAAO,MAAM,aAAa,MAAM,CAAA;AAEhC,8CAA8C;AAC9C,eAAO,MAAM,qBAAqB,SAAS,CAAA;AAE3C,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAapE;AAED,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,kBAAkB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAY7E;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ3E;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAQxF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,CA0BzD;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,kBAAkB,CAQ/D;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAC,CAOhF;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAElD;AAED,iDAAiD;AACjD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAOtD;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAa7E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAO3C"}
@@ -0,0 +1,263 @@
1
+ // The DynamoDB item layout of the event log. It's pure: it shapes items the way the AWS SDK's
2
+ // low-level client takes them, and imports nothing from the SDK.
3
+ //
4
+ // | Attribute | Type | Event item | Snapshot item (sk 0) | Head item (sk -1) |
5
+ // | ------------ | ---- | -------------- | -------------------- | ----------------- |
6
+ // | `pk` | S | entity ID | entity ID | entity ID |
7
+ // | `sk` | N | event sequence | `0` | `-1` |
8
+ // | `type` | S | event type | | |
9
+ // | `version` | N | event version | | |
10
+ // | `entityType` | S | entity type | entity type | |
11
+ // | `payload` | S | payload JSON | state JSON | |
12
+ // | `metadata` | S | metadata JSON | | |
13
+ // | `seq` | N | | snapshot sequence | |
14
+ // | `eventSeq` | N | | last event folded in | |
15
+ // | `head` | N | | | highest sequence |
16
+ // | `ttl` | N | optional | optional | optional |
17
+ import { eventId } from '../event.js';
18
+ import { EvtError } from '../errors.js';
19
+ import { DOCUMENT, checkInt64, int64Argument, invalid, safeIntegerArgument, } from '../fields.js';
20
+ import { parseJson } from '../json.js';
21
+ import { encodeMetadata, metadataFromJson } from '../metadata.js';
22
+ import { utf8Decode, utf8Encode, utf8Length } from '../utf8.js';
23
+ /** The sort key of a stream's inline snapshot. */
24
+ export const SNAPSHOT_SORT_KEY = 0n;
25
+ /** The sort key of a stream's head item. */
26
+ export const HEAD_SORT_KEY = -1n;
27
+ /** The sort key of a single-item view row. */
28
+ export const DEFAULT_VIEW_SORT_KEY = 'VIEW';
29
+ /** Encodes an event as an event-log item. `ttl` (Unix seconds) is written only when positive. */
30
+ export function eventItem(event, ttl) {
31
+ return withTtl({
32
+ pk: { S: event.entityId },
33
+ sk: { N: int64Argument(event.sequence, 'event.sequence').toString() },
34
+ type: { S: event.type },
35
+ version: { N: safeIntegerArgument(event.version, 'event.version').toString() },
36
+ entityType: { S: event.entityType },
37
+ payload: { S: payloadText(event.payload, 'event payload') },
38
+ metadata: { S: encodeMetadata(event.metadata) },
39
+ }, ttl);
40
+ }
41
+ /** Encodes a stream's inline snapshot item. `ttl` is written only when positive. */
42
+ export function snapshotItem(snapshot, ttl) {
43
+ return withTtl({
44
+ pk: { S: snapshot.entityId },
45
+ sk: { N: SNAPSHOT_SORT_KEY.toString() },
46
+ seq: { N: int64Argument(snapshot.sequence, 'snapshot.sequence').toString() },
47
+ eventSeq: { N: int64Argument(snapshot.eventSequence, 'snapshot.eventSequence').toString() },
48
+ entityType: { S: snapshot.entityType },
49
+ payload: { S: payloadText(snapshot.payload, 'snapshot payload') },
50
+ }, ttl);
51
+ }
52
+ /** Encodes a stream's head item. `ttl` is written only when positive. */
53
+ export function headItem(entityId, head, ttl) {
54
+ const item = {
55
+ pk: { S: entityId },
56
+ sk: { N: HEAD_SORT_KEY.toString() },
57
+ head: { N: int64Argument(head, 'head').toString() },
58
+ };
59
+ return withTtl(item, ttl);
60
+ }
61
+ /** Encodes a single-item view row: `pk = {entityType}#{entityId}`, `sk = "VIEW"`. */
62
+ export function viewItem(entityType, entityId, payload) {
63
+ return {
64
+ pk: { S: `${entityType}#${entityId}` },
65
+ sk: { S: DEFAULT_VIEW_SORT_KEY },
66
+ entityID: { S: entityId },
67
+ entityType: { S: entityType },
68
+ payload: { S: payloadText(payload, 'view payload') },
69
+ };
70
+ }
71
+ /**
72
+ * Decodes an event-log item. Missing attributes other than the key are empty, and `metadata` must
73
+ * be present and not blank. A JSON `null` metadata is the zero value, as in Go.
74
+ */
75
+ export function eventFromItem(item) {
76
+ const entityId = requiredString(item, 'pk');
77
+ const sequence = requiredNumber(item, 'sk');
78
+ const id = eventId(entityId, sequence);
79
+ const metadata = optionalString(item, 'metadata') ?? '';
80
+ if (metadata.trim() === '') {
81
+ throw invalid(`event ${id} has empty metadata`);
82
+ }
83
+ let decoded;
84
+ try {
85
+ decoded = metadataFromJson(parseJson(metadata, DOCUMENT));
86
+ }
87
+ catch (error) {
88
+ throw new EvtError('invalidRecord', `event ${id} metadata: ${message(error)}`, { cause: error });
89
+ }
90
+ return {
91
+ id,
92
+ sequence,
93
+ type: optionalString(item, 'type') ?? '',
94
+ version: safeInteger(optionalNumber(item, 'version') ?? 0n, 'version'),
95
+ entityId,
96
+ entityType: optionalString(item, 'entityType') ?? '',
97
+ payload: utf8Encode(optionalString(item, 'payload') ?? ''),
98
+ metadata: decoded,
99
+ };
100
+ }
101
+ /** Decodes a stream's inline snapshot item. */
102
+ export function snapshotFromItem(item) {
103
+ return {
104
+ entityType: optionalString(item, 'entityType') ?? '',
105
+ entityId: requiredString(item, 'pk'),
106
+ sequence: optionalNumber(item, 'seq') ?? 0n,
107
+ eventSequence: optionalNumber(item, 'eventSeq') ?? 0n,
108
+ payload: utf8Encode(optionalString(item, 'payload') ?? ''),
109
+ };
110
+ }
111
+ /** Decodes a head item into its head and its `ttl`, if it has one. */
112
+ export function headFromItem(item) {
113
+ const ttl = optionalNumber(item, 'ttl');
114
+ return {
115
+ head: requiredNumber(item, 'head'),
116
+ ttl: ttl === undefined ? undefined : safeInteger(ttl, 'ttl'),
117
+ };
118
+ }
119
+ /** Whether an item is a stream's inline snapshot (`sk = 0`). */
120
+ export function isSnapshotItem(item) {
121
+ return sortKey(item) === SNAPSHOT_SORT_KEY;
122
+ }
123
+ /** An item's numeric sort key, if it has one. */
124
+ export function sortKey(item) {
125
+ const sk = item['sk'];
126
+ if (sk === undefined || !('N' in sk)) {
127
+ return undefined;
128
+ }
129
+ return parseNumber(sk.N);
130
+ }
131
+ /**
132
+ * The `ttl` of an item written at `nowMs` (Unix milliseconds) under a retention of `retentionMs`:
133
+ * their sum in whole Unix seconds, rounded down after adding, as Go's `Time.Add(...).Unix()` is.
134
+ * Undefined, so no `ttl` is written, for a zero retention. A retention with a fraction of a
135
+ * millisecond is refused, because Go would count it.
136
+ */
137
+ export function expiry(nowMs, retentionMs) {
138
+ if (!Number.isSafeInteger(nowMs) || !Number.isSafeInteger(retentionMs) || retentionMs < 0) {
139
+ throw new EvtError('invalidArgument', 'the clock and the retention must be whole, non-negative milliseconds: ' +
140
+ `${nowMs}, ${retentionMs}`);
141
+ }
142
+ if (retentionMs === 0) {
143
+ return undefined;
144
+ }
145
+ return Math.floor((nowMs + retentionMs) / 1000);
146
+ }
147
+ /**
148
+ * The size DynamoDB counts for an item: each attribute's name plus its value, in UTF-8 bytes. The
149
+ * commit budget measures every action with it.
150
+ */
151
+ export function itemSize(item) {
152
+ let size = 0;
153
+ for (const [name, value] of Object.entries(item)) {
154
+ size += utf8Length(name) + valueSize(value);
155
+ }
156
+ return size;
157
+ }
158
+ function valueSize(value) {
159
+ if ('S' in value) {
160
+ return utf8Length(value.S);
161
+ }
162
+ if ('N' in value) {
163
+ return utf8Length(value.N);
164
+ }
165
+ if ('B' in value) {
166
+ return value.B.length;
167
+ }
168
+ if ('BOOL' in value || 'NULL' in value) {
169
+ return 1;
170
+ }
171
+ if ('M' in value) {
172
+ return 3 + itemSize(value.M) + Object.keys(value.M).length;
173
+ }
174
+ if ('L' in value) {
175
+ return value.L.reduce((size, entry) => size + 1 + valueSize(entry), 3);
176
+ }
177
+ if ('SS' in value) {
178
+ return value.SS.reduce((size, entry) => size + utf8Length(entry), 0);
179
+ }
180
+ if ('NS' in value) {
181
+ return value.NS.reduce((size, entry) => size + utf8Length(entry), 0);
182
+ }
183
+ return value.BS.reduce((size, entry) => size + entry.length, 0);
184
+ }
185
+ function withTtl(item, ttl) {
186
+ if (ttl !== undefined && safeIntegerArgument(ttl, 'ttl') > 0) {
187
+ item['ttl'] = { N: ttl.toString() };
188
+ }
189
+ return item;
190
+ }
191
+ // A payload is stored as a DynamoDB string, so it must be UTF-8. A null payload is stored empty.
192
+ function payloadText(payload, what) {
193
+ if (payload === null) {
194
+ return '';
195
+ }
196
+ try {
197
+ return utf8Decode(payload, what);
198
+ }
199
+ catch (error) {
200
+ const reason = `${what} is not valid UTF-8 and cannot be stored as a string`;
201
+ throw new EvtError('invalidArgument', reason, { cause: error });
202
+ }
203
+ }
204
+ function requiredString(item, name) {
205
+ const value = optionalString(item, name);
206
+ if (value === undefined) {
207
+ throw invalid(`item has no ${name} attribute`);
208
+ }
209
+ return value;
210
+ }
211
+ function requiredNumber(item, name) {
212
+ const value = optionalNumber(item, name);
213
+ if (value === undefined) {
214
+ throw invalid(`item has no ${name} attribute`);
215
+ }
216
+ return value;
217
+ }
218
+ function optionalString(item, name) {
219
+ const value = item[name];
220
+ if (value === undefined || 'NULL' in value) {
221
+ return undefined;
222
+ }
223
+ if (!('S' in value)) {
224
+ throw invalid(`attribute ${name} is not a string`);
225
+ }
226
+ return value.S;
227
+ }
228
+ function optionalNumber(item, name) {
229
+ const value = item[name];
230
+ if (value === undefined || 'NULL' in value) {
231
+ return undefined;
232
+ }
233
+ if (!('N' in value)) {
234
+ throw invalid(`attribute ${name} is not a number`);
235
+ }
236
+ const number = parseNumber(value.N);
237
+ if (number === undefined) {
238
+ throw invalid(`attribute ${name} is not an integer: ${value.N}`);
239
+ }
240
+ return number;
241
+ }
242
+ // An int64 in decimal, as strconv.ParseInt reads it: an optional sign, then digits.
243
+ function parseNumber(text) {
244
+ if (!/^[+-]?\d+$/.test(text)) {
245
+ return undefined;
246
+ }
247
+ try {
248
+ return checkInt64(BigInt(text), 'number');
249
+ }
250
+ catch {
251
+ return undefined;
252
+ }
253
+ }
254
+ function safeInteger(value, name) {
255
+ if (value < BigInt(Number.MIN_SAFE_INTEGER) || value > BigInt(Number.MAX_SAFE_INTEGER)) {
256
+ throw invalid(`attribute ${name} is ${value}, past the integers it holds`);
257
+ }
258
+ return Number(value);
259
+ }
260
+ function message(error) {
261
+ return error instanceof Error ? error.message : String(error);
262
+ }
263
+ //# sourceMappingURL=item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"item.js","sourceRoot":"","sources":["../../src/dynamodb/item.ts"],"names":[],"mappings":"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"}