@reventlessdev/reventless-aws 3.0.0-alpha.304 → 3.0.0-alpha.306

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 (69) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +9 -9
  3. package/src/Platform.res +1 -1
  4. package/src/adapter/Api/AppSync_Resolver_Native.res +1 -1
  5. package/src/adapter/Api/AppSync_Resolver_Retrying.res +2 -2
  6. package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +69 -11
  7. package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res.mjs +19 -1
  8. package/src/adapter/DcbEventLog/DcbEventLogStorage_DynamoDb_Runtime.res +2 -2
  9. package/src/adapter/DcbEventLog/DcbEventLogStorage_Postgres.res +1 -1
  10. package/src/adapter/EventLog/EventLogStorage_DynamoDb_Runtime.res +1 -1
  11. package/src/adapter/Postgres/PgChangeFeedRelay_Runtime.res +1 -1
  12. package/src/adapter/Postgres/PgProjectionFeed.res +1 -1
  13. package/src/adapter/QueryDb/QueryDbBackend.res +1 -1
  14. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +29 -15
  15. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res.mjs +6 -5
  16. package/src/adapter/QueryEngine/QueryEngine_DynamoDb.res +1 -1
  17. package/src/adapter/Runtime/AggregateEntryPoint.mjs +1 -1
  18. package/src/adapter/Runtime/AggregateEntryPoint_Ops.res +1 -1
  19. package/src/adapter/Runtime/AutomationSliceEntryPoint.mjs +1 -1
  20. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +1 -1
  21. package/src/adapter/Runtime/CounterEntryPoint.mjs +1 -1
  22. package/src/adapter/Runtime/CounterEntryPoint_Ops.res +1 -1
  23. package/src/adapter/Runtime/DcbCommandTopicEntryPoint.mjs +44 -6
  24. package/src/adapter/Runtime/DcbCommandTopicEntryPoint_Ops.res +1 -1
  25. package/src/adapter/Runtime/EventCollectorEntryPoint.mjs +8 -9
  26. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res +36 -8
  27. package/src/adapter/Runtime/EventCollectorEntryPoint_Ops.res.mjs +18 -7
  28. package/src/adapter/Runtime/EventMapperEntryPoint.mjs +1 -1
  29. package/src/adapter/Runtime/EventMapperEntryPoint_Ops.res +1 -1
  30. package/src/adapter/Runtime/ExtensionPointEntryPoint.mjs +1 -1
  31. package/src/adapter/Runtime/ExtensionPointEntryPoint_Ops.res +1 -1
  32. package/src/adapter/Runtime/PgQueryResolverEntryPoint.mjs +1 -1
  33. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +1 -1
  34. package/src/adapter/Runtime/PluginExtensionPointEntryPoint.res +1 -1
  35. package/src/adapter/Runtime/ProjectionEntryPoint_Ops.res +1 -1
  36. package/src/adapter/Runtime/QueryDbEntryPoint_Ops.res +1 -1
  37. package/src/adapter/Runtime/ReadModelEntryPoint.mjs +1 -1
  38. package/src/adapter/Runtime/ReadModelEntryPoint_Ops.res +1 -1
  39. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +1 -1
  40. package/src/adapter/Runtime/SideEffectEntryPoint.mjs +1 -1
  41. package/src/adapter/Runtime/SideEffectEntryPoint_Ops.res +1 -1
  42. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res +3 -1
  43. package/src/adapter/Runtime/StateChangeSliceRuntime_Builder_Single.res.mjs +4 -1
  44. package/src/adapter/Runtime/StateViewSliceEntryPoint.mjs +1 -1
  45. package/src/adapter/Runtime/StateViewSliceEntryPoint_Ops.res +1 -1
  46. package/src/adapter/Runtime/StreamRoutedEntryPoint_Ops.res +1 -1
  47. package/src/adapter/Runtime/TaskBucketEntryPoint.mjs +1 -1
  48. package/src/adapter/Runtime/TaskBucketEntryPoint_Ops.res +1 -1
  49. package/src/plugin/runtime/PluginRuntime_Builder.res +46 -22
  50. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +16 -11
  51. package/src/util/Util_Bundle.res +1 -1
  52. package/src/util/Util_DynamoDbStream_Runtime.res +1 -1
  53. package/src/util/Util_LambdaEnvBudget.res +74 -0
  54. package/src/util/Util_LambdaEnvBudget.res.mjs +37 -0
  55. package/tests/AWS_TagsTest.res +2 -2
  56. package/tests/Auth_ActiveRolePoolAttachmentTest.res +140 -1
  57. package/tests/Auth_ActiveRolePoolAttachmentTest.res.mjs +117 -2
  58. package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res +2 -2
  59. package/tests/EventCollectorEntryPoint_OpsTest.res +13 -4
  60. package/tests/EventCollectorEntryPoint_OpsTest.res.mjs +19 -13
  61. package/tests/EventLogStorage_DynamoDb_RuntimeTest.res +1 -1
  62. package/tests/QueryDbResolvers_AppSyncTest.res +2 -2
  63. package/tests/Util_BundleEsmLoaderTest.res +1 -1
  64. package/tests/Util_BundleRuntimeExtensionTest.res +1 -1
  65. package/tests/Util_LambdaEnvBudgetTest.res +78 -0
  66. package/tests/Util_LambdaEnvBudgetTest.res.mjs +55 -0
  67. package/tests/integration/AggregateEntryPoint_IntegrationTest.res +1 -1
  68. package/tests/integration/DcbCommandTopicEntryPoint_IntegrationTest.res +1 -1
  69. package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res +2 -2
@@ -0,0 +1,78 @@
1
+ // Guards the deploy-time check on a Lambda's 4KB environment.
2
+ //
3
+ // The check exists because the limit is enforced by AWS mid-`pulumi up`, on a
4
+ // call that names a byte count and not the field that grew. The two cases worth
5
+ // pinning are the ones that decide whether a deploy proceeds: an exact total
6
+ // already over the limit must stop it, and an over-limit total that only appears
7
+ // once the unresolved queue-URL vars are estimated must not — a wrong estimate
8
+ // blocking a good deploy would be worse than the failure it prevents.
9
+
10
+ open JestGlobals
11
+
12
+ let budget = Util_LambdaEnvBudget.limit
13
+
14
+ let throws = (f: unit => 'a): option<string> =>
15
+ try {
16
+ let _ = f()
17
+ None
18
+ } catch {
19
+ | exn => exn->JsExn.fromException->Option.flatMap(JsExn.message)
20
+ }
21
+
22
+ describe("Util_LambdaEnvBudget.check", () => {
23
+ testSync("passes a small environment", () => {
24
+ let msg = throws(() =>
25
+ Util_LambdaEnvBudget.check(~lambdaName="Small", ~handlerConfigJson=`{"queueUrl":"q"}`)
26
+ )
27
+ expect(msg)->toEqual(None)
28
+ })
29
+
30
+ testSync("throws when HANDLER_CONFIG alone exceeds the limit", () => {
31
+ let big = `{"x":"` ++ String.repeat("a", budget) ++ `"}`
32
+ let msg = throws(() => Util_LambdaEnvBudget.check(~lambdaName="TooBig", ~handlerConfigJson=big))
33
+ expect(msg->Option.isSome)->toBe(true)
34
+ // Names the Lambda and points at the fix, not just the byte count.
35
+ expect(msg->Option.mapOr(false, m => m->String.includes("TooBig")))->toBe(true)
36
+ expect(msg->Option.mapOr(false, m => m->String.includes("extraStringAssets")))->toBe(true)
37
+ })
38
+
39
+ testSync("counts the queue-URL var names toward the exact total", () => {
40
+ // Sized so HANDLER_CONFIG alone fits and the var NAMES alone push it over —
41
+ // the names are known at check time, so this must throw rather than warn.
42
+ let keys = Array.make(~length=40, "")->Array.mapWithIndex((_, i) =>
43
+ `PTA_AVeryLongAggregateNameNumber${i->Int.toString}_QUEUE_URL`
44
+ )
45
+ let keyBytes = keys->Array.reduce(0, (acc, k) => acc + String.length(k))
46
+ let fixed = Util_LambdaEnvBudget.frameworkVarsBytes + String.length("HANDLER_CONFIG")
47
+ // Just past the limit on the exact total alone — the names are enough.
48
+ let json = String.repeat("a", budget - fixed - keyBytes + 1)
49
+ let msg = throws(() =>
50
+ Util_LambdaEnvBudget.check(
51
+ ~lambdaName="ManyTargets",
52
+ ~handlerConfigJson=json,
53
+ ~outputValuedKeys=keys,
54
+ )
55
+ )
56
+ expect(msg->Option.isSome)->toBe(true)
57
+ })
58
+
59
+ testSync("only estimating over the limit warns rather than throwing", () => {
60
+ // Exact total sits under the limit; it is the per-URL allowance that crosses
61
+ // it. The deploy must be allowed to proceed and find out.
62
+ let keys = Array.make(~length=20, "")->Array.mapWithIndex((_, i) => `PTA_A${i->Int.toString}_URL`)
63
+ let exact =
64
+ Util_LambdaEnvBudget.frameworkVarsBytes +
65
+ String.length("HANDLER_CONFIG") +
66
+ keys->Array.reduce(0, (acc, k) => acc + String.length(k))
67
+ let room = budget - exact - 100
68
+ let json = String.repeat("a", room)
69
+ let msg = throws(() =>
70
+ Util_LambdaEnvBudget.check(
71
+ ~lambdaName="Estimated",
72
+ ~handlerConfigJson=json,
73
+ ~outputValuedKeys=keys,
74
+ )
75
+ )
76
+ expect(msg)->toEqual(None)
77
+ })
78
+ })
@@ -0,0 +1,55 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
4
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
7
+ import * as Util_LambdaEnvBudget$ReventlessAws from "../src/util/Util_LambdaEnvBudget.res.mjs";
8
+
9
+ function throws(f) {
10
+ try {
11
+ f();
12
+ return;
13
+ } catch (raw_exn) {
14
+ let exn = Primitive_exceptions.internalToException(raw_exn);
15
+ return Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message);
16
+ }
17
+ }
18
+
19
+ globalThis.describe("Util_LambdaEnvBudget.check", () => {
20
+ globalThis.test("passes a small environment", () => {
21
+ let msg = throws(() => Util_LambdaEnvBudget$ReventlessAws.check("Small", `{"queueUrl":"q"}`, undefined));
22
+ globalThis.expect(msg).toEqual(undefined);
23
+ });
24
+ globalThis.test("throws when HANDLER_CONFIG alone exceeds the limit", () => {
25
+ let big = `{"x":"` + "a".repeat(Util_LambdaEnvBudget$ReventlessAws.limit) + `"}`;
26
+ let msg = throws(() => Util_LambdaEnvBudget$ReventlessAws.check("TooBig", big, undefined));
27
+ globalThis.expect(Stdlib_Option.isSome(msg)).toBe(true);
28
+ globalThis.expect(Stdlib_Option.mapOr(msg, false, m => m.includes("TooBig"))).toBe(true);
29
+ globalThis.expect(Stdlib_Option.mapOr(msg, false, m => m.includes("extraStringAssets"))).toBe(true);
30
+ });
31
+ globalThis.test("counts the queue-URL var names toward the exact total", () => {
32
+ let keys = Stdlib_Array.make(40, "").map((param, i) => `PTA_AVeryLongAggregateNameNumber` + i.toString() + `_QUEUE_URL`);
33
+ let keyBytes = Stdlib_Array.reduce(keys, 0, (acc, k) => acc + k.length | 0);
34
+ let fixed = Util_LambdaEnvBudget$ReventlessAws.frameworkVarsBytes + "HANDLER_CONFIG".length | 0;
35
+ let json = "a".repeat(((Util_LambdaEnvBudget$ReventlessAws.limit - fixed | 0) - keyBytes | 0) + 1 | 0);
36
+ let msg = throws(() => Util_LambdaEnvBudget$ReventlessAws.check("ManyTargets", json, keys));
37
+ globalThis.expect(Stdlib_Option.isSome(msg)).toBe(true);
38
+ });
39
+ globalThis.test("only estimating over the limit warns rather than throwing", () => {
40
+ let keys = Stdlib_Array.make(20, "").map((param, i) => `PTA_A` + i.toString() + `_URL`);
41
+ let exact = (Util_LambdaEnvBudget$ReventlessAws.frameworkVarsBytes + "HANDLER_CONFIG".length | 0) + Stdlib_Array.reduce(keys, 0, (acc, k) => acc + k.length | 0) | 0;
42
+ let room = (Util_LambdaEnvBudget$ReventlessAws.limit - exact | 0) - 100 | 0;
43
+ let json = "a".repeat(room);
44
+ let msg = throws(() => Util_LambdaEnvBudget$ReventlessAws.check("Estimated", json, keys));
45
+ globalThis.expect(msg).toEqual(undefined);
46
+ });
47
+ });
48
+
49
+ let budget = Util_LambdaEnvBudget$ReventlessAws.limit;
50
+
51
+ export {
52
+ budget,
53
+ throws,
54
+ }
55
+ /* Not a pure module */
@@ -11,7 +11,7 @@
11
11
  // CommandAccepted -> Lambda:Unhandled.
12
12
  //
13
13
  // This is also the harness that unblocks moving the Aggregate functor wiring
14
- // behind a typed core (docs/plans/minimize-lambda-entrypoint-mjs-shell.md,
14
+ // behind a typed core (docs/plans/done/minimize-lambda-entrypoint-mjs-shell.md,
15
15
  // Tier 2.5): with it green, that refactor is verifiable end-to-end rather than
16
16
  // only at compile time. Boots via the same Docker-gated
17
17
  // `pnpm run test:integration` suite as the storage-runtime tests.
@@ -161,7 +161,7 @@ describe("DcbCommandTopicEntryPoint integration", () => {
161
161
  )
162
162
 
163
163
  // Residual composite-fence burst contention
164
- // (docs/plans/dcb-composite-fence-residual-burst-contention.md).
164
+ // (docs/plans/done/dcb-composite-fence-residual-burst-contention.md).
165
165
  //
166
166
  // The entry point must derive `partitionTag = Composite(...)` and thread it
167
167
  // into the DynamoDB `append`, so a `@compositePartitionTag` slice collapses to
@@ -331,7 +331,7 @@ describe("DCB DynamoDb integration — optimistic concurrency primitives", () =>
331
331
  // on the WHOLE composite key, not on each member. Distinct entities sharing a
332
332
  // low-cardinality prefix (environment/platformName/pluginName) must therefore NOT
333
333
  // serialize on that prefix — the deploy-fan-out hot-fence regression. Plan:
334
- // docs/plans/Backlog/dcb-hot-tag-fence-contention.md § "Root-cause correction".
334
+ // docs/plans/done/dcb-hot-tag-fence-contention.md § "Root-cause correction".
335
335
  describe("DCB DynamoDb integration — composite partition hot-fence fix", () => {
336
336
  let composite = (keys, seps): Reventless.DcbTag.derivedPartitionTag => Composite({keys, seps})
337
337
  let specKeys = ["environment", "platformName", "pluginName", "resourceName"]
@@ -464,7 +464,7 @@ describe("DCB DynamoDb integration — per-type fence granularity", () => {
464
464
  // DynamoDB used to reject the whole append: `tag_<key>` is a GSI hash key and a key
465
465
  // attribute cannot hold an empty string. The adapter now skips that one attribute,
466
466
  // leaving the index sparse — everything else about the event is unchanged.
467
- // See docs/plans/dcb-empty-tag-values-break-append.md.
467
+ // See docs/plans/done/dcb-empty-tag-values-break-append.md.
468
468
  describe("DCB DynamoDb integration — an empty tag value does not break the append", () => {
469
469
  let tags = [tag("orderId", "O-empty"), tag("customerId", "")]
470
470