@photon-grove/evt 0.0.0 → 0.1.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 (149) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +164 -1
  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/client.d.ts +83 -0
  20. package/dist/dynamodb/client.d.ts.map +1 -0
  21. package/dist/dynamodb/client.js +6 -0
  22. package/dist/dynamodb/client.js.map +1 -0
  23. package/dist/dynamodb/head.d.ts +34 -0
  24. package/dist/dynamodb/head.d.ts.map +1 -0
  25. package/dist/dynamodb/head.js +62 -0
  26. package/dist/dynamodb/head.js.map +1 -0
  27. package/dist/dynamodb/index.d.ts +6 -0
  28. package/dist/dynamodb/index.d.ts.map +1 -0
  29. package/dist/dynamodb/index.js +8 -0
  30. package/dist/dynamodb/index.js.map +1 -0
  31. package/dist/dynamodb/item.d.ts +70 -0
  32. package/dist/dynamodb/item.d.ts.map +1 -0
  33. package/dist/dynamodb/item.js +264 -0
  34. package/dist/dynamodb/item.js.map +1 -0
  35. package/dist/dynamodb/marker.d.ts +11 -0
  36. package/dist/dynamodb/marker.d.ts.map +1 -0
  37. package/dist/dynamodb/marker.js +56 -0
  38. package/dist/dynamodb/marker.js.map +1 -0
  39. package/dist/dynamodb/repository.d.ts +61 -0
  40. package/dist/dynamodb/repository.d.ts.map +1 -0
  41. package/dist/dynamodb/repository.js +731 -0
  42. package/dist/dynamodb/repository.js.map +1 -0
  43. package/dist/dynamodb/requests.d.ts +65 -0
  44. package/dist/dynamodb/requests.d.ts.map +1 -0
  45. package/dist/dynamodb/requests.js +179 -0
  46. package/dist/dynamodb/requests.js.map +1 -0
  47. package/dist/envelope.d.ts +15 -0
  48. package/dist/envelope.d.ts.map +1 -0
  49. package/dist/envelope.js +59 -0
  50. package/dist/envelope.js.map +1 -0
  51. package/dist/errors.d.ts +205 -0
  52. package/dist/errors.d.ts.map +1 -0
  53. package/dist/errors.js +240 -0
  54. package/dist/errors.js.map +1 -0
  55. package/dist/event.d.ts +47 -0
  56. package/dist/event.d.ts.map +1 -0
  57. package/dist/event.js +64 -0
  58. package/dist/event.js.map +1 -0
  59. package/dist/features.d.ts +55 -0
  60. package/dist/features.d.ts.map +1 -0
  61. package/dist/features.js +126 -0
  62. package/dist/features.js.map +1 -0
  63. package/dist/fields.d.ts +31 -0
  64. package/dist/fields.d.ts.map +1 -0
  65. package/dist/fields.js +105 -0
  66. package/dist/fields.js.map +1 -0
  67. package/dist/index.d.ts +15 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +17 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/json.d.ts +47 -0
  72. package/dist/json.d.ts.map +1 -0
  73. package/dist/json.js +458 -0
  74. package/dist/json.js.map +1 -0
  75. package/dist/memory/index.d.ts +2 -0
  76. package/dist/memory/index.d.ts.map +1 -0
  77. package/dist/memory/index.js +3 -0
  78. package/dist/memory/index.js.map +1 -0
  79. package/dist/memory/repository.d.ts +70 -0
  80. package/dist/memory/repository.d.ts.map +1 -0
  81. package/dist/memory/repository.js +308 -0
  82. package/dist/memory/repository.js.map +1 -0
  83. package/dist/metadata.d.ts +47 -0
  84. package/dist/metadata.d.ts.map +1 -0
  85. package/dist/metadata.js +75 -0
  86. package/dist/metadata.js.map +1 -0
  87. package/dist/repository.d.ts +131 -0
  88. package/dist/repository.d.ts.map +1 -0
  89. package/dist/repository.js +130 -0
  90. package/dist/repository.js.map +1 -0
  91. package/dist/retry.d.ts +25 -0
  92. package/dist/retry.d.ts.map +1 -0
  93. package/dist/retry.js +50 -0
  94. package/dist/retry.js.map +1 -0
  95. package/dist/snapshots.d.ts +21 -0
  96. package/dist/snapshots.d.ts.map +1 -0
  97. package/dist/snapshots.js +35 -0
  98. package/dist/snapshots.js.map +1 -0
  99. package/dist/store.d.ts +103 -0
  100. package/dist/store.d.ts.map +1 -0
  101. package/dist/store.js +246 -0
  102. package/dist/store.js.map +1 -0
  103. package/dist/testing/equal.d.ts +22 -0
  104. package/dist/testing/equal.d.ts.map +1 -0
  105. package/dist/testing/equal.js +121 -0
  106. package/dist/testing/equal.js.map +1 -0
  107. package/dist/testing/index.d.ts +3 -0
  108. package/dist/testing/index.d.ts.map +1 -0
  109. package/dist/testing/index.js +5 -0
  110. package/dist/testing/index.js.map +1 -0
  111. package/dist/testing/scenario.d.ts +136 -0
  112. package/dist/testing/scenario.d.ts.map +1 -0
  113. package/dist/testing/scenario.js +307 -0
  114. package/dist/testing/scenario.js.map +1 -0
  115. package/dist/utf8.d.ts +17 -0
  116. package/dist/utf8.d.ts.map +1 -0
  117. package/dist/utf8.js +82 -0
  118. package/dist/utf8.js.map +1 -0
  119. package/package.json +58 -2
  120. package/src/aggregate.ts +196 -0
  121. package/src/base64.ts +80 -0
  122. package/src/codec.ts +139 -0
  123. package/src/commit-id.ts +50 -0
  124. package/src/dynamodb/client.ts +102 -0
  125. package/src/dynamodb/head.ts +93 -0
  126. package/src/dynamodb/index.ts +45 -0
  127. package/src/dynamodb/item.ts +334 -0
  128. package/src/dynamodb/marker.ts +64 -0
  129. package/src/dynamodb/repository.ts +1030 -0
  130. package/src/dynamodb/requests.ts +256 -0
  131. package/src/envelope.ts +67 -0
  132. package/src/errors.ts +365 -0
  133. package/src/event.ts +117 -0
  134. package/src/features.ts +175 -0
  135. package/src/fields.ts +134 -0
  136. package/src/globals.d.ts +39 -0
  137. package/src/index.ts +98 -0
  138. package/src/json.ts +546 -0
  139. package/src/memory/index.ts +11 -0
  140. package/src/memory/repository.ts +463 -0
  141. package/src/metadata.ts +120 -0
  142. package/src/repository.ts +275 -0
  143. package/src/retry.ts +74 -0
  144. package/src/snapshots.ts +42 -0
  145. package/src/store.ts +377 -0
  146. package/src/testing/equal.ts +146 -0
  147. package/src/testing/index.ts +14 -0
  148. package/src/testing/scenario.ts +406 -0
  149. package/src/utf8.ts +92 -0
@@ -0,0 +1,56 @@
1
+ import { type JsonValue } from './json.js';
2
+ /** Encodes values of `T` to stored bytes and decodes them back. */
3
+ export interface Codec<T> {
4
+ encode(value: T): Uint8Array;
5
+ decode(bytes: Uint8Array): T;
6
+ }
7
+ /**
8
+ * The part of a [Standard Schema](https://standardschema.dev) validator evt calls, so Zod,
9
+ * Valibot, ArkType and the rest work without evt depending on any of them.
10
+ */
11
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
12
+ readonly '~standard': {
13
+ readonly version: 1;
14
+ readonly vendor: string;
15
+ readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
16
+ readonly types?: {
17
+ readonly input: Input;
18
+ readonly output: Output;
19
+ } | undefined;
20
+ };
21
+ }
22
+ /** A Standard Schema validation result: the value, or the issues that refused it. */
23
+ export type StandardResult<Output> = {
24
+ readonly value: Output;
25
+ readonly issues?: undefined;
26
+ } | {
27
+ readonly issues: readonly {
28
+ readonly message: string;
29
+ }[];
30
+ };
31
+ /** Options for {@link json}. */
32
+ export interface JsonOptions<T> {
33
+ /** Validates each value before it's encoded and after it's decoded, synchronously. */
34
+ schema?: StandardSchemaV1<unknown, T> | undefined;
35
+ }
36
+ /**
37
+ * A JSON codec written with evt's encoder (the one Go's `encoding/json` output is reproduced
38
+ * with). Plain objects encode in property order.
39
+ *
40
+ * Decoding gives plain objects, arrays and numbers, so `T` must be plain JSON: a `Map`, a `bigint`
41
+ * or a `Date` doesn't decode back to itself. A domain that must match a Go or Rust one byte for
42
+ * byte, with a map whose keys are written sorted, needs a codec of its own that decodes the map as
43
+ * a `Map`. An integer past `Number.MAX_SAFE_INTEGER` is refused rather than rounded.
44
+ *
45
+ * Encoding refuses a value decoding would refuse, and with a `schema`, each value is validated
46
+ * before it's encoded and after it's decoded, so an event or a snapshot that couldn't be read back
47
+ * fails its commit instead of every later load. The schema must not transform values: the value
48
+ * is encoded as given.
49
+ */
50
+ export declare function json<T>(options?: JsonOptions<T>): Codec<T>;
51
+ /**
52
+ * A JSON value as plain JavaScript: objects as plain objects, numbers as `number`. An integer past
53
+ * the safe range is refused, because `number` would round it.
54
+ */
55
+ export declare function plainJson(value: JsonValue): unknown;
56
+ //# sourceMappingURL=codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../src/codec.ts"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,SAAS,EAA2B,MAAM,WAAW,CAAA;AAG9E,mEAAmE;AACnE,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;IAC5B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,CAAC,CAAA;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IAC/D,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;QACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,cAAc,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAA;QAC/F,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;SAAC,GAAG,SAAS,CAAA;KAC9E,CAAA;CACF;AAED,qFAAqF;AACrF,MAAM,MAAM,cAAc,CAAC,MAAM,IAC7B;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAC,GACrD;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAC,EAAE,CAAA;CAAC,CAAA;AAE5D,gCAAgC;AAChC,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,sFAAsF;IACtF,MAAM,CAAC,EAAE,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;CAClD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,GAAE,WAAW,CAAC,CAAC,CAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAoB9D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAgCnD"}
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,83 @@
1
+ import type { Item } from './item.js';
2
+ /** The options the repository passes with every call. */
3
+ export interface RequestOptions {
4
+ abortSignal?: AbortSignal;
5
+ }
6
+ /** One action of a `TransactWriteItems` call. */
7
+ export interface TransactItem {
8
+ ConditionCheck?: ConditionCheckAction;
9
+ Put?: PutAction;
10
+ Update?: UpdateAction;
11
+ Delete?: DeleteAction;
12
+ }
13
+ /** The expression parts an action or a query may carry. */
14
+ export interface Expressions {
15
+ ConditionExpression?: string;
16
+ ExpressionAttributeNames?: Record<string, string>;
17
+ ExpressionAttributeValues?: Item;
18
+ }
19
+ export interface ConditionCheckAction extends Expressions {
20
+ TableName: string;
21
+ Key: Item;
22
+ ConditionExpression: string;
23
+ }
24
+ export interface PutAction extends Expressions {
25
+ TableName: string;
26
+ Item: Item;
27
+ }
28
+ export interface UpdateAction extends Expressions {
29
+ TableName: string;
30
+ Key: Item;
31
+ UpdateExpression: string;
32
+ }
33
+ export interface DeleteAction extends Expressions {
34
+ TableName: string;
35
+ Key: Item;
36
+ }
37
+ export interface GetItemInput {
38
+ TableName: string;
39
+ Key: Item;
40
+ ConsistentRead?: boolean;
41
+ ProjectionExpression?: string;
42
+ ExpressionAttributeNames?: Record<string, string>;
43
+ }
44
+ export interface PutItemInput extends Expressions {
45
+ TableName: string;
46
+ Item: Item;
47
+ }
48
+ export interface QueryInput {
49
+ TableName: string;
50
+ KeyConditionExpression: string;
51
+ ExpressionAttributeNames?: Record<string, string>;
52
+ ExpressionAttributeValues: Item;
53
+ ConsistentRead?: boolean;
54
+ ProjectionExpression?: string;
55
+ ScanIndexForward?: boolean;
56
+ Limit?: number;
57
+ ExclusiveStartKey?: Item;
58
+ }
59
+ export interface ScanInput {
60
+ TableName: string;
61
+ ConsistentRead?: boolean;
62
+ ProjectionExpression?: string;
63
+ Limit?: number;
64
+ ExclusiveStartKey?: Item;
65
+ }
66
+ /** A page of a query or a scan. Items come back as the SDK decodes them. */
67
+ export interface Page {
68
+ Items?: Record<string, unknown>[] | undefined;
69
+ LastEvaluatedKey?: Record<string, unknown> | undefined;
70
+ }
71
+ /** The calls {@link DynamoRepository} makes: the SDK's `DynamoDB` client has them all. */
72
+ export interface DynamoClient {
73
+ getItem(input: GetItemInput, options?: RequestOptions): Promise<{
74
+ Item?: Record<string, unknown> | undefined;
75
+ }>;
76
+ putItem(input: PutItemInput, options?: RequestOptions): Promise<unknown>;
77
+ query(input: QueryInput, options?: RequestOptions): Promise<Page>;
78
+ scan(input: ScanInput, options?: RequestOptions): Promise<Page>;
79
+ transactWriteItems(input: {
80
+ TransactItems: TransactItem[];
81
+ }, options?: RequestOptions): Promise<unknown>;
82
+ }
83
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/dynamodb/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ // The DynamoDB calls the repository makes, as a structural interface. The AWS SDK's aggregated
2
+ // `DynamoDB` client (`@aws-sdk/client-dynamodb`) satisfies it, so this package imports nothing
3
+ // from the SDK. Requests and responses use the low-level `AttributeValue` maps, never the document
4
+ // client's marshalling, because the storage format pins every attribute's type.
5
+ export {};
6
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/dynamodb/client.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,+FAA+F;AAC/F,mGAAmG;AACnG,gFAAgF"}
@@ -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,6 @@
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, ttlFromItem, viewItem, } from './item.js';
2
+ export { type ConditionCheckAction, type DeleteAction, type DynamoClient, type Expressions, type GetItemInput, type Page, type PutAction, type PutItemInput, type QueryInput, type RequestOptions, type ScanInput, type TransactItem, type UpdateAction, } from './client.js';
3
+ export { FEATURES_PK, REBUILD_LOCK_PK, manifestFromItem, markerItem } from './marker.js';
4
+ export { DynamoRepository, type DynamoRepositoryOptions } from './repository.js';
5
+ export { type CommitTtl, type SnapshotTtl, commitTransaction, snapshotTransaction, } from './requests.js';
6
+ //# 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,WAAW,EACX,QAAQ,GACT,MAAM,WAAW,CAAA;AAClB,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAC,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,EAAC,MAAM,aAAa,CAAA;AACtF,OAAO,EAAC,gBAAgB,EAAE,KAAK,uBAAuB,EAAC,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EACL,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,eAAe,CAAA"}
@@ -0,0 +1,8 @@
1
+ // @photon-grove/evt/dynamodb: the DynamoDB backend. It imports nothing from the AWS SDK: the
2
+ // repository takes the SDK's `DynamoDB` client, or anything shaped like it, as a DynamoClient.
3
+ export { DEFAULT_VIEW_SORT_KEY, HEAD_SORT_KEY, SNAPSHOT_SORT_KEY, eventFromItem, eventItem, expiry, headFromItem, headItem, isSnapshotItem, itemSize, snapshotFromItem, snapshotItem, sortKey, ttlFromItem, viewItem, } from './item.js';
4
+ export {} from './client.js';
5
+ export { FEATURES_PK, REBUILD_LOCK_PK, manifestFromItem, markerItem } from './marker.js';
6
+ export { DynamoRepository } from './repository.js';
7
+ export { commitTransaction, snapshotTransaction, } from './requests.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dynamodb/index.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,+FAA+F;AAE/F,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,WAAW,EACX,QAAQ,GACT,MAAM,WAAW,CAAA;AAClB,OAAO,EAcN,MAAM,aAAa,CAAA;AACpB,OAAO,EAAC,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,EAAC,MAAM,aAAa,CAAA;AACtF,OAAO,EAAC,gBAAgB,EAA+B,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAGL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,eAAe,CAAA"}
@@ -0,0 +1,70 @@
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
+ /** An item's `ttl` in Unix seconds, or undefined when it has none. */
53
+ export declare function ttlFromItem(item: Item): number | undefined;
54
+ /** Whether an item is a stream's inline snapshot (`sk = 0`). */
55
+ export declare function isSnapshotItem(item: Item): boolean;
56
+ /** An item's numeric sort key, if it has one. */
57
+ export declare function sortKey(item: Item): bigint | undefined;
58
+ /**
59
+ * The `ttl` of an item written at `nowMs` (Unix milliseconds) under a retention of `retentionMs`:
60
+ * their sum in whole Unix seconds, rounded down after adding, as Go's `Time.Add(...).Unix()` is.
61
+ * Undefined, so no `ttl` is written, for a zero retention. A retention with a fraction of a
62
+ * millisecond is refused, because Go would count it.
63
+ */
64
+ export declare function expiry(nowMs: number, retentionMs: number): number | undefined;
65
+ /**
66
+ * The size DynamoDB counts for an item: each attribute's name plus its value, in UTF-8 bytes. The
67
+ * commit budget measures every action with it.
68
+ */
69
+ export declare function itemSize(item: Item): number;
70
+ //# 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,CAEhF;AAED,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAI1D;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"}