@reventlessdev/reventless-aws 3.0.0-alpha.256 → 3.0.0-alpha.258

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.258 (2026-08-02)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/reventless-aws
9
+
10
+
11
+
12
+
13
+
14
+ # 3.0.0-alpha.257 (2026-08-02)
15
+
16
+ ### Features
17
+
18
+ * **aws:** activate [@offload](https://github.com/offload) for plugin payloads across platform + plugin stacks ([3d9e91c](https://github.com/ReventlessDev/reventless-core/commit/3d9e91c382504f9bbb71e653dd96c503ec25a566))
19
+ * **aws:** S3 GetObject->string binding + structure offload resolver ([1274bcc](https://github.com/ReventlessDev/reventless-core/commit/1274bcce29f8a1b70db362a10585c508710e7b56))
20
+
21
+
6
22
  # 3.0.0-alpha.256 (2026-08-02)
7
23
 
8
24
  **Note:** Version bump only for package @reventlessdev/reventless-aws
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-aws",
3
- "version": "3.0.0-alpha.256",
3
+ "version": "3.0.0-alpha.258",
4
4
  "description": "AWS adapters for Reventless",
5
5
  "license": "Apache-2.0",
6
6
  "dependencies": {
@@ -11,18 +11,18 @@
11
11
  "@aws-sdk/s3-request-presigner": "3.970.0",
12
12
  "sury": "11.0.0-alpha.4",
13
13
  "uuid": "^13.0.0",
14
- "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.1",
14
+ "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.2",
15
15
  "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
16
16
  "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
17
- "@reventlessdev/rescript-node": "2.0.0-alpha.0",
18
- "@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.63",
19
- "@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
17
+ "@reventlessdev/rescript-node": "2.0.0-alpha.1",
18
+ "@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.64",
20
19
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
21
- "@reventlessdev/reventless-core": "3.0.0-alpha.202",
22
- "@reventlessdev/reventless-infra": "3.0.0-alpha.119",
20
+ "@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
21
+ "@reventlessdev/reventless-core": "3.0.0-alpha.204",
23
22
  "@reventlessdev/reventless-interop": "3.0.0-alpha.30",
24
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.66",
25
- "@reventlessdev/reventless-spec": "3.0.0-alpha.94"
23
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.68",
24
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.121",
25
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.96"
26
26
  },
27
27
  "devDependencies": {
28
28
  "rescript": "12.3.0",
package/src/Platform.res CHANGED
@@ -1355,6 +1355,44 @@ module MakeWithConfig = (
1355
1355
  (),
1356
1356
  )
1357
1357
 
1358
+ // ── Content-addressed offload bucket (@offload primitive) ─────────────────
1359
+ //
1360
+ // One platform-level bucket holds the large `pluginDefinition` fields
1361
+ // (`structure` ~74 KB, `apiSchemaFragment` ~32 KB) keyed by their SHA-256
1362
+ // (`sha256/<hash>`). Content-addressed and immutable, so it needs no CORS,
1363
+ // lifecycle, or versioning — identical payloads across versions land on one
1364
+ // object (free dedupe). Plugin stacks PUT to it (a `BucketObject` in the
1365
+ // plugin deploy, via the offload hook) and the ComponentDefinitions Lambda
1366
+ // GETs from it to resolve an offloaded `structure`. Kept out of the declared
1367
+ // `@storageRef` stores and their pending-claim/expiry machinery: offload
1368
+ // objects are written durably up front and are never "pending".
1369
+ let offloadProtection = Util_StoreLayout.protectionFor(~stack=Pulumi.Pulumi.getStackName())
1370
+ let offloadBucket = PulumiAws.S3.Bucket.make(
1371
+ ~name="reventless-offload",
1372
+ ~args={
1373
+ forceDestroy: (offloadProtection == Unprotected)->Pulumi.Input.make,
1374
+ tags: AWS.Tags.make(
1375
+ ~name="reventless-offload",
1376
+ ~kind=ReventlessCore.ComponentType.Platform,
1377
+ ~role=Other("Offload"),
1378
+ ~scope=Platform,
1379
+ ),
1380
+ },
1381
+ ~opts={protect: offloadProtection == Protected},
1382
+ )
1383
+ let offloadBucketName = offloadBucket.bucket
1384
+ let _offloadPab = PulumiAws.S3.BucketPublicAccessBlock.make(
1385
+ ~name="reventless-offload-pab",
1386
+ ~args={
1387
+ bucket: offloadBucket.id->Pulumi.Output.asInput,
1388
+ blockPublicAcls: Pulumi.Input.make(true),
1389
+ blockPublicPolicy: Pulumi.Input.make(true),
1390
+ ignorePublicAcls: Pulumi.Input.make(true),
1391
+ restrictPublicBuckets: Pulumi.Input.make(true),
1392
+ },
1393
+ )
1394
+ Pulumi.Pulumi.export("offloadBucket", offloadBucketName)
1395
+
1358
1396
  // Mount the Platform_ComponentDefinitions Lambda resolver on the Platform API
1359
1397
  // (split mode) or Domain API (unified mode — platformApi == domainApi above).
1360
1398
  // Also register the Plugin RM table with the AllAggregates Lambda runtime
@@ -1366,6 +1404,7 @@ module MakeWithConfig = (
1366
1404
  Platform_ComponentDefinitions_Lambda.make(
1367
1405
  ~api=platformApi,
1368
1406
  ~pluginReadModelTableName=tableName,
1407
+ ~offloadBucketName,
1369
1408
  ~opts={},
1370
1409
  )
1371
1410
  | None => ()
@@ -2112,8 +2151,39 @@ module MakeWithConfig = (
2112
2151
  hooks.api := Some(targetApi->wrapHookedValue)
2113
2152
  hooks.apiRole := Some(targetApiRole->wrapHookedValue)
2114
2153
 
2154
+ // Register the deploy-time offload hook so Plugin_Builder content-addresses
2155
+ // the two large pluginDefinition fields (`structure`, `apiSchemaFragment`)
2156
+ // into the platform's offload bucket and carries them as references instead
2157
+ // of inline. The hook fires synchronously during P.make() (both values are
2158
+ // concrete at graph construction), writing a content-addressed BucketObject
2159
+ // and returning its ref; cleared after the build so nothing else offloads.
2160
+ // The bucket name comes from the platform stack (deploy the platform first).
2161
+ let offloadBucketName: Pulumi.Output.t<string> = switch platformStackRef {
2162
+ | Some(stackRef) =>
2163
+ (stackRef->Pulumi.StackReference.getOutput("offloadBucket"): Pulumi.Output.t<option<string>>)
2164
+ ->Pulumi.Output.apply(o => o->Option.getOr("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY"))
2165
+ | None => Pulumi.Output.make("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY")
2166
+ }
2167
+ ReventlessCore.Plugin_Helpers.registerOffload((~store, ~bytes) => {
2168
+ let hash = NodeCrypto.sha256Hex(bytes)
2169
+ let key = "sha256/" ++ hash
2170
+ // Content-addressed: the name and key are the hash, so re-deploying an
2171
+ // unchanged field writes the same object (idempotent, deduplicating).
2172
+ let _ = PulumiAws.S3.BucketObject.make(
2173
+ ~name="offload-" ++ hash,
2174
+ ~args={
2175
+ bucket: offloadBucketName->Pulumi.Output.asInput,
2176
+ key: Pulumi.Input.make(key),
2177
+ content: Pulumi.Input.make(bytes),
2178
+ contentType: Pulumi.Input.make("application/json"),
2179
+ },
2180
+ )
2181
+ {Reventless.Offload.store, key, hash, bytes: bytes->String.length}
2182
+ })
2183
+
2115
2184
  module P = unpack(plugin)
2116
2185
  let pluginComponent = P.make()
2186
+ ReventlessCore.Plugin_Helpers.clearOffload()
2117
2187
  currentDeployTarget := Domain // reset after build
2118
2188
 
2119
2189
  // Note: StateTopic_AppSync.finish runs from inside subscriptionInfraHook —
@@ -1,6 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as S from "sury/src/S.res.mjs";
4
+ import * as NodeCrypto from "@reventlessdev/rescript-node/src/NodeCrypto.res.mjs";
4
5
  import * as Pervasives from "@rescript/runtime/lib/es6/Pervasives.js";
5
6
  import * as Aws from "@pulumi/aws";
6
7
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
@@ -15,6 +16,7 @@ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
15
16
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
16
17
  import * as Plugin$ReventlessAws from "./components/Plugin.res.mjs";
17
18
  import * as Logger$ReventlessCore from "@reventlessdev/reventless-core/src/util/Logger.res.mjs";
19
+ import * as AWS_Tags$ReventlessAws from "./adapter/AWS_Tags.res.mjs";
18
20
  import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
19
21
  import * as Scheduler$ReventlessAws from "./components/Scheduler.res.mjs";
20
22
  import * as Aggregate$ReventlessCore from "@reventlessdev/reventless-core/src/components/Aggregate/Aggregate.res.mjs";
@@ -833,9 +835,28 @@ function MakeWithConfig(Config) {
833
835
  }
834
836
  });
835
837
  PluginRuntime_Builder$ReventlessAws.registerConfig(pluginEpEventTopicArn, pluginReadModelTableName, hooks_schedulerRoleUrn.contents, undefined, undefined, domainApiId, Config.cloner, undefined);
838
+ let offloadProtection = Util_StoreLayout$ReventlessAws.protectionFor(Pulumi.getStack(), undefined);
839
+ let offloadBucket = new (Aws.s3.Bucket)("reventless-offload", {
840
+ forceDestroy: offloadProtection === "Unprotected",
841
+ tags: AWS_Tags$ReventlessAws.make("reventless-offload", "Platform", {
842
+ TAG: "Other",
843
+ _0: "Offload"
844
+ }, "Platform", undefined, undefined, undefined, undefined)
845
+ }, {
846
+ protect: offloadProtection === "Protected"
847
+ });
848
+ let offloadBucketName = offloadBucket.bucket;
849
+ new (Aws.s3.BucketPublicAccessBlock)("reventless-offload-pab", {
850
+ bucket: offloadBucket.id,
851
+ blockPublicAcls: true,
852
+ blockPublicPolicy: true,
853
+ ignorePublicAcls: true,
854
+ restrictPublicBuckets: true
855
+ });
856
+ Pulumi$Pulumi.$$export("offloadBucket", offloadBucketName);
836
857
  if (pluginReadModelTableName !== undefined) {
837
858
  AggregateRuntime_Builder_Single$ReventlessAws.setPluginReadModelTable(pluginReadModelTableName);
838
- Platform_ComponentDefinitions_Lambda$ReventlessAws.make(platformApi, pluginReadModelTableName, {});
859
+ Platform_ComponentDefinitions_Lambda$ReventlessAws.make(platformApi, pluginReadModelTableName, offloadBucketName, {});
839
860
  }
840
861
  let rm = admin.stateViewSlicesOutputs["UiFragments"];
841
862
  if (rm !== undefined) {
@@ -1201,7 +1222,25 @@ function MakeWithConfig(Config) {
1201
1222
  let targetApiRole = resolveTargetApiRole();
1202
1223
  hooksApiRef.contents = Platform_Casts$ReventlessAws.wrapHookedValue(targetApi);
1203
1224
  hooksApiRoleRef.contents = Platform_Casts$ReventlessAws.wrapHookedValue(targetApiRole);
1225
+ let offloadBucketName = platformStackRef !== undefined ? Primitive_option.valFromOption(platformStackRef).getOutput("offloadBucket").apply(o => Stdlib_Option.getOr(o, "OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY")) : Pulumi.output("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY");
1226
+ Plugin_Helpers$ReventlessCore.registerOffload((store, bytes) => {
1227
+ let hash = NodeCrypto.sha256Hex(bytes);
1228
+ let key = "sha256/" + hash;
1229
+ new (Aws.s3.BucketObject)("offload-" + hash, {
1230
+ bucket: offloadBucketName,
1231
+ key: key,
1232
+ content: bytes,
1233
+ contentType: "application/json"
1234
+ });
1235
+ return {
1236
+ store: store,
1237
+ key: key,
1238
+ hash: hash,
1239
+ bytes: bytes.length
1240
+ };
1241
+ });
1204
1242
  let pluginComponent = plugin.make();
1243
+ Plugin_Helpers$ReventlessCore.clearOffload();
1205
1244
  currentDeployTarget.contents = "Domain";
1206
1245
  Pulumi$Pulumi.$$export("_interopMeta", Plugin_Helpers$ReventlessCore.getInteropMeta());
1207
1246
  let pluginOutputs = Component$ReventlessCore.outputs(pluginComponent);
@@ -2028,9 +2067,28 @@ function Make($star) {
2028
2067
  }
2029
2068
  });
2030
2069
  PluginRuntime_Builder$ReventlessAws.registerConfig(pluginEpEventTopicArn, pluginReadModelTableName, hooks_schedulerRoleUrn.contents, undefined, undefined, domainApiId, false, undefined);
2070
+ let offloadProtection = Util_StoreLayout$ReventlessAws.protectionFor(Pulumi.getStack(), undefined);
2071
+ let offloadBucket = new (Aws.s3.Bucket)("reventless-offload", {
2072
+ forceDestroy: offloadProtection === "Unprotected",
2073
+ tags: AWS_Tags$ReventlessAws.make("reventless-offload", "Platform", {
2074
+ TAG: "Other",
2075
+ _0: "Offload"
2076
+ }, "Platform", undefined, undefined, undefined, undefined)
2077
+ }, {
2078
+ protect: offloadProtection === "Protected"
2079
+ });
2080
+ let offloadBucketName = offloadBucket.bucket;
2081
+ new (Aws.s3.BucketPublicAccessBlock)("reventless-offload-pab", {
2082
+ bucket: offloadBucket.id,
2083
+ blockPublicAcls: true,
2084
+ blockPublicPolicy: true,
2085
+ ignorePublicAcls: true,
2086
+ restrictPublicBuckets: true
2087
+ });
2088
+ Pulumi$Pulumi.$$export("offloadBucket", offloadBucketName);
2031
2089
  if (pluginReadModelTableName !== undefined) {
2032
2090
  AggregateRuntime_Builder_Single$ReventlessAws.setPluginReadModelTable(pluginReadModelTableName);
2033
- Platform_ComponentDefinitions_Lambda$ReventlessAws.make(platformApi, pluginReadModelTableName, {});
2091
+ Platform_ComponentDefinitions_Lambda$ReventlessAws.make(platformApi, pluginReadModelTableName, offloadBucketName, {});
2034
2092
  }
2035
2093
  let rm = admin.stateViewSlicesOutputs["UiFragments"];
2036
2094
  if (rm !== undefined) {
@@ -2390,7 +2448,25 @@ function Make($star) {
2390
2448
  let targetApiRole = resolveTargetApiRole();
2391
2449
  hooksApiRef.contents = Platform_Casts$ReventlessAws.wrapHookedValue(targetApi);
2392
2450
  hooksApiRoleRef.contents = Platform_Casts$ReventlessAws.wrapHookedValue(targetApiRole);
2451
+ let offloadBucketName = platformStackRef !== undefined ? Primitive_option.valFromOption(platformStackRef).getOutput("offloadBucket").apply(o => Stdlib_Option.getOr(o, "OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY")) : Pulumi.output("OFFLOAD_BUCKET_PENDING_PLATFORM_DEPLOY");
2452
+ Plugin_Helpers$ReventlessCore.registerOffload((store, bytes) => {
2453
+ let hash = NodeCrypto.sha256Hex(bytes);
2454
+ let key = "sha256/" + hash;
2455
+ new (Aws.s3.BucketObject)("offload-" + hash, {
2456
+ bucket: offloadBucketName,
2457
+ key: key,
2458
+ content: bytes,
2459
+ contentType: "application/json"
2460
+ });
2461
+ return {
2462
+ store: store,
2463
+ key: key,
2464
+ hash: hash,
2465
+ bytes: bytes.length
2466
+ };
2467
+ });
2393
2468
  let pluginComponent = plugin.make();
2469
+ Plugin_Helpers$ReventlessCore.clearOffload();
2394
2470
  currentDeployTarget.contents = "Domain";
2395
2471
  Pulumi$Pulumi.$$export("_interopMeta", Plugin_Helpers$ReventlessCore.getInteropMeta());
2396
2472
  let pluginOutputs = Component$ReventlessCore.outputs(pluginComponent);
@@ -27,6 +27,7 @@ export function response(ctx) {
27
27
  let make = (
28
28
  ~api: Pulumi.Output.t<AppSync.GraphQLApi.t>,
29
29
  ~pluginReadModelTableName: Pulumi.Output.t<string>,
30
+ ~offloadBucketName: Pulumi.Output.t<string>,
30
31
  ~opts: Pulumi.ComponentResource.options,
31
32
  ) => {
32
33
  let opts = opts->ReventlessCore.Util.Pulumi.ComponentResourceOptions.toCustomResourceOptions
@@ -45,7 +46,9 @@ let make = (
45
46
  )
46
47
 
47
48
  let _ =
48
- pluginReadModelTableName->Pulumi.Output.apply(tableName => {
49
+ (pluginReadModelTableName, offloadBucketName)
50
+ ->Pulumi.Output.all2
51
+ ->Pulumi.Output.apply(((tableName, offloadBucket)) => {
49
52
  open PolicyDocument
50
53
  let _rolePolicy = IAM.RolePolicy.make(
51
54
  ~name=name ++ "LambdaPolicy",
@@ -65,6 +68,15 @@ let make = (
65
68
  actions: Actions(["dynamodb:Scan"]),
66
69
  resources: Resource("arn:aws:dynamodb:*:*:table/" ++ tableName),
67
70
  },
71
+ // Offloaded `structure` payloads live in the platform's
72
+ // content-addressed offload bucket; the handler GETs them by their
73
+ // `sha256/<hash>` key and substitutes before filtering.
74
+ {
75
+ sid: "AllowOffloadGet",
76
+ effect: Allow,
77
+ actions: Actions(["s3:GetObject"]),
78
+ resources: Resource("arn:aws:s3:::" ++ offloadBucket ++ "/*"),
79
+ },
68
80
  ],
69
81
  )
70
82
  ->PolicyDocument.toJsonString
@@ -117,6 +129,7 @@ let make = (
117
129
  Lambda.Function.variables: Dict.fromArray([
118
130
  ("Environment", Pulumi.Pulumi.getStackName()->Pulumi.Input.make),
119
131
  ("PLUGIN_RM_TABLE", pluginReadModelTableName->Pulumi.Output.asInput),
132
+ ("OFFLOAD_BUCKET", offloadBucketName->Pulumi.Output.asInput),
120
133
  ("ADMIN_ENTRY_JSON", adminEntryJson->Pulumi.Input.make),
121
134
  ("NODE_OPTIONS", Util_Bundle.esmLoaderNodeOptions->Pulumi.Input.make),
122
135
  ("ESM_FALLBACK_DIRS", Util_Bundle.esmFallbackDirs->Pulumi.Input.make),
@@ -27,11 +27,14 @@ export function response(ctx) {
27
27
  }
28
28
  `;
29
29
 
30
- function make(api, pluginReadModelTableName, opts) {
30
+ function make(api, pluginReadModelTableName, offloadBucketName, opts) {
31
31
  let opts$1 = Util_Pulumi$ReventlessCore.ComponentResourceOptions.toCustomResourceOptions(opts);
32
32
  let name = "PlatformUIDefinitions";
33
33
  let lambdaRole = IAM$PulumiAws.Role.makeWithDefaultPolicy(name + "Lambda", Pulumi.output(AWS$ReventlessAws.Lambda.principal), AWS_Tags$ReventlessAws.make(name + "Lambda", "Platform", "Identity", "Platform", undefined, undefined, undefined, undefined), opts$1);
34
- pluginReadModelTableName.apply(tableName => {
34
+ Pulumi.all([
35
+ pluginReadModelTableName,
36
+ offloadBucketName
37
+ ]).apply(param => {
35
38
  new (Aws.iam.RolePolicy)(name + "LambdaPolicy", {
36
39
  policy: PolicyDocument$PulumiAws.toJsonString(PolicyDocument$PulumiAws.make(undefined, name + "LambdaPolicy", [
37
40
  {
@@ -44,7 +47,13 @@ function make(api, pluginReadModelTableName, opts) {
44
47
  Sid: "AllowScanPluginRm",
45
48
  Effect: "Allow",
46
49
  Action: ["dynamodb:Scan"],
47
- Resource: "arn:aws:dynamodb:*:*:table/" + tableName
50
+ Resource: "arn:aws:dynamodb:*:*:table/" + param[0]
51
+ },
52
+ {
53
+ Sid: "AllowOffloadGet",
54
+ Effect: "Allow",
55
+ Action: ["s3:GetObject"],
56
+ Resource: "arn:aws:s3:::" + param[1] + "/*"
48
57
  }
49
58
  ])),
50
59
  role: lambdaRole.id
@@ -76,6 +85,10 @@ function make(api, pluginReadModelTableName, opts) {
76
85
  "PLUGIN_RM_TABLE",
77
86
  pluginReadModelTableName
78
87
  ],
88
+ [
89
+ "OFFLOAD_BUCKET",
90
+ offloadBucketName
91
+ ],
79
92
  [
80
93
  "ADMIN_ENTRY_JSON",
81
94
  adminEntryJson
@@ -65,6 +65,35 @@ let adminEntry: option<JSON.t> =
65
65
  | _ => None
66
66
  }
67
67
 
68
+ // Resolve an offloaded `structure`: a large structure is content-addressed to the
69
+ // offload bucket at deploy time and persisted as an `{$offload: {...}}` reference,
70
+ // so fetch the object's bytes and substitute the real structure JSON before it is
71
+ // filtered. Inline (or absent) structures pass through untouched. The `fetch` is
72
+ // per-hash cached, so an identical structure shared across versions is read once.
73
+ let resolveStructure = (
74
+ fetch: string => promise<string>,
75
+ item: dict<JSON.t>,
76
+ ): promise<dict<JSON.t>> =>
77
+ switch item
78
+ ->Dict.get("structure")
79
+ ->Option.flatMap(JSON.Decode.object)
80
+ ->Option.flatMap(o => o->Dict.get(Reventless.Offload.sentinelKey)) {
81
+ | None => Promise.resolve(item)
82
+ | Some(refJson) =>
83
+ switch refJson
84
+ ->JSON.Decode.object
85
+ ->Option.flatMap(r => r->Dict.get("key"))
86
+ ->Option.flatMap(JSON.Decode.string) {
87
+ | None => Promise.resolve(item)
88
+ | Some(key) =>
89
+ fetch(key)->Promise.then(bytes => {
90
+ let resolved = Dict.fromArray(item->Dict.toArray)
91
+ resolved->Dict.set("structure", JSON.parseOrThrow(bytes))
92
+ Promise.resolve(resolved)
93
+ })
94
+ }
95
+ }
96
+
68
97
  let handler = async (_event: JSON.t): array<JSON.t> => {
69
98
  let admin = adminEntry->Option.mapOr([], e => [e])
70
99
  switch NodeProcess.env->Dict.get("PLUGIN_RM_TABLE") {
@@ -72,12 +101,18 @@ let handler = async (_event: JSON.t): array<JSON.t> => {
72
101
  Console.error("Platform_ComponentDefinitions: PLUGIN_RM_TABLE env var not set")
73
102
  admin
74
103
  | Some(table) =>
75
- let items = await Platform_AdminScan_Ops.scanAll(
104
+ let rawItems = await Platform_AdminScan_Ops.scanAll(
76
105
  ~tableName=table,
77
106
  ~filterExpression="contains(#status, :connected)",
78
107
  ~expressionAttributeNames=Dict.fromArray([("#status", "status")]),
79
108
  ~expressionAttributeValues=Dict.fromArray([(":connected", JSON.Encode.string("Connected"))]),
80
109
  )
110
+ // Substitute any offloaded structure references with their bytes before filtering.
111
+ let bucket = NodeProcess.env->Dict.get("OFFLOAD_BUCKET")->Option.getOr("")
112
+ let fetch = Reventless.Offload.cachedFetch(key =>
113
+ AwsSdk.S3.GetObjectCommand.getString(~bucket, ~key)
114
+ )
115
+ let items = await Promise.all(rawItems->Array.map(item => resolveStructure(fetch, item)))
81
116
  let userEntries =
82
117
  Platform_AdminScan_Ops.latestByName(items, ~nameVersionOf=item => item->str("name"), ~toEntry)
83
118
  Array.concat(admin, userEntries)
@@ -1,7 +1,9 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as S3$AwsSdk from "@reventlessdev/rescript-aws-sdk/src/S3.res.mjs";
3
4
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Offload$Reventless from "@reventlessdev/reventless-spec/src/semantic/Offload.res.mjs";
5
7
  import * as Platform_AdminScan_Ops$ReventlessAws from "./Platform_AdminScan_Ops.res.mjs";
6
8
 
7
9
  function str(item, key) {
@@ -46,6 +48,23 @@ let s = process.env["ADMIN_ENTRY_JSON"];
46
48
 
47
49
  let adminEntry = s !== undefined && s !== "" ? JSON.parse(s) : undefined;
48
50
 
51
+ function resolveStructure(fetch, item) {
52
+ let refJson = Stdlib_Option.flatMap(Stdlib_Option.flatMap(item["structure"], Stdlib_JSON.Decode.object), o => o[Offload$Reventless.sentinelKey]);
53
+ if (refJson === undefined) {
54
+ return Promise.resolve(item);
55
+ }
56
+ let key = Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(refJson), r => r["key"]), Stdlib_JSON.Decode.string);
57
+ if (key !== undefined) {
58
+ return fetch(key).then(bytes => {
59
+ let resolved = Object.fromEntries(Object.entries(item));
60
+ resolved["structure"] = JSON.parse(bytes);
61
+ return Promise.resolve(resolved);
62
+ });
63
+ } else {
64
+ return Promise.resolve(item);
65
+ }
66
+ }
67
+
49
68
  async function handler(_event) {
50
69
  let admin = Stdlib_Option.mapOr(adminEntry, [], e => [e]);
51
70
  let table = process.env["PLUGIN_RM_TABLE"];
@@ -54,13 +73,16 @@ async function handler(_event) {
54
73
  console.error("Platform_ComponentDefinitions: PLUGIN_RM_TABLE env var not set");
55
74
  return admin;
56
75
  }
57
- let items = await Platform_AdminScan_Ops$ReventlessAws.scanAll(table, "contains(#status, :connected)", Object.fromEntries([[
76
+ let rawItems = await Platform_AdminScan_Ops$ReventlessAws.scanAll(table, "contains(#status, :connected)", Object.fromEntries([[
58
77
  "#status",
59
78
  "status"
60
79
  ]]), Object.fromEntries([[
61
80
  ":connected",
62
81
  "Connected"
63
82
  ]]));
83
+ let bucket = Stdlib_Option.getOr(process.env["OFFLOAD_BUCKET"], "");
84
+ let fetch = Offload$Reventless.cachedFetch(key => S3$AwsSdk.GetObjectCommand.getString(bucket, key));
85
+ let items = await Promise.all(rawItems.map(item => resolveStructure(fetch, item)));
64
86
  let userEntries = Platform_AdminScan_Ops$ReventlessAws.latestByName(items, item => str(item, "name"), toEntry);
65
87
  return admin.concat(userEntries);
66
88
  }
@@ -74,6 +96,7 @@ export {
74
96
  filterStructure,
75
97
  toEntry,
76
98
  adminEntry,
99
+ resolveStructure,
77
100
  handler,
78
101
  }
79
102
  /* s Not a pure module */