@reventlessdev/rescript-pulumi-aws 2.4.0-alpha.76 → 2.4.0-alpha.77
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,15 @@
|
|
|
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
|
+
# 2.4.0-alpha.77 (2026-08-16)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **core:** exclude retired rows from reads a caller may not widen ([662f31a](https://github.com/ReventlessDev/reventless-core/commit/662f31abb717bda5154199d349da6dcf8e2d3e78))
|
|
11
|
+
* **core:** let [@retired](https://github.com/retired) name a lifecycle state, not only a boolean ([6bb346b](https://github.com/ReventlessDev/reventless-core/commit/6bb346b4f6a5f33826fc24537953482a76067177))
|
|
12
|
+
* **core:** mark the state that retires a row, and allow more than one ([cb1461f](https://github.com/ReventlessDev/reventless-core/commit/cb1461f024d3ca3b53fd9c8b010a054e3fcc4555))
|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
# 2.4.0-alpha.76 (2026-08-15)
|
|
7
16
|
|
|
8
17
|
**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": "2.4.0-alpha.
|
|
3
|
+
"version": "2.4.0-alpha.77",
|
|
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-alpha.4",
|
|
25
|
-
"@reventlessdev/rescript-
|
|
26
|
-
"@reventlessdev/rescript-
|
|
25
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
26
|
+
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.11"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"esbuild": "^0.25.12",
|
|
@@ -447,6 +447,13 @@ let listAllItemsConnection = (
|
|
|
447
447
|
// than a per-request one.
|
|
448
448
|
~ownerField: option<string>=?,
|
|
449
449
|
~elevatedGroups: array<string>=[],
|
|
450
|
+
// The state's `@retired` field, when it declares one. Baked in for the same
|
|
451
|
+
// reason `ownerField` is: there is no Lambda in this path to read it at
|
|
452
|
+
// request time.
|
|
453
|
+
~retiredField: option<string>=?,
|
|
454
|
+
// The states that retire the row, for the state form of the annotation.
|
|
455
|
+
// Absent is the boolean form, where the value is always `true`.
|
|
456
|
+
~retiredValues: option<array<string>>=?,
|
|
450
457
|
) => {
|
|
451
458
|
let requireAttributeClause = switch requireAttribute {
|
|
452
459
|
| Some(attr) => `
|
|
@@ -480,6 +487,70 @@ let listAllItemsConnection = (
|
|
|
480
487
|
parts.push('#owner = :owner');
|
|
481
488
|
}`
|
|
482
489
|
}
|
|
490
|
+
// ── retirement narrowing (generated) ──
|
|
491
|
+
// Reuses `_exempt` when the owner clause already computed it, and computes its
|
|
492
|
+
// own when it did not — the two clauses are independently optional and either
|
|
493
|
+
// may be the only one present.
|
|
494
|
+
//
|
|
495
|
+
// `includeRetired` IS read from ctx.args, unlike the owner predicate, and the
|
|
496
|
+
// difference is deliberate: this argument does not say which rows the caller
|
|
497
|
+
// wants, it asks to lift a restriction, and it is honoured only inside the
|
|
498
|
+
// `_exempt` branch. A non-exempt caller passing it changes nothing.
|
|
499
|
+
//
|
|
500
|
+
// `attribute_not_exists OR = false` rather than `<> true`: a row written before
|
|
501
|
+
// the annotation existed carries no such attribute, and DynamoDB's `<>` does
|
|
502
|
+
// not match a missing one — the whole view would come back empty on the day
|
|
503
|
+
// the annotation lands.
|
|
504
|
+
//
|
|
505
|
+
// The state form compares `<>` against the retiring state instead, under the
|
|
506
|
+
// same `attribute_not_exists` guard and for the same reason. An equality
|
|
507
|
+
// predicate over an enum-valued attribute indexes exactly as a boolean one
|
|
508
|
+
// does, so the warning about an unindexed retirement field carries over
|
|
509
|
+
// unchanged.
|
|
510
|
+
let retiredClause = switch retiredField {
|
|
511
|
+
| None => ""
|
|
512
|
+
| Some(field) =>
|
|
513
|
+
let elevatedLiteral = elevatedGroups->Array.map(g => `'${g}'`)->Array.join(", ")
|
|
514
|
+
let exemptPrelude = switch ownerField {
|
|
515
|
+
| Some(_) => ""
|
|
516
|
+
| None => `
|
|
517
|
+
const _id = ctx.identity;
|
|
518
|
+
const _sub = _id == null ? null : _id.sub;
|
|
519
|
+
const _groups = (_id != null && _id.claims != null && _id.claims['cognito:groups']) || [];
|
|
520
|
+
const _elevated = [${elevatedLiteral}];
|
|
521
|
+
const _exempt = _sub == null || _groups.some(g => _elevated.indexOf(g) >= 0);`
|
|
522
|
+
}
|
|
523
|
+
`${exemptPrelude}
|
|
524
|
+
// ── retirement narrowing (generated) ──
|
|
525
|
+
const _wantsRetired = _exempt && ctx.args.includeRetired === true;
|
|
526
|
+
if (!_wantsRetired) {
|
|
527
|
+
names['#retired'] = '${field}';
|
|
528
|
+
${switch retiredValues {
|
|
529
|
+
| None => ` values[':retiredFalse'] = util.dynamodb.toDynamoDB(false);
|
|
530
|
+
parts.push('(attribute_not_exists(#retired) OR #retired = :retiredFalse)');`
|
|
531
|
+
// One `<>` per state, ANDed, rather than `NOT IN`: DynamoDB's `IN` needs a
|
|
532
|
+
// parenthesised operand list built from the same placeholders anyway, and
|
|
533
|
+
// the conjunction keeps `attribute_not_exists` covering the absent case
|
|
534
|
+
// once for the whole clause — a row that states no lifecycle is not
|
|
535
|
+
// retired, the same reading every other adapter takes.
|
|
536
|
+
| Some(states) =>
|
|
537
|
+
let placeholders = states->Array.mapWithIndex((state, i) => (`:retiredValue${Int.toString(i)}`, state))
|
|
538
|
+
let assignments =
|
|
539
|
+
placeholders
|
|
540
|
+
->Array.map(((ph, state)) => ` values['${ph}'] = util.dynamodb.toDynamoDB('${state}');`)
|
|
541
|
+
->Array.join("\n")
|
|
542
|
+
let comparisons =
|
|
543
|
+
placeholders->Array.map(((ph, _)) => `#retired <> ${ph}`)->Array.join(" AND ")
|
|
544
|
+
// A set naming nothing withdraws nothing, so it pushes no predicate down.
|
|
545
|
+
switch placeholders {
|
|
546
|
+
| [] => ""
|
|
547
|
+
| _ =>
|
|
548
|
+
`${assignments}
|
|
549
|
+
parts.push('(attribute_not_exists(#retired) OR (${comparisons}))');`
|
|
550
|
+
}
|
|
551
|
+
}}
|
|
552
|
+
}`
|
|
553
|
+
}
|
|
483
554
|
let filterClauses =
|
|
484
555
|
filterFields
|
|
485
556
|
->Array.map(f => `
|
|
@@ -569,7 +640,7 @@ export function request(ctx) {
|
|
|
569
640
|
return key;
|
|
570
641
|
});
|
|
571
642
|
parts.push('#id IN (' + placeholders.join(', ') + ')');
|
|
572
|
-
}${filterClauses}${rangeClauses}${requireAttributeClause}${ownerClause}
|
|
643
|
+
}${filterClauses}${rangeClauses}${requireAttributeClause}${ownerClause}${retiredClause}
|
|
573
644
|
// The cursor is base64(JSON({ token, index })); decode the after arg back to the raw
|
|
574
645
|
// DynamoDB continuation token the response side emitted (Fix 1 round-trip).
|
|
575
646
|
let after = null;
|
|
@@ -360,7 +360,7 @@ export function request(ctx) {
|
|
|
360
360
|
` + resultResponseCode + `
|
|
361
361
|
`;
|
|
362
362
|
|
|
363
|
-
function listAllItemsConnection(labelField, filterFieldsOpt, rangeFieldsOpt, sortFieldsOpt, requireAttribute, ownerField, elevatedGroupsOpt) {
|
|
363
|
+
function listAllItemsConnection(labelField, filterFieldsOpt, rangeFieldsOpt, sortFieldsOpt, requireAttribute, ownerField, elevatedGroupsOpt, retiredField, retiredValues) {
|
|
364
364
|
let filterFields = filterFieldsOpt !== undefined ? filterFieldsOpt : [];
|
|
365
365
|
let rangeFields = rangeFieldsOpt !== undefined ? rangeFieldsOpt : [];
|
|
366
366
|
let sortFields = sortFieldsOpt !== undefined ? sortFieldsOpt : [];
|
|
@@ -391,6 +391,39 @@ function listAllItemsConnection(labelField, filterFieldsOpt, rangeFieldsOpt, sor
|
|
|
391
391
|
} else {
|
|
392
392
|
ownerClause = "";
|
|
393
393
|
}
|
|
394
|
+
let retiredClause;
|
|
395
|
+
if (retiredField !== undefined) {
|
|
396
|
+
let elevatedLiteral$1 = elevatedGroups.map(g => `'` + g + `'`).join(", ");
|
|
397
|
+
let exemptPrelude = ownerField !== undefined ? "" : `
|
|
398
|
+
const _id = ctx.identity;
|
|
399
|
+
const _sub = _id == null ? null : _id.sub;
|
|
400
|
+
const _groups = (_id != null && _id.claims != null && _id.claims['cognito:groups']) || [];
|
|
401
|
+
const _elevated = [` + elevatedLiteral$1 + `];
|
|
402
|
+
const _exempt = _sub == null || _groups.some(g => _elevated.indexOf(g) >= 0);`;
|
|
403
|
+
let tmp;
|
|
404
|
+
if (retiredValues !== undefined) {
|
|
405
|
+
let placeholders = retiredValues.map((state, i) => [
|
|
406
|
+
`:retiredValue` + i.toString(),
|
|
407
|
+
state
|
|
408
|
+
]);
|
|
409
|
+
let assignments = placeholders.map(param => ` values['` + param[0] + `'] = util.dynamodb.toDynamoDB('` + param[1] + `');`).join("\n");
|
|
410
|
+
let comparisons = placeholders.map(param => `#retired <> ` + param[0]).join(" AND ");
|
|
411
|
+
tmp = placeholders.length !== 0 ? assignments + `
|
|
412
|
+
parts.push('(attribute_not_exists(#retired) OR (` + comparisons + `))');` : "";
|
|
413
|
+
} else {
|
|
414
|
+
tmp = ` values[':retiredFalse'] = util.dynamodb.toDynamoDB(false);
|
|
415
|
+
parts.push('(attribute_not_exists(#retired) OR #retired = :retiredFalse)');`;
|
|
416
|
+
}
|
|
417
|
+
retiredClause = exemptPrelude + `
|
|
418
|
+
// ── retirement narrowing (generated) ──
|
|
419
|
+
const _wantsRetired = _exempt && ctx.args.includeRetired === true;
|
|
420
|
+
if (!_wantsRetired) {
|
|
421
|
+
names['#retired'] = '` + retiredField + `';
|
|
422
|
+
` + tmp + `
|
|
423
|
+
}`;
|
|
424
|
+
} else {
|
|
425
|
+
retiredClause = "";
|
|
426
|
+
}
|
|
394
427
|
let filterClauses = filterFields.map(f => `
|
|
395
428
|
if (filter.` + f + `Eq !== undefined && filter.` + f + `Eq !== null && filter.` + f + `Eq !== '') {
|
|
396
429
|
names['#` + f + `'] = '` + f + `';
|
|
@@ -460,7 +493,7 @@ export function request(ctx) {
|
|
|
460
493
|
return key;
|
|
461
494
|
});
|
|
462
495
|
parts.push('#id IN (' + placeholders.join(', ') + ')');
|
|
463
|
-
}` + filterClauses + rangeClauses + requireAttributeClause + ownerClause + `
|
|
496
|
+
}` + filterClauses + rangeClauses + requireAttributeClause + ownerClause + retiredClause + `
|
|
464
497
|
// The cursor is base64(JSON({ token, index })); decode the after arg back to the raw
|
|
465
498
|
// DynamoDB continuation token the response side emitted (Fix 1 round-trip).
|
|
466
499
|
let after = null;
|