@reventlessdev/rescript-pulumi-aws 3.0.0-alpha.10 → 3.0.0-alpha.12

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.12 (2026-09-09)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/rescript-pulumi-aws
9
+
10
+
11
+
12
+
13
+
14
+ # 3.0.0-alpha.11 (2026-09-08)
15
+
16
+ ### Bug Fixes
17
+
18
+ * **aws:** the collector gate waits on the one property an update changes ([2c48193](https://github.com/ReventlessDev/reventless-core/commit/2c481934d58c64b8e637d0df1b051b03cf59a35c))
19
+
20
+
6
21
  # 3.0.0-alpha.10 (2026-09-08)
7
22
 
8
23
  **Note:** Version bump only for package @reventlessdev/rescript-pulumi-aws
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/rescript-pulumi-aws",
3
- "version": "3.0.0-alpha.10",
3
+ "version": "3.0.0-alpha.12",
4
4
  "description": "ReScript bindings for @pulumi/aws",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -22,8 +22,8 @@
22
22
  "@pulumi/aws": "~7.19.0",
23
23
  "@pulumi/aws-native": "^1.62.0",
24
24
  "sury": "11.0.0-rc.2",
25
- "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.16",
26
- "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19"
25
+ "@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.17",
26
+ "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.20"
27
27
  },
28
28
  "devDependencies": {
29
29
  "esbuild": "^0.25.12",
@@ -1,3 +1,7 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Context types
3
+ // ---------------------------------------------------------------------------
4
+
1
5
  /** Bindings for @aws-appsync/utils and AppSync JS resolver context types.
2
6
  Used in resolver source files compiled to APPSYNC_JS — not Pulumi deploy-time code.
3
7
 
@@ -6,11 +10,6 @@
6
10
  AppSync provides the module as an object with named exports. When bundled with
7
11
  esbuild (--external:@aws-appsync/utils), the import is preserved for AppSync runtime.
8
12
  */
9
-
10
- // ---------------------------------------------------------------------------
11
- // Context types
12
- // ---------------------------------------------------------------------------
13
-
14
13
  type error = {
15
14
  message: string,
16
15
  @as("type") type_: string,
@@ -4,12 +4,11 @@
4
4
  exported `request` and `response` functions, ready to be passed as the `code`
5
5
  field of AppSync_Resolver.makeUnitJsResolver / makePipelineJsResolver.
6
6
  */
7
-
8
- // ---------------------------------------------------------------------------
7
+ let // ---------------------------------------------------------------------------
9
8
  // Shared response snippets (inlined into each resolver's template literal)
10
9
  // ---------------------------------------------------------------------------
11
10
 
12
- let resultResponseCode = `
11
+ resultResponseCode = `
13
12
  export function response(ctx) {
14
13
  if (ctx.error) util.error(ctx.error.message, ctx.error.type);
15
14
  return ctx.result;
@@ -191,15 +190,18 @@ let ownerScopedResultResponse = (
191
190
  | _ =>
192
191
  let ownerPart = switch ownerField {
193
192
  // Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
194
- // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
195
- // arguments, but got 1") and AppSync rejects the whole resolver at create
196
- // time with "The code contains one or more errors". Only a door that emits
197
- // the call conditionally is safe with a bare `() => true`, and that is not a
198
- // property worth relying on across three templates.
199
- | None => "\n const _owns = (row) => true;"
193
+ // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
194
+ // arguments, but got 1") and AppSync rejects the whole resolver at create
195
+ // time with "The code contains one or more errors". Only a door that emits
196
+ // the call conditionally is safe with a bare `() => true`, and that is not a
197
+ // property worth relying on across three templates.
198
+ | None => "\n const _owns = (row) => true;"
200
199
  | Some(field) =>
201
200
  `
202
- // ── owner scoping (generated) ──${ownerGuardPreamble(~ownerField=field, ~elevatedGroups)}`
201
+ // ── owner scoping (generated) ──${ownerGuardPreamble(
202
+ ~ownerField=field,
203
+ ~elevatedGroups,
204
+ )}`
203
205
  }
204
206
  let retiredPart = retiredGuardPreamble(
205
207
  ~retiredField,
@@ -210,7 +212,9 @@ let ownerScopedResultResponse = (
210
212
  `
211
213
  export function response(ctx) {
212
214
  if (ctx.error) util.error(ctx.error.message, ctx.error.type);${ownerPart}${retiredPart}
213
- return _owns(ctx.result)${retiredField->Option.isSome ? " && _live(ctx.result)" : ""} ? ctx.result : null;
215
+ return _owns(ctx.result)${retiredField->Option.isSome
216
+ ? " && _live(ctx.result)"
217
+ : ""} ? ctx.result : null;
214
218
  }`
215
219
  }
216
220
 
@@ -226,15 +230,18 @@ let ownerScopedFirstResultResponse = (
226
230
  | _ =>
227
231
  let ownerPart = switch ownerField {
228
232
  // Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
229
- // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
230
- // arguments, but got 1") and AppSync rejects the whole resolver at create
231
- // time with "The code contains one or more errors". Only a door that emits
232
- // the call conditionally is safe with a bare `() => true`, and that is not a
233
- // property worth relying on across three templates.
234
- | None => "\n const _owns = (row) => true;"
233
+ // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
234
+ // arguments, but got 1") and AppSync rejects the whole resolver at create
235
+ // time with "The code contains one or more errors". Only a door that emits
236
+ // the call conditionally is safe with a bare `() => true`, and that is not a
237
+ // property worth relying on across three templates.
238
+ | None => "\n const _owns = (row) => true;"
235
239
  | Some(field) =>
236
240
  `
237
- // ── owner scoping (generated) ──${ownerGuardPreamble(~ownerField=field, ~elevatedGroups)}`
241
+ // ── owner scoping (generated) ──${ownerGuardPreamble(
242
+ ~ownerField=field,
243
+ ~elevatedGroups,
244
+ )}`
238
245
  }
239
246
  let retiredPart = retiredGuardPreamble(
240
247
  ~retiredField,
@@ -255,8 +262,7 @@ export function response(ctx) {
255
262
  // ---------------------------------------------------------------------------
256
263
 
257
264
  /** Pipeline resolver code with no pre-processing and a standard error-check response. */
258
- let pipelinePassThrough =
259
- `${importUtil}
265
+ let pipelinePassThrough = `${importUtil}
260
266
  export function request(ctx) { return {}; }
261
267
  ${resultResponseCode}
262
268
  `->Pulumi.Input.make
@@ -329,8 +335,7 @@ export function request(ctx) {
329
335
  ${ownerScopedResultResponse(~ownerField, ~elevatedGroups, ~retiredField?, ~retiredValues?)}
330
336
  `->Pulumi.Input.make
331
337
 
332
- let queryById =
333
- `${importUtil}
338
+ let queryById = `${importUtil}
334
339
  export function request(ctx) {
335
340
  return {
336
341
  operation: 'Query',
@@ -348,11 +353,11 @@ ${resultResponseCode}
348
353
  Relay pagination: `first`/`after` (forward) or `last`/`before` (backward).
349
354
  Cursor is base64 of the sort key value.
350
355
  Returns a Relay `{ edges, pageInfo }` shape reusing the entity's `Connection` type. */
351
- // A list in everything but its name, so it scopes the way `listAllItemsConnection`
356
+ let // A list in everything but its name, so it scopes the way `listAllItemsConnection`
352
357
  // does — a FilterExpression on the request, not a guard on the response. The
353
358
  // response is where the page is cut, and narrowing after that cut would report
354
359
  // `hasNextPage` from a count the caller was never allowed to see.
355
- let queryItemsWithSortConditions = (
360
+ queryItemsWithSortConditions = (
356
361
  sortField: string,
357
362
  ~ownerField: option<string>=?,
358
363
  ~elevatedGroups: array<string>=[],
@@ -585,7 +590,8 @@ index among that window's matches (`n`). Pre-window cursors carried
585
590
  tag existed came off a Scan. Only a door with more than one read tests it — see
586
591
  `cursorPathGuard`.
587
592
  */
588
- let cursorDecode = (~args: string) => `
593
+ let cursorDecode = (~args: string) =>
594
+ `
589
595
  let _window = null;
590
596
  let _from = 0;
591
597
  let _cursorPath = null;
@@ -779,7 +785,11 @@ export function request(ctx) {
779
785
  values[':' + key] = '' + value;
780
786
  }
781
787
  });
782
- ${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(~retiredField, ~retiredValues, ~elevatedGroups)}${indexCursorPreamble}
788
+ ${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
789
+ ~retiredField,
790
+ ~retiredValues,
791
+ ~elevatedGroups,
792
+ )}${indexCursorPreamble}
783
793
  const result = {
784
794
  operation: 'Query',
785
795
  query,
@@ -842,7 +852,11 @@ export function request(ctx) {
842
852
  values[':' + key] = '' + value;
843
853
  }
844
854
  });
845
- ${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(~retiredField, ~retiredValues, ~elevatedGroups)}${indexCursorPreamble}
855
+ ${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
856
+ ~retiredField,
857
+ ~retiredValues,
858
+ ~elevatedGroups,
859
+ )}${indexCursorPreamble}
846
860
  const result = {
847
861
  operation: 'Query',
848
862
  query,
@@ -863,8 +877,7 @@ ${indexConnectionResponseCode}
863
877
  // DynamoDB read — list all
864
878
  // ---------------------------------------------------------------------------
865
879
 
866
- let listAllItems =
867
- `${importUtil}
880
+ let listAllItems = `${importUtil}
868
881
  export function request(ctx) {
869
882
  return {
870
883
  operation: 'Scan',
@@ -928,7 +941,8 @@ let listAllItemsConnection = (
928
941
  // have nothing to name in the key condition.
929
942
  let ownerIndex = ownerField->Option.isSome ? ownerIndex : None
930
943
  let requireAttributeClause = switch requireAttribute {
931
- | Some(attr) => `
944
+ | Some(attr) =>
945
+ `
932
946
  names['#${attr}'] = '${attr}';
933
947
  parts.push('attribute_exists(#${attr})');`
934
948
  | None => ""
@@ -986,7 +1000,8 @@ let listAllItemsConnection = (
986
1000
  let elevatedLiteral = elevatedGroups->Array.map(g => `'${g}'`)->Array.join(", ")
987
1001
  let exemptPrelude = switch ownerField {
988
1002
  | Some(_) => ""
989
- | None => `
1003
+ | None =>
1004
+ `
990
1005
  const _id = ctx.identity;
991
1006
  const _sub = _id == null ? null : _id.sub;
992
1007
  const _groups = (_id != null && _id.claims != null && _id.claims['cognito:groups']) || [];
@@ -1007,10 +1022,13 @@ ${switch retiredValues {
1007
1022
  // once for the whole clause — a row that states no lifecycle is not
1008
1023
  // retired, the same reading every other adapter takes.
1009
1024
  | Some(states) =>
1010
- let placeholders = states->Array.mapWithIndex((state, i) => (`:retiredValue${Int.toString(i)}`, state))
1025
+ let placeholders =
1026
+ states->Array.mapWithIndex((state, i) => (`:retiredValue${Int.toString(i)}`, state))
1011
1027
  let assignments =
1012
1028
  placeholders
1013
- ->Array.map(((ph, state)) => ` values['${ph}'] = util.dynamodb.toDynamoDB('${state}');`)
1029
+ ->Array.map(((ph, state)) =>
1030
+ ` values['${ph}'] = util.dynamodb.toDynamoDB('${state}');`
1031
+ )
1014
1032
  ->Array.join("\n")
1015
1033
  let comparisons =
1016
1034
  placeholders->Array.map(((ph, _)) => `#retired <> ${ph}`)->Array.join(" AND ")
@@ -1026,16 +1044,19 @@ ${switch retiredValues {
1026
1044
  }
1027
1045
  let filterClauses =
1028
1046
  filterFields
1029
- ->Array.map(f => `
1047
+ ->Array.map(f =>
1048
+ `
1030
1049
  if (filter.${f}Eq !== undefined && filter.${f}Eq !== null && filter.${f}Eq !== '') {
1031
1050
  names['#${f}'] = '${f}';
1032
1051
  values[':${f}Eq'] = util.dynamodb.toDynamoDB(filter.${f}Eq);
1033
1052
  parts.push('#${f} = :${f}Eq');
1034
- }`)
1053
+ }`
1054
+ )
1035
1055
  ->Array.join("")
1036
1056
  let rangeClauses =
1037
1057
  rangeFields
1038
- ->Array.map(f => `
1058
+ ->Array.map(f =>
1059
+ `
1039
1060
  if (filter.${f}From !== undefined && filter.${f}From !== null && filter.${f}From !== '') {
1040
1061
  names['#${f}'] = '${f}';
1041
1062
  values[':${f}From'] = util.dynamodb.toDynamoDB(filter.${f}From);
@@ -1045,10 +1066,10 @@ ${switch retiredValues {
1045
1066
  names['#${f}'] = '${f}';
1046
1067
  values[':${f}To'] = util.dynamodb.toDynamoDB(filter.${f}To);
1047
1068
  parts.push('#${f} <= :${f}To');
1048
- }`)
1069
+ }`
1070
+ )
1049
1071
  ->Array.join("")
1050
- let sortFieldsLiteral =
1051
- sortFields->Array.map(f => `'${f}'`)->Array.join(", ")
1072
+ let sortFieldsLiteral = sortFields->Array.map(f => `'${f}'`)->Array.join(", ")
1052
1073
  // When the Query branch already ordered on the index's own sort key, the page
1053
1074
  // arrives globally ordered and re-sorting it here is the one way to break that
1054
1075
  // order — a sort over a page is not a sort over the caller's rows.
@@ -1090,8 +1111,7 @@ ${switch retiredValues {
1090
1111
  // halves, because both need it: the request to set `scanIndexForward`, the
1091
1112
  // response to leave an already-ordered page alone.
1092
1113
  let indexOrderedExpr = switch (ownerIndex, ownerIndexSortField) {
1093
- | (Some(_), Some(sf)) =>
1094
- `!_exempt && !!(ctx.args.orderBy && ctx.args.orderBy.field === '${sf}')`
1114
+ | (Some(_), Some(sf)) => `!_exempt && !!(ctx.args.orderBy && ctx.args.orderBy.field === '${sf}')`
1095
1115
  | _ => "false"
1096
1116
  }
1097
1117
  // The two reads, chosen by the same test that used to choose a predicate.
@@ -1099,7 +1119,8 @@ ${switch retiredValues {
1099
1119
  // branch inside one resolver — no second field, no second data source, no
1100
1120
  // client change.
1101
1121
  let requestOperation = switch (ownerField, ownerIndex) {
1102
- | (Some(field), Some(index)) => `
1122
+ | (Some(field), Some(index)) =>
1123
+ `
1103
1124
  const _indexOrdered = ${indexOrderedExpr};
1104
1125
  const req = _exempt
1105
1126
  ? {
@@ -1119,7 +1140,8 @@ ${switch retiredValues {
1119
1140
  nextToken: _window,
1120
1141
  scanIndexForward: !(_indexOrdered && ctx.args.orderBy.direction === 'DESC'),
1121
1142
  };`
1122
- | _ => `
1143
+ | _ =>
1144
+ `
1123
1145
  const req = {
1124
1146
  operation: 'Scan',
1125
1147
  limit: ${listPageWindowBudget},
@@ -1130,7 +1152,8 @@ ${switch retiredValues {
1130
1152
  let requestPathGuard = ownerIndex->Option.isSome ? cursorPathGuard : ""
1131
1153
  let responsePathPreamble = switch ownerIndex {
1132
1154
  | None => ""
1133
- | Some(_) => `${ownerIdentityPreamble}
1155
+ | Some(_) =>
1156
+ `${ownerIdentityPreamble}
1134
1157
  const _path = _exempt ? 's' : 'q';
1135
1158
  const _indexOrdered = ${indexOrderedExpr};`
1136
1159
  }
@@ -1224,7 +1247,10 @@ let resolvedFieldResponse = (
1224
1247
  | None => "\n const _owns = (row) => true;"
1225
1248
  | Some(field) =>
1226
1249
  `
1227
- // ── owner scoping (generated) ──${ownerGuardPreamble(~ownerField=field, ~elevatedGroups)}`
1250
+ // ── owner scoping (generated) ──${ownerGuardPreamble(
1251
+ ~ownerField=field,
1252
+ ~elevatedGroups,
1253
+ )}`
1228
1254
  }
1229
1255
  let retiredPart = retiredGuardPreamble(
1230
1256
  ~retiredField,
@@ -1427,13 +1453,14 @@ let resolveIds = (
1427
1453
  ~retiredField: option<string>=?,
1428
1454
  ~retiredValues: option<array<string>>=?,
1429
1455
  ~elevatedGroups: array<string>=[],
1430
- ) => (tableName: string) => {
1431
- let keysCode = switch sortField {
1432
- | Some(sf) =>
1433
- `id => ({ id: util.dynamodb.toString(id.id), ${sf}: util.dynamodb.toString(id.${sf}) })`
1434
- | None => `id => ({ id: util.dynamodb.toString(id) })`
1435
- }
1436
- `${importUtil}
1456
+ ) =>
1457
+ (tableName: string) => {
1458
+ let keysCode = switch sortField {
1459
+ | Some(sf) =>
1460
+ `id => ({ id: util.dynamodb.toString(id.id), ${sf}: util.dynamodb.toString(id.${sf}) })`
1461
+ | None => `id => ({ id: util.dynamodb.toString(id) })`
1462
+ }
1463
+ `${importUtil}
1437
1464
  import { runtime } from '@aws-appsync/utils';
1438
1465
  export function request(ctx) {
1439
1466
  const idList = ctx.source.${idsField} ?? [];
@@ -1450,21 +1477,21 @@ export function request(ctx) {
1450
1477
  }
1451
1478
  export function response(ctx) {
1452
1479
  if (ctx.error) util.error(ctx.error.message, ctx.error.type);${switch ownerField {
1453
- | None => ""
1454
- | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1455
- }}${retiredGuardPreamble(
1456
- ~retiredField,
1457
- ~retiredValues,
1458
- ~elevatedGroups,
1459
- ~ownerScoped=ownerField->Option.isSome,
1460
- )}
1480
+ | None => ""
1481
+ | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1482
+ }}${retiredGuardPreamble(
1483
+ ~retiredField,
1484
+ ~retiredValues,
1485
+ ~elevatedGroups,
1486
+ ~ownerScoped=ownerField->Option.isSome,
1487
+ )}
1461
1488
  return (ctx.result?.data?.['${tableName}'] ?? []).filter(item =>
1462
1489
  item !== null${ownerField->Option.isSome ? " && _owns(item)" : ""}${retiredField->Option.isSome
1463
- ? " && _live(item)"
1464
- : ""});
1490
+ ? " && _live(item)"
1491
+ : ""});
1465
1492
  }
1466
1493
  `
1467
- }
1494
+ }
1468
1495
 
1469
1496
  /** Batched-by-ids — reads `ctx.args.ids: [String!]!` through one BatchGetItem.
1470
1497
  Missing ids drop out; empty input short-circuits without hitting DDB. The
@@ -1475,8 +1502,9 @@ let batchGetItemsByIds = (
1475
1502
  ~retiredField: option<string>=?,
1476
1503
  ~retiredValues: option<array<string>>=?,
1477
1504
  ~elevatedGroups: array<string>=[],
1478
- ) => (tableName: string) =>
1479
- `${importUtil}
1505
+ ) =>
1506
+ (tableName: string) =>
1507
+ `${importUtil}
1480
1508
  import { runtime } from '@aws-appsync/utils';
1481
1509
  export function request(ctx) {
1482
1510
  const ids = ctx.args.ids ?? [];
@@ -1501,18 +1529,18 @@ export function response(ctx) {
1501
1529
  // caller does not own is dropped rather than refused, for the reason the
1502
1530
  // single-key door answers null: distinguishing "not yours" from "not there"
1503
1531
  // would make this door an oracle for which ids exist.${switch ownerField {
1504
- | None => ""
1505
- | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1506
- }}${retiredGuardPreamble(
1507
- ~retiredField,
1508
- ~retiredValues,
1509
- ~elevatedGroups,
1510
- ~ownerScoped=ownerField->Option.isSome,
1511
- )}
1532
+ | None => ""
1533
+ | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1534
+ }}${retiredGuardPreamble(
1535
+ ~retiredField,
1536
+ ~retiredValues,
1537
+ ~elevatedGroups,
1538
+ ~ownerScoped=ownerField->Option.isSome,
1539
+ )}
1512
1540
  return (ctx.result?.data?.['${tableName}'] ?? []).filter(item =>
1513
1541
  item !== null${ownerField->Option.isSome ? " && _owns(item)" : ""}${retiredField->Option.isSome
1514
- ? " && _live(item)"
1515
- : ""});
1542
+ ? " && _live(item)"
1543
+ : ""});
1516
1544
  }
1517
1545
  `
1518
1546
 
@@ -1536,35 +1564,36 @@ let refsByIds = (
1536
1564
  ~imageExpr: option<string>=?,
1537
1565
  ~ownerField: option<string>=?,
1538
1566
  ~elevatedGroups: array<string>=[],
1539
- ) => (tableName: string) => {
1540
- let ownerGuard = switch ownerField {
1541
- // Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
1542
- // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
1543
- // arguments, but got 1") and AppSync rejects the whole resolver at create
1544
- // time with "The code contains one or more errors". Only a door that emits
1545
- // the call conditionally is safe with a bare `() => true`, and that is not a
1546
- // property worth relying on across three templates.
1547
- | None => "\n const _owns = (row) => true;"
1548
- | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1549
- }
1550
- // Retirement, in the vocabulary the row itself uses: a member test for the
1551
- // state form, truthiness for the boolean one. Absent keeps the row live, which
1552
- // is what a row written before the annotation is.
1553
- let retiredExpr = switch (retiredField, retiredValues) {
1554
- | (None, _) => "false"
1555
- | (Some(f), Some(values)) =>
1556
- let literal = values->Array.map(v => `'${v}'`)->Array.join(", ")
1557
- `[${literal}].indexOf(row['${f}']) >= 0`
1558
- | (Some(f), None) => `row['${f}'] === true`
1559
- }
1560
- // Only the state form has a state to name, and only a retired row reports one:
1561
- // this door names rows, it does not publish a lifecycle column to callers the
1562
- // list withholds.
1563
- let stateExpr = switch (retiredField, retiredValues) {
1564
- | (Some(f), Some(_)) => `_retired(row) ? (row['${f}'] ?? null) : null`
1565
- | _ => "null"
1566
- }
1567
- `${importUtil}
1567
+ ) =>
1568
+ (tableName: string) => {
1569
+ let ownerGuard = switch ownerField {
1570
+ // Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
1571
+ // zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
1572
+ // arguments, but got 1") and AppSync rejects the whole resolver at create
1573
+ // time with "The code contains one or more errors". Only a door that emits
1574
+ // the call conditionally is safe with a bare `() => true`, and that is not a
1575
+ // property worth relying on across three templates.
1576
+ | None => "\n const _owns = (row) => true;"
1577
+ | Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
1578
+ }
1579
+ // Retirement, in the vocabulary the row itself uses: a member test for the
1580
+ // state form, truthiness for the boolean one. Absent keeps the row live, which
1581
+ // is what a row written before the annotation is.
1582
+ let retiredExpr = switch (retiredField, retiredValues) {
1583
+ | (None, _) => "false"
1584
+ | (Some(f), Some(values)) =>
1585
+ let literal = values->Array.map(v => `'${v}'`)->Array.join(", ")
1586
+ `[${literal}].indexOf(row['${f}']) >= 0`
1587
+ | (Some(f), None) => `row['${f}'] === true`
1588
+ }
1589
+ // Only the state form has a state to name, and only a retired row reports one:
1590
+ // this door names rows, it does not publish a lifecycle column to callers the
1591
+ // list withholds.
1592
+ let stateExpr = switch (retiredField, retiredValues) {
1593
+ | (Some(f), Some(_)) => `_retired(row) ? (row['${f}'] ?? null) : null`
1594
+ | _ => "null"
1595
+ }
1596
+ `${importUtil}
1568
1597
  import { runtime } from '@aws-appsync/utils';
1569
1598
  export function request(ctx) {
1570
1599
  const ids = ctx.args.ids ?? [];
@@ -1595,14 +1624,13 @@ export function response(ctx) {
1595
1624
  }));
1596
1625
  }
1597
1626
  `
1598
- }
1627
+ }
1599
1628
 
1600
1629
  // ---------------------------------------------------------------------------
1601
1630
  // DynamoDB write
1602
1631
  // ---------------------------------------------------------------------------
1603
1632
 
1604
- let putItem =
1605
- `${importUtil}
1633
+ let putItem = `${importUtil}
1606
1634
  export function request(ctx) {
1607
1635
  return {
1608
1636
  operation: 'PutItem',
@@ -1629,8 +1657,7 @@ export function request(ctx) {
1629
1657
  ${resultResponseCode}
1630
1658
  `->Pulumi.Input.make
1631
1659
 
1632
- let deleteItem =
1633
- `${importUtil}
1660
+ let deleteItem = `${importUtil}
1634
1661
  export function request(ctx) {
1635
1662
  return {
1636
1663
  operation: 'DeleteItem',
@@ -1773,8 +1800,7 @@ export function response(ctx) {
1773
1800
  let authorizeIndexedAccessRequest = authorizeIndexedAccess
1774
1801
 
1775
1802
  /** @deprecated The response check is now part of authorizeIndexedAccess. */
1776
- let authorizeIndexedAccessResponse = (~group as _: string) =>
1777
- resultResponseCode->Pulumi.Input.make
1803
+ let authorizeIndexedAccessResponse = (~group as _: string) => resultResponseCode->Pulumi.Input.make
1778
1804
 
1779
1805
  // ---------------------------------------------------------------------------
1780
1806
  // Response-only helpers
@@ -28,9 +28,7 @@ type args = {
28
28
  mergedApiArn?: Pulumi.Input.t<string>,
29
29
  sourceApiId?: Pulumi.Input.t<string>,
30
30
  sourceApiArn?: Pulumi.Input.t<string>,
31
- sourceApiAssociationConfigs?: Pulumi.Input.t<
32
- array<Pulumi.Input.t<sourceApiAssociationConfig>>,
33
- >,
31
+ sourceApiAssociationConfigs?: Pulumi.Input.t<array<Pulumi.Input.t<sourceApiAssociationConfig>>>,
34
32
  description?: Pulumi.Input.t<string>,
35
33
  }
36
34
 
@@ -1,11 +1,10 @@
1
+ // ── Auth types ────────────────────────────────────────────────────────────────
2
+
1
3
  /** @pulumi/aws-native/appsync/Api — AppSync Events (Pub/Sub) API.
2
4
  Distinct from AppSync GraphQL API (`aws.appsync.GraphQLApi`).
3
5
  Used for real-time server-to-client event push via AppSync Events channels.
4
6
  See: https://www.pulumi.com/registry/packages/aws-native/api-docs/appsync/api
5
7
  */
6
-
7
- // ── Auth types ────────────────────────────────────────────────────────────────
8
-
9
8
  /** Authentication mode for connections / publish / subscribe. */
10
9
  type authMode = {
11
10
  /** Auth type string — use the `authType` constants below. */
@@ -4,7 +4,6 @@
4
4
  Channels within the namespace are addressed as `/default/{channelName}`.
5
5
  See: https://www.pulumi.com/registry/packages/aws-native/api-docs/appsync/channelnamespace
6
6
  */
7
-
8
7
  type authMode = {
9
8
  authType?: Pulumi.Input.t<string>,
10
9
  }
@@ -74,8 +73,5 @@ type args = {
74
73
  }
75
74
 
76
75
  @module("@pulumi/aws-native") @scope("appsync") @new
77
- external make: (
78
- ~name: string,
79
- ~args: args,
80
- ~opts: option<Pulumi.CustomResourceOptions.t>=?,
81
- ) => t = "ChannelNamespace"
76
+ external make: (~name: string, ~args: args, ~opts: option<Pulumi.CustomResourceOptions.t>=?) => t =
77
+ "ChannelNamespace"
@@ -32,8 +32,5 @@ type args = {
32
32
  }
33
33
 
34
34
  @module("@pulumi/aws-native") @scope("appsync") @new
35
- external make: (
36
- ~name: string,
37
- ~args: args,
38
- ~opts: option<Pulumi.CustomResourceOptions.t>=?,
39
- ) => t = "Resolver"
35
+ external make: (~name: string, ~args: args, ~opts: option<Pulumi.CustomResourceOptions.t>=?) => t =
36
+ "Resolver"
@@ -1,7 +1,6 @@
1
1
  /** @pulumi/aws/cloudwatch/logmetricfilter
2
2
  see: https://www.pulumi.com/registry/packages/aws/api-docs/cloudwatch/logmetricfilter/
3
3
  */
4
-
5
4
  /** How matched log events are turned into a CloudWatch metric data point.
6
5
  `value`/`dimensions` use metric-filter JSON selectors (e.g. `"$.value"`). */
7
6
  type metricTransformation = {
@@ -1,7 +1,6 @@
1
1
  /** @pulumi/aws/cloudwatch/metricalarm
2
2
  see: https://www.pulumi.com/registry/packages/aws/api-docs/cloudwatch/metricalarm/
3
3
  */
4
-
5
4
  type t = {arn: Pulumi.Output.t<string>, id: Pulumi.Output.t<string>}
6
5
 
7
6
  /** Single-metric alarm args. `comparisonOperator` uses CloudWatch's operator
@@ -119,7 +119,5 @@ type getResult = {
119
119
  }
120
120
 
121
121
  @module("@pulumi/aws") @scope("cognito") @val
122
- external getUserPoolOutput: (
123
- ~args: getArgs,
124
- ~opts: InvokeOptions.t=?,
125
- ) => Output.t<getResult> = "getUserPoolOutput"
122
+ external getUserPoolOutput: (~args: getArgs, ~opts: InvokeOptions.t=?) => Output.t<getResult> =
123
+ "getUserPoolOutput"
package/src/IAM/IAM.res CHANGED
@@ -103,7 +103,7 @@ module Role = {
103
103
  assumeRolePolicy: servicePrincipal
104
104
  ->Pulumi.Output.apply(principal => Policy.assumeRolePolicy(name, principal))
105
105
  ->Pulumi.Output.asInput,
106
- tags: ?tags,
106
+ ?tags,
107
107
  },
108
108
  ~opts,
109
109
  )
@@ -54,11 +54,8 @@ module EventSubscription = {
54
54
  }
55
55
 
56
56
  @module("@pulumi/aws") @scope("kinesis") @new
57
- external make: (
58
- ~name: string,
59
- ~args: args=?,
60
- ~opts: Pulumi.CustomResourceOptions.t=?
61
- ) => stream = "Stream"
57
+ external make: (~name: string, ~args: args=?, ~opts: Pulumi.CustomResourceOptions.t=?) => stream =
58
+ "Stream"
62
59
 
63
60
  @send
64
61
  external onEvent: (
@@ -66,5 +63,5 @@ external onEvent: (
66
63
  ~name: string,
67
64
  ~handler: Lambda.eventHandlerNoResult<event>,
68
65
  ~args: subscriptionArgs=?,
69
- ~opts: Pulumi.CustomResourceOptions.t=?
66
+ ~opts: Pulumi.CustomResourceOptions.t=?,
70
67
  ) => EventSubscription.t = "onEvent"
@@ -37,5 +37,8 @@ external make: (~name: string, ~args: args, ~opts: Pulumi.CustomResourceOptions.
37
37
  "FunctionUrl"
38
38
 
39
39
  @module("@pulumi/aws") @scope(("lambda", "FunctionUrl"))
40
- external get: (~name: string, ~id: Pulumi.Input.t<string>, ~opts: Pulumi.CustomResourceOptions.t=?) => t =
41
- "get"
40
+ external get: (
41
+ ~name: string,
42
+ ~id: Pulumi.Input.t<string>,
43
+ ~opts: Pulumi.CustomResourceOptions.t=?,
44
+ ) => t = "get"
@@ -88,11 +88,10 @@ let _resolveLayerArnFromSsm = (): option<string> =>
88
88
  * manually.
89
89
  * 3. `None` when both fail — Lambdas deploy without the layer.
90
90
  */
91
- let reventlessLayerArn: option<string> =
92
- switch _layerArnEnv {
93
- | Some(arn) if arn->String.trim->String.length > 0 => Some(arn->String.trim)
94
- | _ => _resolveLayerArnFromSsm()
95
- }
91
+ let reventlessLayerArn: option<string> = switch _layerArnEnv {
92
+ | Some(arn) if arn->String.trim->String.length > 0 => Some(arn->String.trim)
93
+ | _ => _resolveLayerArnFromSsm()
94
+ }
96
95
 
97
96
  @val
98
97
  external environment: option<string> = "process.env.Environment"
@@ -253,14 +252,17 @@ module Function = {
253
252
  id: Pulumi.Output.t<string>,
254
253
  name: Pulumi.Output.t<string>,
255
254
  invokeArn: Pulumi.Output.t<string>,
255
+ /** When AWS last wrote the function. Server-computed and different after
256
+ every code update, which is what separates it from the four identifiers
257
+ above: those are equal before and after, so the engine can resolve them
258
+ from existing state without waiting for the update. Depend on this one to
259
+ wait for the new code to actually be live. */
260
+ lastModified: Pulumi.Output.t<string>,
256
261
  }
257
262
 
258
263
  @module("@pulumi/aws") @scope("lambda") @new
259
- external make: (
260
- ~name: string,
261
- ~args: args,
262
- ~opts: Pulumi.CustomResourceOptions.t=?,
263
- ) => t = "Function"
264
+ external make: (~name: string, ~args: args, ~opts: Pulumi.CustomResourceOptions.t=?) => t =
265
+ "Function"
264
266
 
265
267
  @module("@pulumi/aws") @scope(("lambda", "Function"))
266
268
  external get: (
@@ -4,7 +4,6 @@
4
4
  Aurora (incl. Aurora Serverless v2) Postgres cluster. Pair with one or more
5
5
  `Rds_ClusterInstance` — a cluster has no compute of its own.
6
6
  */
7
-
8
7
  /** See `Rds_Instance.masterUserSecret`. */
9
8
  type masterUserSecret = {
10
9
  kmsKeyId: string,
@@ -1,7 +1,6 @@
1
1
  /** @pulumi/aws/rds/instance
2
2
  see: https://www.pulumi.com/registry/packages/aws/api-docs/rds/instance
3
3
  */
4
-
5
4
  /** One entry of `masterUserSecrets`, populated when `manageMasterUserPassword`
6
5
  is true — RDS creates and rotates the master password in Secrets Manager and
7
6
  reports the secret ARN here. */
@@ -34,5 +34,4 @@ type args = {
34
34
  }
35
35
 
36
36
  @module("@pulumi/aws") @scope("rds") @new
37
- external make: (~name: string, ~args: args, ~opts: Pulumi.CustomResourceOptions.t=?) => t =
38
- "Proxy"
37
+ external make: (~name: string, ~args: args, ~opts: Pulumi.CustomResourceOptions.t=?) => t = "Proxy"
@@ -1,9 +1,7 @@
1
1
  /** @pulumi/aws/s3/BucketV2
2
2
  see: https://www.pulumi.com/registry/packages/aws/api-docs/s3/bucketv2
3
3
  */
4
- @module("@pulumi/aws")
5
- @scope("s3")
6
- @new
4
+ @module("@pulumi/aws") @scope("s3") @new
7
5
  external make: (
8
6
  ~name: string,
9
7
  ~args: S3_Bucket.args=?,
@@ -18,9 +18,8 @@ let cert = Acm.Certificate.make(
18
18
  ~opts={provider: usEast1},
19
19
  )
20
20
 
21
- let firstValidationOption = cert.domainValidationOptions->Pulumi.Output.apply(opts =>
22
- opts->Array.getUnsafe(0)
23
- )
21
+ let firstValidationOption =
22
+ cert.domainValidationOptions->Pulumi.Output.apply(opts => opts->Array.getUnsafe(0))
24
23
 
25
24
  let validationRecord = Route53.Record.make(
26
25
  ~name="example-cert-validation",
@@ -8,9 +8,7 @@
8
8
  let mergedExecRole = IAM.Role.make(
9
9
  ~name="example-merged-exec-role",
10
10
  ~args={
11
- assumeRolePolicy: Pulumi.Input.make(
12
- `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"appsync.amazonaws.com"},"Action":"sts:AssumeRole"}]}`,
13
- ),
11
+ assumeRolePolicy: Pulumi.Input.make(`{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"appsync.amazonaws.com"},"Action":"sts:AssumeRole"}]}`),
14
12
  },
15
13
  )
16
14