@reventlessdev/rescript-pulumi-aws 3.0.0-alpha.0 → 3.0.0-alpha.2

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,21 @@
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.2 (2026-08-21)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **core:** make @resolves/[@resolves](https://github.com/resolves)Many work end to end ([4c52957](https://github.com/ReventlessDev/reventless-core/commit/4c5295759dcb4b3eda4f0f4f2c1bc387fed88fcb))
11
+ * **deps:** update sury to 11.0.0-rc.2 to fix unreachable union constructors ([fa5744f](https://github.com/ReventlessDev/reventless-core/commit/fa5744fed8de975e2f14725c856c6e5ce7d04a74))
12
+
13
+
14
+ # 3.0.0-alpha.1 (2026-08-18)
15
+
16
+ ### Bug Fixes
17
+
18
+ * **aws:** normalize the null a table without a sort key resolves to ([8fb15ac](https://github.com/ReventlessDev/reventless-core/commit/8fb15ac066679b6799f4287c2c8d332e2367f599))
19
+
20
+
6
21
  # 3.0.0-alpha.0 (2026-08-18)
7
22
 
8
23
  * feat(sury)!: migrate to sury 11.0.0-rc.1 ([2cf8969](https://github.com/ReventlessDev/reventless-core/commit/2cf8969a222ce1b775563668a4126cb20611966c))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/rescript-pulumi-aws",
3
- "version": "3.0.0-alpha.0",
3
+ "version": "3.0.0-alpha.2",
4
4
  "description": "ReScript bindings for @pulumi/aws",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -21,14 +21,14 @@
21
21
  "dependencies": {
22
22
  "@pulumi/aws": "~7.19.0",
23
23
  "@pulumi/aws-native": "^1.62.0",
24
- "sury": "11.0.0-rc.1",
24
+ "sury": "11.0.0-rc.2",
25
25
  "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.12",
26
26
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19"
27
27
  },
28
28
  "devDependencies": {
29
29
  "esbuild": "^0.25.12",
30
30
  "rescript": "12.3.0",
31
- "sury-ppx": "11.0.0-rc.1"
31
+ "sury-ppx": "11.0.0-rc.2"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "rescript": "12.3.0"
@@ -1082,7 +1082,55 @@ export function response(ctx) {
1082
1082
  // DynamoDB nested resolvers — resolve linked item(s) by ID
1083
1083
  // ---------------------------------------------------------------------------
1084
1084
 
1085
- let resolveId = (~sourceIdField: string) =>
1085
+ /**
1086
+ The response of a cross-table field (`@resolves`) over a Query-shaped read.
1087
+
1088
+ The narrowing is the TARGET's, not the declaring view's: the row comes out of the
1089
+ target's table, so whether this caller may see it is the target's question — asked
1090
+ here with the same `_owns` / `_live` guards every by-key door on that table asks.
1091
+
1092
+ A nested field takes no `includeRetired` argument, so `_wantsRetired` is never
1093
+ true and a retired row never travels through one. A reference that must keep
1094
+ reading as a name after the archive took it is what `{list}Refs` + `@namedWhenRetired`
1095
+ answers.
1096
+ */
1097
+ let resolvedFieldResponse = (
1098
+ ~multi: bool,
1099
+ ~ownerField: option<string>,
1100
+ ~elevatedGroups: array<string>,
1101
+ ~retiredField: option<string>=?,
1102
+ ~retiredValues: option<array<string>>=?,
1103
+ ) =>
1104
+ switch (ownerField, retiredField) {
1105
+ | (None, None) => multi ? resultListResponseCode : firstResultResponseCode
1106
+ | _ =>
1107
+ let ownerPart = switch ownerField {
1108
+ // Takes the row it ignores, for the reason `ownerScopedResponse` gives: a
1109
+ // zero-parameter stub called with one argument is a TS2554 the APPSYNC_JS
1110
+ // type-checker rejects at resolver-create time.
1111
+ | None => "\n const _owns = (row) => true;"
1112
+ | Some(field) =>
1113
+ `
1114
+ // ── owner scoping (generated) ──${ownerGuardPreamble(~ownerField=field, ~elevatedGroups)}`
1115
+ }
1116
+ let retiredPart = retiredGuardPreamble(
1117
+ ~retiredField,
1118
+ ~retiredValues,
1119
+ ~elevatedGroups,
1120
+ ~ownerScoped=ownerField->Option.isSome,
1121
+ )
1122
+ let live = retiredField->Option.isSome ? " && _live(_row)" : ""
1123
+ let body = multi
1124
+ ? ` return (ctx.result.items ?? []).filter(_row => _owns(_row)${live});`
1125
+ : ` const _row = ctx.result.items[0] ?? null;\n return _owns(_row)${live} ? _row : null;`
1126
+ `
1127
+ export function response(ctx) {
1128
+ if (ctx.error) util.error(ctx.error.message, ctx.error.type);${ownerPart}${retiredPart}
1129
+ ${body}
1130
+ }`
1131
+ }
1132
+
1133
+ let resolveId = (~sourceIdField: string, ~response: string=firstResultResponseCode) =>
1086
1134
  `${importUtil}
1087
1135
  export function request(ctx) {
1088
1136
  if (!ctx.source.${sourceIdField}) return runtime.earlyReturn(null);
@@ -1098,10 +1146,15 @@ export function request(ctx) {
1098
1146
  scanIndexForward: (ctx.args.forward ?? true)
1099
1147
  };
1100
1148
  }
1101
- ${firstResultResponseCode}
1149
+ ${response}
1102
1150
  `->Pulumi.Input.make
1103
1151
 
1104
- let resolveIdSort = (~sourceIdField: string, ~sourceSortField: string, ~targetSortField: string) =>
1152
+ let resolveIdSort = (
1153
+ ~sourceIdField: string,
1154
+ ~sourceSortField: string,
1155
+ ~targetSortField: string,
1156
+ ~response: string=firstResultResponseCode,
1157
+ ) =>
1105
1158
  `${importUtil}
1106
1159
  export function request(ctx) {
1107
1160
  return {
@@ -1119,13 +1172,14 @@ export function request(ctx) {
1119
1172
  scanIndexForward: (ctx.args.forward ?? true)
1120
1173
  };
1121
1174
  }
1122
- ${firstResultResponseCode}
1175
+ ${response}
1123
1176
  `->Pulumi.Input.make
1124
1177
 
1125
1178
  let resolveIdSortArgument = (
1126
1179
  ~sourceIdField: string,
1127
1180
  ~sourceSortArgument: string,
1128
1181
  ~targetSortField: string,
1182
+ ~response: string=firstResultResponseCode,
1129
1183
  ) =>
1130
1184
  `${importUtil}
1131
1185
  export function request(ctx) {
@@ -1151,14 +1205,19 @@ export function request(ctx) {
1151
1205
  scanIndexForward: (ctx.args.forward ?? true)
1152
1206
  };
1153
1207
  }
1154
- ${firstResultResponseCode}
1208
+ ${response}
1155
1209
  `->Pulumi.Input.make
1156
1210
 
1157
1211
  // ---------------------------------------------------------------------------
1158
1212
  // DynamoDB nested resolvers — resolve by index
1159
1213
  // ---------------------------------------------------------------------------
1160
1214
 
1161
- let resolveIdByIndex = (~index: string, ~sourceIdField: string, ~targetIdField: string) =>
1215
+ let resolveIdByIndex = (
1216
+ ~index: string,
1217
+ ~sourceIdField: string,
1218
+ ~targetIdField: string,
1219
+ ~response: string=firstResultResponseCode,
1220
+ ) =>
1162
1221
  `${importUtil}
1163
1222
  export function request(ctx) {
1164
1223
  return {
@@ -1174,7 +1233,7 @@ export function request(ctx) {
1174
1233
  scanIndexForward: (ctx.args.forward ?? true)
1175
1234
  };
1176
1235
  }
1177
- ${firstResultResponseCode}
1236
+ ${response}
1178
1237
  `->Pulumi.Input.make
1179
1238
 
1180
1239
  let resolveIdByIndexSort = (
@@ -1183,6 +1242,7 @@ let resolveIdByIndexSort = (
1183
1242
  ~sourceSortField: string,
1184
1243
  ~targetIdField: string,
1185
1244
  ~targetSortField: string,
1245
+ ~response: string=firstResultResponseCode,
1186
1246
  ) =>
1187
1247
  `${importUtil}
1188
1248
  export function request(ctx) {
@@ -1202,7 +1262,7 @@ export function request(ctx) {
1202
1262
  scanIndexForward: (ctx.args.forward ?? true)
1203
1263
  };
1204
1264
  }
1205
- ${firstResultResponseCode}
1265
+ ${response}
1206
1266
  `->Pulumi.Input.make
1207
1267
 
1208
1268
  let resolveIdByIndexSortArgument = (
@@ -1211,6 +1271,7 @@ let resolveIdByIndexSortArgument = (
1211
1271
  ~sourceSortArgument: string,
1212
1272
  ~targetIdField: string,
1213
1273
  ~targetSortField: string,
1274
+ ~response: string=firstResultResponseCode,
1214
1275
  ) =>
1215
1276
  `${importUtil}
1216
1277
  export function request(ctx) {
@@ -1237,12 +1298,27 @@ export function request(ctx) {
1237
1298
  scanIndexForward: (ctx.args.forward ?? true)
1238
1299
  };
1239
1300
  }
1240
- ${firstResultResponseCode}
1301
+ ${response}
1241
1302
  `->Pulumi.Input.make
1242
1303
 
1243
- // resolveIdsreturns a plain string (table name is interpolated by the adapter
1244
- // via Pulumi.Output.apply)
1245
- let resolveIds = (tableName: string, ~idsField: string, ~sortField: option<string>) => {
1304
+ /** `@resolvesMany`the parent's id array batch-read from the target's table.
1305
+
1306
+ Returns a plain string: the table name is interpolated by the adapter via
1307
+ `Pulumi.Output.apply`, because BatchGetItem's `tables` map keys on the literal
1308
+ name.
1309
+
1310
+ Same shape as `batchGetItemsByIds`, and narrowed by the same guards — the
1311
+ target's, since the rows are the target's. Missing ids come back as nulls in
1312
+ the result array (BatchGetItem preserves index correspondence) and are
1313
+ dropped, so the field is shorter rather than null-holed. */
1314
+ let resolveIds = (
1315
+ ~idsField: string,
1316
+ ~sortField: option<string>,
1317
+ ~ownerField: option<string>=?,
1318
+ ~retiredField: option<string>=?,
1319
+ ~retiredValues: option<array<string>>=?,
1320
+ ~elevatedGroups: array<string>=[],
1321
+ ) => (tableName: string) => {
1246
1322
  let keysCode = switch sortField {
1247
1323
  | Some(sf) =>
1248
1324
  `id => ({ id: util.dynamodb.toString(id.id), ${sf}: util.dynamodb.toString(id.${sf}) })`
@@ -1251,23 +1327,32 @@ let resolveIds = (tableName: string, ~idsField: string, ~sortField: option<strin
1251
1327
  `${importUtil}
1252
1328
  import { runtime } from '@aws-appsync/utils';
1253
1329
  export function request(ctx) {
1254
- const idList = ctx.source.${idsField};
1255
- if (idList && idList.length > 0) {
1256
- return {
1257
- operation: 'BatchGetItem',
1258
- tables: {
1259
- '${tableName}': {
1260
- keys: idList.map(${keysCode}),
1261
- consistentRead: true
1262
- }
1330
+ const idList = ctx.source.${idsField} ?? [];
1331
+ if (idList.length === 0) return runtime.earlyReturn([]);
1332
+ return {
1333
+ operation: 'BatchGetItem',
1334
+ tables: {
1335
+ '${tableName}': {
1336
+ keys: idList.map(${keysCode}),
1337
+ consistentRead: true
1263
1338
  }
1264
- };
1265
- }
1266
- return { operation: 'GetItem', key: { id: util.dynamodb.toString(ctx.source.id) } };
1339
+ }
1340
+ };
1267
1341
  }
1268
1342
  export function response(ctx) {
1269
- if (ctx.error) util.error(ctx.error.message, ctx.error.type);
1270
- return ctx.result;
1343
+ if (ctx.error) util.error(ctx.error.message, ctx.error.type);${switch ownerField {
1344
+ | None => ""
1345
+ | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1346
+ }}${retiredGuardPreamble(
1347
+ ~retiredField,
1348
+ ~retiredValues,
1349
+ ~elevatedGroups,
1350
+ ~ownerScoped=ownerField->Option.isSome,
1351
+ )}
1352
+ return (ctx.result?.data?.['${tableName}'] ?? []).filter(item =>
1353
+ item !== null${ownerField->Option.isSome ? " && _owns(item)" : ""}${retiredField->Option.isSome
1354
+ ? " && _live(item)"
1355
+ : ""});
1271
1356
  }
1272
1357
  `
1273
1358
  }
@@ -724,7 +724,28 @@ export function response(ctx) {
724
724
  `;
725
725
  }
726
726
 
727
- function resolveId(sourceIdField) {
727
+ function resolvedFieldResponse(multi, ownerField, elevatedGroups, retiredField, retiredValues) {
728
+ if (ownerField === undefined && retiredField === undefined) {
729
+ if (multi) {
730
+ return resultListResponseCode;
731
+ } else {
732
+ return firstResultResponseCode;
733
+ }
734
+ }
735
+ let ownerPart = ownerField !== undefined ? `
736
+ // ── owner scoping (generated) ──` + ownerGuardPreamble(ownerField, elevatedGroups) : "\n const _owns = (row) => true;";
737
+ let retiredPart = retiredGuardPreamble(retiredField, retiredValues, elevatedGroups, Stdlib_Option.isSome(ownerField));
738
+ let live = Stdlib_Option.isSome(retiredField) ? " && _live(_row)" : "";
739
+ let body = multi ? ` return (ctx.result.items ?? []).filter(_row => _owns(_row)` + live + `);` : ` const _row = ctx.result.items[0] ?? null;\n return _owns(_row)` + live + ` ? _row : null;`;
740
+ return `
741
+ export function response(ctx) {
742
+ if (ctx.error) util.error(ctx.error.message, ctx.error.type);` + ownerPart + retiredPart + `
743
+ ` + body + `
744
+ }`;
745
+ }
746
+
747
+ function resolveId(sourceIdField, responseOpt) {
748
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
728
749
  return importUtil + `
729
750
  export function request(ctx) {
730
751
  if (!ctx.source.` + sourceIdField + `) return runtime.earlyReturn(null);
@@ -740,11 +761,12 @@ export function request(ctx) {
740
761
  scanIndexForward: (ctx.args.forward ?? true)
741
762
  };
742
763
  }
743
- ` + firstResultResponseCode + `
764
+ ` + response + `
744
765
  `;
745
766
  }
746
767
 
747
- function resolveIdSort(sourceIdField, sourceSortField, targetSortField) {
768
+ function resolveIdSort(sourceIdField, sourceSortField, targetSortField, responseOpt) {
769
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
748
770
  return importUtil + `
749
771
  export function request(ctx) {
750
772
  return {
@@ -762,11 +784,12 @@ export function request(ctx) {
762
784
  scanIndexForward: (ctx.args.forward ?? true)
763
785
  };
764
786
  }
765
- ` + firstResultResponseCode + `
787
+ ` + response + `
766
788
  `;
767
789
  }
768
790
 
769
- function resolveIdSortArgument(sourceIdField, sourceSortArgument, targetSortField) {
791
+ function resolveIdSortArgument(sourceIdField, sourceSortArgument, targetSortField, responseOpt) {
792
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
770
793
  return importUtil + `
771
794
  export function request(ctx) {
772
795
  const query = ctx.args.` + sourceSortArgument + `
@@ -791,11 +814,12 @@ export function request(ctx) {
791
814
  scanIndexForward: (ctx.args.forward ?? true)
792
815
  };
793
816
  }
794
- ` + firstResultResponseCode + `
817
+ ` + response + `
795
818
  `;
796
819
  }
797
820
 
798
- function resolveIdByIndex(index, sourceIdField, targetIdField) {
821
+ function resolveIdByIndex(index, sourceIdField, targetIdField, responseOpt) {
822
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
799
823
  return importUtil + `
800
824
  export function request(ctx) {
801
825
  return {
@@ -811,11 +835,12 @@ export function request(ctx) {
811
835
  scanIndexForward: (ctx.args.forward ?? true)
812
836
  };
813
837
  }
814
- ` + firstResultResponseCode + `
838
+ ` + response + `
815
839
  `;
816
840
  }
817
841
 
818
- function resolveIdByIndexSort(index, sourceIdField, sourceSortField, targetIdField, targetSortField) {
842
+ function resolveIdByIndexSort(index, sourceIdField, sourceSortField, targetIdField, targetSortField, responseOpt) {
843
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
819
844
  return importUtil + `
820
845
  export function request(ctx) {
821
846
  return {
@@ -834,11 +859,12 @@ export function request(ctx) {
834
859
  scanIndexForward: (ctx.args.forward ?? true)
835
860
  };
836
861
  }
837
- ` + firstResultResponseCode + `
862
+ ` + response + `
838
863
  `;
839
864
  }
840
865
 
841
- function resolveIdByIndexSortArgument(index, sourceIdField, sourceSortArgument, targetIdField, targetSortField) {
866
+ function resolveIdByIndexSortArgument(index, sourceIdField, sourceSortArgument, targetIdField, targetSortField, responseOpt) {
867
+ let response = responseOpt !== undefined ? responseOpt : firstResultResponseCode;
842
868
  return importUtil + `
843
869
  export function request(ctx) {
844
870
  const query = ctx.args.` + sourceSortArgument + `
@@ -864,34 +890,42 @@ export function request(ctx) {
864
890
  scanIndexForward: (ctx.args.forward ?? true)
865
891
  };
866
892
  }
867
- ` + firstResultResponseCode + `
893
+ ` + response + `
868
894
  `;
869
895
  }
870
896
 
871
- function resolveIds(tableName, idsField, sortField) {
872
- let keysCode = sortField !== undefined ? `id => ({ id: util.dynamodb.toString(id.id), ` + sortField + `: util.dynamodb.toString(id.` + sortField + `) })` : `id => ({ id: util.dynamodb.toString(id) })`;
873
- return importUtil + `
897
+ function resolveIds(idsField, sortField, ownerField, retiredField, retiredValues, $staropt$star) {
898
+ return tableName => {
899
+ let elevatedGroups = $staropt$star !== undefined ? $staropt$star : [];
900
+ let keysCode = sortField !== undefined ? `id => ({ id: util.dynamodb.toString(id.id), ` + sortField + `: util.dynamodb.toString(id.` + sortField + `) })` : `id => ({ id: util.dynamodb.toString(id) })`;
901
+ return importUtil + `
874
902
  import { runtime } from '@aws-appsync/utils';
875
903
  export function request(ctx) {
876
- const idList = ctx.source.` + idsField + `;
877
- if (idList && idList.length > 0) {
878
- return {
879
- operation: 'BatchGetItem',
880
- tables: {
881
- '` + tableName + `': {
882
- keys: idList.map(` + keysCode + `),
883
- consistentRead: true
884
- }
904
+ const idList = ctx.source.` + idsField + ` ?? [];
905
+ if (idList.length === 0) return runtime.earlyReturn([]);
906
+ return {
907
+ operation: 'BatchGetItem',
908
+ tables: {
909
+ '` + tableName + `': {
910
+ keys: idList.map(` + keysCode + `),
911
+ consistentRead: true
885
912
  }
886
- };
887
- }
888
- return { operation: 'GetItem', key: { id: util.dynamodb.toString(ctx.source.id) } };
913
+ }
914
+ };
889
915
  }
890
916
  export function response(ctx) {
891
- if (ctx.error) util.error(ctx.error.message, ctx.error.type);
892
- return ctx.result;
917
+ if (ctx.error) util.error(ctx.error.message, ctx.error.type);` + (
918
+ ownerField !== undefined ? ownerGuardPreamble(ownerField, elevatedGroups) : ""
919
+ ) + retiredGuardPreamble(retiredField, retiredValues, elevatedGroups, Stdlib_Option.isSome(ownerField)) + `
920
+ return (ctx.result?.data?.['` + tableName + `'] ?? []).filter(item =>
921
+ item !== null` + (
922
+ Stdlib_Option.isSome(ownerField) ? " && _owns(item)" : ""
923
+ ) + (
924
+ Stdlib_Option.isSome(retiredField) ? " && _live(item)" : ""
925
+ ) + `);
893
926
  }
894
927
  `;
928
+ };
895
929
  }
896
930
 
897
931
  function batchGetItemsByIds(ownerField, retiredField, retiredValues, $staropt$star) {
@@ -1223,6 +1257,7 @@ export {
1223
1257
  queryByIndexSortFiltered,
1224
1258
  listAllItems,
1225
1259
  listAllItemsConnection,
1260
+ resolvedFieldResponse,
1226
1261
  resolveId,
1227
1262
  resolveIdSort,
1228
1263
  resolveIdSortArgument,
@@ -9,7 +9,9 @@ type t = {
9
9
  name: Pulumi.Output.t<string>,
10
10
  id: Pulumi.Output.t<string>,
11
11
  hashKey: Pulumi.Output.t<string>,
12
- rangeKey: Pulumi.Output.t<option<string>>,
12
+ // Pulumi resolves an absent range key to `null`, which ReScript's `option`
13
+ // (None = undefined) does not accept. Nullable is the shape that arrives.
14
+ rangeKey: Pulumi.Output.t<Nullable.t<string>>,
13
15
  streamEnabled: Pulumi.Output.t<option<bool>>,
14
16
  streamArn: Pulumi.Output.t<string>,
15
17
  streamLabel: Pulumi.Output.t<string>,