@reventlessdev/rescript-pulumi-aws 3.0.0-alpha.4 → 3.0.0-alpha.40
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 +300 -0
- package/package.json +8 -7
- package/rescript.json +2 -1
- package/src/AppSync/AppSync_ResolverRuntime.res +4 -5
- package/src/AppSync/AppSync_Resolver_Functions.res +281 -169
- package/src/AppSync/AppSync_Resolver_Functions.res.mjs +116 -72
- package/src/AppSync/AppSync_SourceApiAssociation.res +1 -3
- package/src/AwsNative/AppSync/AwsNative_AppSync_Api.res +2 -3
- package/src/AwsNative/AppSync/AwsNative_AppSync_ChannelNamespace.res +2 -6
- package/src/AwsNative/AppSync/AwsNative_AppSync_Resolver.res +2 -5
- package/src/Cloudwatch/Cloudwatch_EventRule.res +4 -0
- package/src/Cloudwatch/Cloudwatch_EventTarget.res +11 -0
- package/src/Cloudwatch/Cloudwatch_LogMetricFilter.res +0 -1
- package/src/Cloudwatch/Cloudwatch_MetricAlarm.res +1 -2
- package/src/Cognito/Cognito_UserPool.res +2 -4
- package/src/IAM/IAM.res +1 -1
- package/src/IAM/PolicyDocument.res +2 -2
- package/src/IAM/PolicyDocument.res.mjs +3 -3
- package/src/Kinesis/Kinesis_Stream.res +3 -6
- package/src/Kms/Kms.res +5 -0
- package/src/Kms/Kms.res.mjs +12 -0
- package/src/Kms/Kms_Alias.res +16 -0
- package/src/Kms/Kms_Alias.res.mjs +2 -0
- package/src/Kms/Kms_Key.res +23 -0
- package/src/Kms/Kms_Key.res.mjs +2 -0
- package/src/Lambda/FunctionUrl.res +5 -2
- package/src/Lambda/Lambda.res +139 -53
- package/src/Lambda/Lambda.res.mjs +152 -23
- package/src/Rds/Rds_Cluster.res +0 -1
- package/src/Rds/Rds_Instance.res +0 -1
- package/src/Rds/Rds_Proxy.res +1 -2
- package/src/S3/S3_Bucket.res +1 -1
- package/src/S3/S3_BucketV2.res +1 -3
- package/src/SNS/SNS_Topic.res +9 -9
- package/src/Scheduler/Scheduler.res +4 -0
- package/src/Scheduler/Scheduler.res.mjs +9 -0
- package/src/Scheduler/Scheduler_ScheduleGroup.res +14 -0
- package/src/Scheduler/Scheduler_ScheduleGroup.res.mjs +2 -0
- package/src/SecretsManager/GetSecretVersion.res +1 -1
- package/src/example/AlarmMailExample.res +34 -0
- package/src/example/AlarmMailExample.res.mjs +44 -0
- package/src/example/CustomDomainExample.res +2 -3
- package/src/example/MergedApiExample.res +1 -3
- package/tests/AppSync_Resolver_FunctionsTest.mjs +141 -23
|
@@ -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
|
-
|
|
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;
|
|
@@ -62,6 +61,21 @@ let exemptPreamble = (~elevatedGroups: array<string>) => {
|
|
|
62
61
|
const _exempt = _sub == null || _groups.some(g => _elevated.indexOf(g) >= 0);`
|
|
63
62
|
}
|
|
64
63
|
|
|
64
|
+
/**
|
|
65
|
+
A view row's `_change` field: the stored value for an exempt caller, null for anyone else.
|
|
66
|
+
Answered from the request step, so the view's data source is never called.
|
|
67
|
+
*/
|
|
68
|
+
let rowChangeField = (~field: string, ~elevatedGroups: array<string>): Pulumi.Input.t<string> =>
|
|
69
|
+
`import { util, runtime } from '@aws-appsync/utils';
|
|
70
|
+
export function request(ctx) {${exemptPreamble(~elevatedGroups)}
|
|
71
|
+
const _row = ctx.source;
|
|
72
|
+
return runtime.earlyReturn(_exempt && _row != null && _row['${field}'] != null ? _row['${field}'] : null);
|
|
73
|
+
}
|
|
74
|
+
export function response(ctx) {
|
|
75
|
+
return ctx.result;
|
|
76
|
+
}
|
|
77
|
+
`->Pulumi.Input.make
|
|
78
|
+
|
|
65
79
|
/**
|
|
66
80
|
A by-key read's retirement guard: `_live(row)`, true when the caller may see it.
|
|
67
81
|
The post-read half of what `listAllItemsConnection` pushes into a
|
|
@@ -191,15 +205,18 @@ let ownerScopedResultResponse = (
|
|
|
191
205
|
| _ =>
|
|
192
206
|
let ownerPart = switch ownerField {
|
|
193
207
|
// Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
// zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
|
|
209
|
+
// arguments, but got 1") and AppSync rejects the whole resolver at create
|
|
210
|
+
// time with "The code contains one or more errors". Only a door that emits
|
|
211
|
+
// the call conditionally is safe with a bare `() => true`, and that is not a
|
|
212
|
+
// property worth relying on across three templates.
|
|
213
|
+
| None => "\n const _owns = (row) => true;"
|
|
200
214
|
| Some(field) =>
|
|
201
215
|
`
|
|
202
|
-
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
216
|
+
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
217
|
+
~ownerField=field,
|
|
218
|
+
~elevatedGroups,
|
|
219
|
+
)}`
|
|
203
220
|
}
|
|
204
221
|
let retiredPart = retiredGuardPreamble(
|
|
205
222
|
~retiredField,
|
|
@@ -210,7 +227,9 @@ let ownerScopedResultResponse = (
|
|
|
210
227
|
`
|
|
211
228
|
export function response(ctx) {
|
|
212
229
|
if (ctx.error) util.error(ctx.error.message, ctx.error.type);${ownerPart}${retiredPart}
|
|
213
|
-
return _owns(ctx.result)${retiredField->Option.isSome
|
|
230
|
+
return _owns(ctx.result)${retiredField->Option.isSome
|
|
231
|
+
? " && _live(ctx.result)"
|
|
232
|
+
: ""} ? ctx.result : null;
|
|
214
233
|
}`
|
|
215
234
|
}
|
|
216
235
|
|
|
@@ -226,15 +245,18 @@ let ownerScopedFirstResultResponse = (
|
|
|
226
245
|
| _ =>
|
|
227
246
|
let ownerPart = switch ownerField {
|
|
228
247
|
// Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
// zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
|
|
249
|
+
// arguments, but got 1") and AppSync rejects the whole resolver at create
|
|
250
|
+
// time with "The code contains one or more errors". Only a door that emits
|
|
251
|
+
// the call conditionally is safe with a bare `() => true`, and that is not a
|
|
252
|
+
// property worth relying on across three templates.
|
|
253
|
+
| None => "\n const _owns = (row) => true;"
|
|
235
254
|
| Some(field) =>
|
|
236
255
|
`
|
|
237
|
-
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
256
|
+
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
257
|
+
~ownerField=field,
|
|
258
|
+
~elevatedGroups,
|
|
259
|
+
)}`
|
|
238
260
|
}
|
|
239
261
|
let retiredPart = retiredGuardPreamble(
|
|
240
262
|
~retiredField,
|
|
@@ -255,8 +277,7 @@ export function response(ctx) {
|
|
|
255
277
|
// ---------------------------------------------------------------------------
|
|
256
278
|
|
|
257
279
|
/** Pipeline resolver code with no pre-processing and a standard error-check response. */
|
|
258
|
-
let pipelinePassThrough =
|
|
259
|
-
`${importUtil}
|
|
280
|
+
let pipelinePassThrough = `${importUtil}
|
|
260
281
|
export function request(ctx) { return {}; }
|
|
261
282
|
${resultResponseCode}
|
|
262
283
|
`->Pulumi.Input.make
|
|
@@ -329,8 +350,7 @@ export function request(ctx) {
|
|
|
329
350
|
${ownerScopedResultResponse(~ownerField, ~elevatedGroups, ~retiredField?, ~retiredValues?)}
|
|
330
351
|
`->Pulumi.Input.make
|
|
331
352
|
|
|
332
|
-
let queryById =
|
|
333
|
-
`${importUtil}
|
|
353
|
+
let queryById = `${importUtil}
|
|
334
354
|
export function request(ctx) {
|
|
335
355
|
return {
|
|
336
356
|
operation: 'Query',
|
|
@@ -348,11 +368,11 @@ ${resultResponseCode}
|
|
|
348
368
|
Relay pagination: `first`/`after` (forward) or `last`/`before` (backward).
|
|
349
369
|
Cursor is base64 of the sort key value.
|
|
350
370
|
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`
|
|
371
|
+
let // A list in everything but its name, so it scopes the way `listAllItemsConnection`
|
|
352
372
|
// does — a FilterExpression on the request, not a guard on the response. The
|
|
353
373
|
// response is where the page is cut, and narrowing after that cut would report
|
|
354
374
|
// `hasNextPage` from a count the caller was never allowed to see.
|
|
355
|
-
|
|
375
|
+
queryItemsWithSortConditions = (
|
|
356
376
|
sortField: string,
|
|
357
377
|
~ownerField: option<string>=?,
|
|
358
378
|
~elevatedGroups: array<string>=[],
|
|
@@ -559,9 +579,26 @@ the survivors serves short — usually empty — pages under a selective filter.
|
|
|
559
579
|
no loops in APPSYNC_JS the door reads wider instead and addresses the surplus by
|
|
560
580
|
position. 1 MB caps a page anyway, hence 1000; `filtered` is the JS expression
|
|
561
581
|
saying whether a filter was pushed down.
|
|
582
|
+
|
|
583
|
+
An unfiltered read takes one row past the page. DynamoDB hands back a token
|
|
584
|
+
whenever it stops AT the limit, end of data or not, so a read of exactly the page
|
|
585
|
+
reports a next page that comes back blank; the extra row is what says one exists.
|
|
562
586
|
*/
|
|
563
587
|
let pageWindowBudget = (~filtered: string) =>
|
|
564
|
-
`(${filtered} ? (_first > 1000 ? _first : 1000) : _first + _from)`
|
|
588
|
+
`(${filtered} ? (_first > 1000 ? _first : 1000) : _first + _from + 1)`
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
The same budget for the full-list door, which may also read backward.
|
|
592
|
+
|
|
593
|
+
A backward page is the slice `[_from, _upTo)` of the window, so the read has to
|
|
594
|
+
reach `_upTo` rows into it — `_first + _from` would stop short and hand back a
|
|
595
|
+
page with its tail missing. Forward reads one row past the page, for the reason
|
|
596
|
+
`pageWindowBudget` gives; a backward page needs none, as one provably follows it.
|
|
597
|
+
*/
|
|
598
|
+
let listPageWindowBudget = {
|
|
599
|
+
let need = "(_backward ? _upTo : _first + _from + 1)"
|
|
600
|
+
`(parts.length > 0 ? (${need} > 1000 ? ${need} : 1000) : ${need})`
|
|
601
|
+
}
|
|
565
602
|
|
|
566
603
|
/**
|
|
567
604
|
Decodes `after` into the window it names (`t`, the token opening it) and the row's
|
|
@@ -573,7 +610,8 @@ index among that window's matches (`n`). Pre-window cursors carried
|
|
|
573
610
|
tag existed came off a Scan. Only a door with more than one read tests it — see
|
|
574
611
|
`cursorPathGuard`.
|
|
575
612
|
*/
|
|
576
|
-
let cursorDecode = (~args: string) =>
|
|
613
|
+
let cursorDecode = (~args: string) =>
|
|
614
|
+
`
|
|
577
615
|
let _window = null;
|
|
578
616
|
let _from = 0;
|
|
579
617
|
let _cursorPath = null;
|
|
@@ -597,21 +635,74 @@ let cursorPathGuard = `
|
|
|
597
635
|
util.error('This cursor belongs to a different read of this list; restart from the first page.', 'CursorPathMismatch');
|
|
598
636
|
}`
|
|
599
637
|
|
|
638
|
+
/**
|
|
639
|
+
The full-list door's cursor decode, which unlike `cursorDecode` may run backward.
|
|
640
|
+
|
|
641
|
+
A `{t, n}` cursor names a position INSIDE a read window, and a window is re-read
|
|
642
|
+
from its own token — which forward paging already relies on to resume mid-window.
|
|
643
|
+
Backward is the same move in the other direction: re-read the window `before`
|
|
644
|
+
names and cut the page that ends at `n`, `[n - first, n)`. No new cursor shape, no
|
|
645
|
+
index, and no assumption forward paging does not already make.
|
|
646
|
+
|
|
647
|
+
What it cannot do is cross into an EARLIER window: DynamoDB's continuation chain
|
|
648
|
+
walks one way, so a window cannot name the one before it. `_upTo <= 0` with a
|
|
649
|
+
non-null window is that case, and it is the only one still refused.
|
|
650
|
+
|
|
651
|
+
Declares `_first` (the response's slicing needs it before `connectionPageResponse`
|
|
652
|
+
would have declared it, so that one omits it here).
|
|
653
|
+
*/
|
|
654
|
+
let listCursorPreamble = `
|
|
655
|
+
const _first = ctx.args.first ?? 50;
|
|
656
|
+
let _window = null;
|
|
657
|
+
let _from = 0;
|
|
658
|
+
let _cursorPath = null;
|
|
659
|
+
let _backward = false;
|
|
660
|
+
let _upTo = -1;
|
|
661
|
+
if (ctx.args.before != null && ctx.args.before !== '') {
|
|
662
|
+
const _c = JSON.parse(util.base64Decode(ctx.args.before));
|
|
663
|
+
_window = (_c.t !== undefined ? _c.t : _c.token) ?? null;
|
|
664
|
+
_cursorPath = _c.p ?? 's';
|
|
665
|
+
_backward = true;
|
|
666
|
+
_upTo = _c.n !== undefined ? _c.n : 0;
|
|
667
|
+
_from = (_upTo - _first) > 0 ? (_upTo - _first) : 0;
|
|
668
|
+
} else if (ctx.args.after != null && ctx.args.after !== '') {
|
|
669
|
+
const _c = JSON.parse(util.base64Decode(ctx.args.after));
|
|
670
|
+
_window = (_c.t !== undefined ? _c.t : _c.token) ?? null;
|
|
671
|
+
_from = _c.n !== undefined ? _c.n + 1 : 0;
|
|
672
|
+
_cursorPath = _c.p ?? 's';
|
|
673
|
+
}`
|
|
674
|
+
|
|
600
675
|
/**
|
|
601
676
|
Cuts the requested page out of the returned window. Expects `items` (sorted, if the
|
|
602
677
|
door sorts) plus `_window` / `_from` from `cursorDecode`. `pathExpr` is the JS
|
|
603
678
|
expression naming which read minted these cursors, for a door that has two.
|
|
679
|
+
|
|
680
|
+
`bidirectional` is the full-list door, whose page may have been cut backward: it
|
|
681
|
+
reads `_backward` / `_upTo` from `listCursorPreamble` and takes `_first` from
|
|
682
|
+
there rather than declaring its own.
|
|
604
683
|
*/
|
|
605
|
-
let connectionPageResponse = (~pathExpr: option<string
|
|
684
|
+
let connectionPageResponse = (~pathExpr: option<string>=?, ~bidirectional: bool=false) => {
|
|
606
685
|
let tag = switch pathExpr {
|
|
607
686
|
| None => ""
|
|
608
687
|
| Some(e) => `, p: ${e}`
|
|
609
688
|
}
|
|
610
|
-
|
|
611
|
-
|
|
689
|
+
let firstDecl = bidirectional ? "" : "\n const _first = ctx.args.first ?? 50;"
|
|
690
|
+
let slice = bidirectional
|
|
691
|
+
? `
|
|
692
|
+
const _rest = _backward ? items.slice(_from, _upTo) : items.slice(_from);
|
|
693
|
+
const _page = _backward ? _rest : _rest.slice(0, _first);
|
|
694
|
+
// A backward page was cut from ahead, so a next page provably exists — the one
|
|
695
|
+
// the caller came from — whatever this window's tail looks like.
|
|
696
|
+
const _more = _backward ? true : _rest.length > _first;`
|
|
697
|
+
: `
|
|
612
698
|
const _rest = items.slice(_from);
|
|
613
699
|
const _page = _rest.slice(0, _first);
|
|
614
|
-
const _more = _rest.length > _first
|
|
700
|
+
const _more = _rest.length > _first;`
|
|
701
|
+
// Only what the door can actually serve. `!!ctx.args.after` said "a page
|
|
702
|
+
// precedes this one", which is a different claim: at a window boundary one does
|
|
703
|
+
// and this door cannot reach it, so the client drew a Prev that always errored.
|
|
704
|
+
let hasPrevious = bidirectional ? "_from > 0" : "!!ctx.args.after"
|
|
705
|
+
`${firstDecl}${slice}
|
|
615
706
|
const _next = ctx.result?.nextToken ?? null;
|
|
616
707
|
const _lastIndex = _page.length - 1;
|
|
617
708
|
// A row's cursor names its own position. The last row of a page that closes its
|
|
@@ -632,7 +723,7 @@ let connectionPageResponse = (~pathExpr: option<string>=?) => {
|
|
|
632
723
|
edges,
|
|
633
724
|
pageInfo: {
|
|
634
725
|
hasNextPage: _more || !!_next,
|
|
635
|
-
hasPreviousPage:
|
|
726
|
+
hasPreviousPage: ${hasPrevious},
|
|
636
727
|
startCursor: edges.length > 0 ? edges[0].cursor : _boundary,
|
|
637
728
|
endCursor: edges.length > 0 ? edges[edges.length - 1].cursor : _boundary,
|
|
638
729
|
},
|
|
@@ -652,7 +743,7 @@ export function response(ctx) {
|
|
|
652
743
|
|
|
653
744
|
/** Refuses backward paging, for the reason `listAllItemsConnection` gives: the
|
|
654
745
|
cursor is DynamoDB's own continuation token, which only walks forward, so
|
|
655
|
-
`last`/`before` cannot be
|
|
746
|
+
`last`/`before` cannot be honored, and handing back the forward page would answer
|
|
656
747
|
a different question without saying so. The arguments stay declared — one that
|
|
657
748
|
came and went with the index's shape would make every client feature-detect — and
|
|
658
749
|
the local backend refuses them with the same message. */
|
|
@@ -714,7 +805,11 @@ export function request(ctx) {
|
|
|
714
805
|
values[':' + key] = '' + value;
|
|
715
806
|
}
|
|
716
807
|
});
|
|
717
|
-
${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
|
|
808
|
+
${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
|
|
809
|
+
~retiredField,
|
|
810
|
+
~retiredValues,
|
|
811
|
+
~elevatedGroups,
|
|
812
|
+
)}${indexCursorPreamble}
|
|
718
813
|
const result = {
|
|
719
814
|
operation: 'Query',
|
|
720
815
|
query,
|
|
@@ -777,7 +872,11 @@ export function request(ctx) {
|
|
|
777
872
|
values[':' + key] = '' + value;
|
|
778
873
|
}
|
|
779
874
|
});
|
|
780
|
-
${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
|
|
875
|
+
${ownerFilterClause(~ownerField, ~elevatedGroups)}${retiredFilterClause(
|
|
876
|
+
~retiredField,
|
|
877
|
+
~retiredValues,
|
|
878
|
+
~elevatedGroups,
|
|
879
|
+
)}${indexCursorPreamble}
|
|
781
880
|
const result = {
|
|
782
881
|
operation: 'Query',
|
|
783
882
|
query,
|
|
@@ -798,8 +897,7 @@ ${indexConnectionResponseCode}
|
|
|
798
897
|
// DynamoDB read — list all
|
|
799
898
|
// ---------------------------------------------------------------------------
|
|
800
899
|
|
|
801
|
-
let listAllItems =
|
|
802
|
-
`${importUtil}
|
|
900
|
+
let listAllItems = `${importUtil}
|
|
803
901
|
export function request(ctx) {
|
|
804
902
|
return {
|
|
805
903
|
operation: 'Scan',
|
|
@@ -863,7 +961,8 @@ let listAllItemsConnection = (
|
|
|
863
961
|
// have nothing to name in the key condition.
|
|
864
962
|
let ownerIndex = ownerField->Option.isSome ? ownerIndex : None
|
|
865
963
|
let requireAttributeClause = switch requireAttribute {
|
|
866
|
-
| Some(attr) =>
|
|
964
|
+
| Some(attr) =>
|
|
965
|
+
`
|
|
867
966
|
names['#${attr}'] = '${attr}';
|
|
868
967
|
parts.push('attribute_exists(#${attr})');`
|
|
869
968
|
| None => ""
|
|
@@ -909,7 +1008,7 @@ let listAllItemsConnection = (
|
|
|
909
1008
|
// Reuses `_exempt` when the owner clause computed it; either clause may be the
|
|
910
1009
|
// only one present. `includeRetired` IS read from ctx.args, unlike the owner
|
|
911
1010
|
// predicate — it asks to lift a restriction rather than naming rows, and is
|
|
912
|
-
//
|
|
1011
|
+
// honored only inside `_exempt`.
|
|
913
1012
|
//
|
|
914
1013
|
// `attribute_not_exists OR = false` rather than `<> true`, because `<>` does not
|
|
915
1014
|
// match a missing attribute and the view would empty out the day the annotation
|
|
@@ -921,7 +1020,8 @@ let listAllItemsConnection = (
|
|
|
921
1020
|
let elevatedLiteral = elevatedGroups->Array.map(g => `'${g}'`)->Array.join(", ")
|
|
922
1021
|
let exemptPrelude = switch ownerField {
|
|
923
1022
|
| Some(_) => ""
|
|
924
|
-
| None =>
|
|
1023
|
+
| None =>
|
|
1024
|
+
`
|
|
925
1025
|
const _id = ctx.identity;
|
|
926
1026
|
const _sub = _id == null ? null : _id.sub;
|
|
927
1027
|
const _groups = (_id != null && _id.claims != null && _id.claims['cognito:groups']) || [];
|
|
@@ -942,10 +1042,13 @@ ${switch retiredValues {
|
|
|
942
1042
|
// once for the whole clause — a row that states no lifecycle is not
|
|
943
1043
|
// retired, the same reading every other adapter takes.
|
|
944
1044
|
| Some(states) =>
|
|
945
|
-
let placeholders =
|
|
1045
|
+
let placeholders =
|
|
1046
|
+
states->Array.mapWithIndex((state, i) => (`:retiredValue${Int.toString(i)}`, state))
|
|
946
1047
|
let assignments =
|
|
947
1048
|
placeholders
|
|
948
|
-
->Array.map(((ph, state)) =>
|
|
1049
|
+
->Array.map(((ph, state)) =>
|
|
1050
|
+
` values['${ph}'] = util.dynamodb.toDynamoDB('${state}');`
|
|
1051
|
+
)
|
|
949
1052
|
->Array.join("\n")
|
|
950
1053
|
let comparisons =
|
|
951
1054
|
placeholders->Array.map(((ph, _)) => `#retired <> ${ph}`)->Array.join(" AND ")
|
|
@@ -961,16 +1064,19 @@ ${switch retiredValues {
|
|
|
961
1064
|
}
|
|
962
1065
|
let filterClauses =
|
|
963
1066
|
filterFields
|
|
964
|
-
->Array.map(f =>
|
|
1067
|
+
->Array.map(f =>
|
|
1068
|
+
`
|
|
965
1069
|
if (filter.${f}Eq !== undefined && filter.${f}Eq !== null && filter.${f}Eq !== '') {
|
|
966
1070
|
names['#${f}'] = '${f}';
|
|
967
1071
|
values[':${f}Eq'] = util.dynamodb.toDynamoDB(filter.${f}Eq);
|
|
968
1072
|
parts.push('#${f} = :${f}Eq');
|
|
969
|
-
}`
|
|
1073
|
+
}`
|
|
1074
|
+
)
|
|
970
1075
|
->Array.join("")
|
|
971
1076
|
let rangeClauses =
|
|
972
1077
|
rangeFields
|
|
973
|
-
->Array.map(f =>
|
|
1078
|
+
->Array.map(f =>
|
|
1079
|
+
`
|
|
974
1080
|
if (filter.${f}From !== undefined && filter.${f}From !== null && filter.${f}From !== '') {
|
|
975
1081
|
names['#${f}'] = '${f}';
|
|
976
1082
|
values[':${f}From'] = util.dynamodb.toDynamoDB(filter.${f}From);
|
|
@@ -980,10 +1086,10 @@ ${switch retiredValues {
|
|
|
980
1086
|
names['#${f}'] = '${f}';
|
|
981
1087
|
values[':${f}To'] = util.dynamodb.toDynamoDB(filter.${f}To);
|
|
982
1088
|
parts.push('#${f} <= :${f}To');
|
|
983
|
-
}`
|
|
1089
|
+
}`
|
|
1090
|
+
)
|
|
984
1091
|
->Array.join("")
|
|
985
|
-
let sortFieldsLiteral =
|
|
986
|
-
sortFields->Array.map(f => `'${f}'`)->Array.join(", ")
|
|
1092
|
+
let sortFieldsLiteral = sortFields->Array.map(f => `'${f}'`)->Array.join(", ")
|
|
987
1093
|
// When the Query branch already ordered on the index's own sort key, the page
|
|
988
1094
|
// arrives globally ordered and re-sorting it here is the one way to break that
|
|
989
1095
|
// order — a sort over a page is not a sort over the caller's rows.
|
|
@@ -1025,8 +1131,7 @@ ${switch retiredValues {
|
|
|
1025
1131
|
// halves, because both need it: the request to set `scanIndexForward`, the
|
|
1026
1132
|
// response to leave an already-ordered page alone.
|
|
1027
1133
|
let indexOrderedExpr = switch (ownerIndex, ownerIndexSortField) {
|
|
1028
|
-
| (Some(_), Some(sf)) =>
|
|
1029
|
-
`!_exempt && !!(ctx.args.orderBy && ctx.args.orderBy.field === '${sf}')`
|
|
1134
|
+
| (Some(_), Some(sf)) => `!_exempt && !!(ctx.args.orderBy && ctx.args.orderBy.field === '${sf}')`
|
|
1030
1135
|
| _ => "false"
|
|
1031
1136
|
}
|
|
1032
1137
|
// The two reads, chosen by the same test that used to choose a predicate.
|
|
@@ -1034,12 +1139,13 @@ ${switch retiredValues {
|
|
|
1034
1139
|
// branch inside one resolver — no second field, no second data source, no
|
|
1035
1140
|
// client change.
|
|
1036
1141
|
let requestOperation = switch (ownerField, ownerIndex) {
|
|
1037
|
-
| (Some(field), Some(index)) =>
|
|
1142
|
+
| (Some(field), Some(index)) =>
|
|
1143
|
+
`
|
|
1038
1144
|
const _indexOrdered = ${indexOrderedExpr};
|
|
1039
1145
|
const req = _exempt
|
|
1040
1146
|
? {
|
|
1041
1147
|
operation: 'Scan',
|
|
1042
|
-
limit: ${
|
|
1148
|
+
limit: ${listPageWindowBudget},
|
|
1043
1149
|
nextToken: _window,
|
|
1044
1150
|
}
|
|
1045
1151
|
: {
|
|
@@ -1050,14 +1156,15 @@ ${switch retiredValues {
|
|
|
1050
1156
|
expressionNames: { '#owner': '${field}' },
|
|
1051
1157
|
expressionValues: { ':owner': util.dynamodb.toDynamoDB(_sub) },
|
|
1052
1158
|
},
|
|
1053
|
-
limit: ${
|
|
1159
|
+
limit: ${listPageWindowBudget},
|
|
1054
1160
|
nextToken: _window,
|
|
1055
1161
|
scanIndexForward: !(_indexOrdered && ctx.args.orderBy.direction === 'DESC'),
|
|
1056
1162
|
};`
|
|
1057
|
-
| _ =>
|
|
1163
|
+
| _ =>
|
|
1164
|
+
`
|
|
1058
1165
|
const req = {
|
|
1059
1166
|
operation: 'Scan',
|
|
1060
|
-
limit: ${
|
|
1167
|
+
limit: ${listPageWindowBudget},
|
|
1061
1168
|
nextToken: _window,
|
|
1062
1169
|
};`
|
|
1063
1170
|
}
|
|
@@ -1065,21 +1172,24 @@ ${switch retiredValues {
|
|
|
1065
1172
|
let requestPathGuard = ownerIndex->Option.isSome ? cursorPathGuard : ""
|
|
1066
1173
|
let responsePathPreamble = switch ownerIndex {
|
|
1067
1174
|
| None => ""
|
|
1068
|
-
| Some(_) =>
|
|
1175
|
+
| Some(_) =>
|
|
1176
|
+
`${ownerIdentityPreamble}
|
|
1069
1177
|
const _path = _exempt ? 's' : 'q';
|
|
1070
1178
|
const _indexOrdered = ${indexOrderedExpr};`
|
|
1071
1179
|
}
|
|
1072
1180
|
let pageResponse = switch ownerIndex {
|
|
1073
|
-
| None => connectionPageResponse()
|
|
1074
|
-
| Some(_) => connectionPageResponse(~pathExpr="_path")
|
|
1181
|
+
| None => connectionPageResponse(~bidirectional=true)
|
|
1182
|
+
| Some(_) => connectionPageResponse(~pathExpr="_path", ~bidirectional=true)
|
|
1075
1183
|
}
|
|
1076
1184
|
`${importUtil}
|
|
1077
1185
|
export function request(ctx) {
|
|
1078
|
-
//
|
|
1079
|
-
//
|
|
1080
|
-
//
|
|
1081
|
-
|
|
1082
|
-
|
|
1186
|
+
// 'before' IS served — the page is cut backward out of the window the cursor
|
|
1187
|
+
// names. 'last' is not: "the last N rows of the list" needs the end of the
|
|
1188
|
+
// list, which a forward-only Scan cursor cannot reach. The ordered
|
|
1189
|
+
// {single}Items connection (queryItemsWithSortConditions) has a real keyset
|
|
1190
|
+
// cursor and honours both — direct callers who need 'last' there.
|
|
1191
|
+
if (ctx.args.last != null) {
|
|
1192
|
+
util.error('last is not supported on full-list connections; page backward with first and before.', 'UnsupportedPagination');
|
|
1083
1193
|
}
|
|
1084
1194
|
const filter = ctx.args.filter ?? {};
|
|
1085
1195
|
const names = {};
|
|
@@ -1104,8 +1214,14 @@ export function request(ctx) {
|
|
|
1104
1214
|
});
|
|
1105
1215
|
parts.push('#id IN (' + placeholders.join(', ') + ')');
|
|
1106
1216
|
}${filterClauses}${rangeClauses}${requireAttributeClause}${ownerClause}${retiredClause}
|
|
1107
|
-
${
|
|
1108
|
-
|
|
1217
|
+
${listCursorPreamble}${requestPathGuard}
|
|
1218
|
+
// The one page a cursor cannot reach: it begins in an earlier window, and a
|
|
1219
|
+
// continuation token cannot name the one before it. Refused by itself rather
|
|
1220
|
+
// than folded into the 'last' guard, because the two are different limits and a
|
|
1221
|
+
// caller can act on this one (page forward from the start).
|
|
1222
|
+
if (_backward && _upTo <= 0 && _window !== null) {
|
|
1223
|
+
util.error('The previous page begins in an earlier read window, which this cursor cannot name; page forward from the start.', 'UnsupportedPagination');
|
|
1224
|
+
}${requestOperation}
|
|
1109
1225
|
if (parts.length > 0) {
|
|
1110
1226
|
req.filter = {
|
|
1111
1227
|
expression: parts.join(' AND '),
|
|
@@ -1117,9 +1233,7 @@ ${cursorDecode(~args="ctx.args")}${requestPathGuard}
|
|
|
1117
1233
|
}
|
|
1118
1234
|
export function response(ctx) {
|
|
1119
1235
|
if (ctx.error) util.error(ctx.error.message, ctx.error.type);
|
|
1120
|
-
let items = ctx.result?.items ?? [];${responsePathPreamble}${sortBlock}${
|
|
1121
|
-
~args="ctx.args",
|
|
1122
|
-
)}${pageResponse}
|
|
1236
|
+
let items = ctx.result?.items ?? [];${responsePathPreamble}${sortBlock}${listCursorPreamble}${pageResponse}
|
|
1123
1237
|
}
|
|
1124
1238
|
`->Pulumi.Input.make
|
|
1125
1239
|
}
|
|
@@ -1153,7 +1267,10 @@ let resolvedFieldResponse = (
|
|
|
1153
1267
|
| None => "\n const _owns = (row) => true;"
|
|
1154
1268
|
| Some(field) =>
|
|
1155
1269
|
`
|
|
1156
|
-
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
1270
|
+
// ── owner scoping (generated) ──${ownerGuardPreamble(
|
|
1271
|
+
~ownerField=field,
|
|
1272
|
+
~elevatedGroups,
|
|
1273
|
+
)}`
|
|
1157
1274
|
}
|
|
1158
1275
|
let retiredPart = retiredGuardPreamble(
|
|
1159
1276
|
~retiredField,
|
|
@@ -1356,13 +1473,14 @@ let resolveIds = (
|
|
|
1356
1473
|
~retiredField: option<string>=?,
|
|
1357
1474
|
~retiredValues: option<array<string>>=?,
|
|
1358
1475
|
~elevatedGroups: array<string>=[],
|
|
1359
|
-
) =>
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1476
|
+
) =>
|
|
1477
|
+
(tableName: string) => {
|
|
1478
|
+
let keysCode = switch sortField {
|
|
1479
|
+
| Some(sf) =>
|
|
1480
|
+
`id => ({ id: util.dynamodb.toString(id.id), ${sf}: util.dynamodb.toString(id.${sf}) })`
|
|
1481
|
+
| None => `id => ({ id: util.dynamodb.toString(id) })`
|
|
1482
|
+
}
|
|
1483
|
+
`${importUtil}
|
|
1366
1484
|
import { runtime } from '@aws-appsync/utils';
|
|
1367
1485
|
export function request(ctx) {
|
|
1368
1486
|
const idList = ctx.source.${idsField} ?? [];
|
|
@@ -1379,21 +1497,21 @@ export function request(ctx) {
|
|
|
1379
1497
|
}
|
|
1380
1498
|
export function response(ctx) {
|
|
1381
1499
|
if (ctx.error) util.error(ctx.error.message, ctx.error.type);${switch ownerField {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1500
|
+
| None => ""
|
|
1501
|
+
| Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
|
|
1502
|
+
}}${retiredGuardPreamble(
|
|
1503
|
+
~retiredField,
|
|
1504
|
+
~retiredValues,
|
|
1505
|
+
~elevatedGroups,
|
|
1506
|
+
~ownerScoped=ownerField->Option.isSome,
|
|
1507
|
+
)}
|
|
1390
1508
|
return (ctx.result?.data?.['${tableName}'] ?? []).filter(item =>
|
|
1391
1509
|
item !== null${ownerField->Option.isSome ? " && _owns(item)" : ""}${retiredField->Option.isSome
|
|
1392
|
-
|
|
1393
|
-
|
|
1510
|
+
? " && _live(item)"
|
|
1511
|
+
: ""});
|
|
1394
1512
|
}
|
|
1395
1513
|
`
|
|
1396
|
-
}
|
|
1514
|
+
}
|
|
1397
1515
|
|
|
1398
1516
|
/** Batched-by-ids — reads `ctx.args.ids: [String!]!` through one BatchGetItem.
|
|
1399
1517
|
Missing ids drop out; empty input short-circuits without hitting DDB. The
|
|
@@ -1404,8 +1522,9 @@ let batchGetItemsByIds = (
|
|
|
1404
1522
|
~retiredField: option<string>=?,
|
|
1405
1523
|
~retiredValues: option<array<string>>=?,
|
|
1406
1524
|
~elevatedGroups: array<string>=[],
|
|
1407
|
-
) =>
|
|
1408
|
-
|
|
1525
|
+
) =>
|
|
1526
|
+
(tableName: string) =>
|
|
1527
|
+
`${importUtil}
|
|
1409
1528
|
import { runtime } from '@aws-appsync/utils';
|
|
1410
1529
|
export function request(ctx) {
|
|
1411
1530
|
const ids = ctx.args.ids ?? [];
|
|
@@ -1430,18 +1549,18 @@ export function response(ctx) {
|
|
|
1430
1549
|
// caller does not own is dropped rather than refused, for the reason the
|
|
1431
1550
|
// single-key door answers null: distinguishing "not yours" from "not there"
|
|
1432
1551
|
// would make this door an oracle for which ids exist.${switch ownerField {
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1552
|
+
| None => ""
|
|
1553
|
+
| Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
|
|
1554
|
+
}}${retiredGuardPreamble(
|
|
1555
|
+
~retiredField,
|
|
1556
|
+
~retiredValues,
|
|
1557
|
+
~elevatedGroups,
|
|
1558
|
+
~ownerScoped=ownerField->Option.isSome,
|
|
1559
|
+
)}
|
|
1441
1560
|
return (ctx.result?.data?.['${tableName}'] ?? []).filter(item =>
|
|
1442
1561
|
item !== null${ownerField->Option.isSome ? " && _owns(item)" : ""}${retiredField->Option.isSome
|
|
1443
|
-
|
|
1444
|
-
|
|
1562
|
+
? " && _live(item)"
|
|
1563
|
+
: ""});
|
|
1445
1564
|
}
|
|
1446
1565
|
`
|
|
1447
1566
|
|
|
@@ -1458,37 +1577,43 @@ let refsByIds = (
|
|
|
1458
1577
|
~retiredField: option<string>,
|
|
1459
1578
|
~retiredValues: option<array<string>>,
|
|
1460
1579
|
~namedWhenRetired: bool,
|
|
1580
|
+
// The picture a reference shows this row by, already read off the state schema
|
|
1581
|
+
// by `Reventless.RowImage` — this template only bakes in the expression it
|
|
1582
|
+
// hands over. `None` for a view that declares none, which emits a literal
|
|
1583
|
+
// `null`, exactly what the nullable field promises.
|
|
1584
|
+
~imageExpr: option<string>=?,
|
|
1461
1585
|
~ownerField: option<string>=?,
|
|
1462
1586
|
~elevatedGroups: array<string>=[],
|
|
1463
|
-
) =>
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1587
|
+
) =>
|
|
1588
|
+
(tableName: string) => {
|
|
1589
|
+
let ownerGuard = switch ownerField {
|
|
1590
|
+
// Takes the row it ignores: APPSYNC_JS type-checks the resolver, so a
|
|
1591
|
+
// zero-parameter stub called as `_owns(row)` is TS2554 ("Expected 0
|
|
1592
|
+
// arguments, but got 1") and AppSync rejects the whole resolver at create
|
|
1593
|
+
// time with "The code contains one or more errors". Only a door that emits
|
|
1594
|
+
// the call conditionally is safe with a bare `() => true`, and that is not a
|
|
1595
|
+
// property worth relying on across three templates.
|
|
1596
|
+
| None => "\n const _owns = (row) => true;"
|
|
1597
|
+
| Some(field) => ownerGuardPreamble(~ownerField=field, ~elevatedGroups)
|
|
1598
|
+
}
|
|
1599
|
+
// Retirement, in the vocabulary the row itself uses: a member test for the
|
|
1600
|
+
// state form, truthiness for the boolean one. Absent keeps the row live, which
|
|
1601
|
+
// is what a row written before the annotation is.
|
|
1602
|
+
let retiredExpr = switch (retiredField, retiredValues) {
|
|
1603
|
+
| (None, _) => "false"
|
|
1604
|
+
| (Some(f), Some(values)) =>
|
|
1605
|
+
let literal = values->Array.map(v => `'${v}'`)->Array.join(", ")
|
|
1606
|
+
`[${literal}].indexOf(row['${f}']) >= 0`
|
|
1607
|
+
| (Some(f), None) => `row['${f}'] === true`
|
|
1608
|
+
}
|
|
1609
|
+
// Only the state form has a state to name, and only a retired row reports one:
|
|
1610
|
+
// this door names rows, it does not publish a lifecycle column to callers the
|
|
1611
|
+
// list withholds.
|
|
1612
|
+
let stateExpr = switch (retiredField, retiredValues) {
|
|
1613
|
+
| (Some(f), Some(_)) => `_retired(row) ? (row['${f}'] ?? null) : null`
|
|
1614
|
+
| _ => "null"
|
|
1615
|
+
}
|
|
1616
|
+
`${importUtil}
|
|
1492
1617
|
import { runtime } from '@aws-appsync/utils';
|
|
1493
1618
|
export function request(ctx) {
|
|
1494
1619
|
const ids = ctx.args.ids ?? [];
|
|
@@ -1513,19 +1638,19 @@ export function response(ctx) {
|
|
|
1513
1638
|
.map(row => ({
|
|
1514
1639
|
id: row.id,
|
|
1515
1640
|
label: row['${labelField}'] ?? row.id,
|
|
1641
|
+
image: ${imageExpr->Option.getOr("null")},
|
|
1516
1642
|
retired: _retired(row),
|
|
1517
1643
|
retiredState: ${stateExpr},
|
|
1518
1644
|
}));
|
|
1519
1645
|
}
|
|
1520
1646
|
`
|
|
1521
|
-
}
|
|
1647
|
+
}
|
|
1522
1648
|
|
|
1523
1649
|
// ---------------------------------------------------------------------------
|
|
1524
1650
|
// DynamoDB write
|
|
1525
1651
|
// ---------------------------------------------------------------------------
|
|
1526
1652
|
|
|
1527
|
-
let putItem =
|
|
1528
|
-
`${importUtil}
|
|
1653
|
+
let putItem = `${importUtil}
|
|
1529
1654
|
export function request(ctx) {
|
|
1530
1655
|
return {
|
|
1531
1656
|
operation: 'PutItem',
|
|
@@ -1552,8 +1677,7 @@ export function request(ctx) {
|
|
|
1552
1677
|
${resultResponseCode}
|
|
1553
1678
|
`->Pulumi.Input.make
|
|
1554
1679
|
|
|
1555
|
-
let deleteItem =
|
|
1556
|
-
`${importUtil}
|
|
1680
|
+
let deleteItem = `${importUtil}
|
|
1557
1681
|
export function request(ctx) {
|
|
1558
1682
|
return {
|
|
1559
1683
|
operation: 'DeleteItem',
|
|
@@ -1567,6 +1691,24 @@ ${resultResponseCode}
|
|
|
1567
1691
|
// Lambda invocations
|
|
1568
1692
|
// ---------------------------------------------------------------------------
|
|
1569
1693
|
|
|
1694
|
+
// The caller as a command Lambda reads it: a Cognito user, an IAM principal, or null.
|
|
1695
|
+
let callerIdentity = `identity: isCognito
|
|
1696
|
+
? {
|
|
1697
|
+
userId: id.sub,
|
|
1698
|
+
username: id.username,
|
|
1699
|
+
groups: id.claims?.['cognito:groups'] ?? [],
|
|
1700
|
+
claims: id.claims,
|
|
1701
|
+
provider: 'Cognito'
|
|
1702
|
+
}
|
|
1703
|
+
: id != null
|
|
1704
|
+
? {
|
|
1705
|
+
userArn: id.userArn ?? null,
|
|
1706
|
+
accountId: id.accountId ?? null,
|
|
1707
|
+
username: id.username ?? null,
|
|
1708
|
+
provider: 'IAM'
|
|
1709
|
+
}
|
|
1710
|
+
: null`
|
|
1711
|
+
|
|
1570
1712
|
/** Invoke a CommandGenerator Lambda. `command` is the Aggregate command name. */
|
|
1571
1713
|
let invokeCommandGenerator = (command: string) =>
|
|
1572
1714
|
`${importUtil}
|
|
@@ -1579,26 +1721,10 @@ export function request(ctx) {
|
|
|
1579
1721
|
command: '${command}',
|
|
1580
1722
|
arguments: ctx.args,
|
|
1581
1723
|
meta: {
|
|
1582
|
-
ip: id?.sourceIp ?? null,
|
|
1583
1724
|
user: id?.username ?? null,
|
|
1584
1725
|
info: ctx.info.parentTypeName + '.' + ctx.info.fieldName
|
|
1585
1726
|
},
|
|
1586
|
-
|
|
1587
|
-
? {
|
|
1588
|
-
userId: id.sub,
|
|
1589
|
-
username: id.username,
|
|
1590
|
-
groups: id.claims?.['cognito:groups'] ?? [],
|
|
1591
|
-
claims: id.claims,
|
|
1592
|
-
provider: 'Cognito'
|
|
1593
|
-
}
|
|
1594
|
-
: id != null
|
|
1595
|
-
? {
|
|
1596
|
-
userArn: id.userArn ?? null,
|
|
1597
|
-
accountId: id.accountId ?? null,
|
|
1598
|
-
username: id.username ?? null,
|
|
1599
|
-
provider: 'IAM'
|
|
1600
|
-
}
|
|
1601
|
-
: null
|
|
1727
|
+
${callerIdentity}
|
|
1602
1728
|
}
|
|
1603
1729
|
};
|
|
1604
1730
|
}
|
|
@@ -1617,26 +1743,10 @@ export function request(ctx) {
|
|
|
1617
1743
|
command: '${tag}',
|
|
1618
1744
|
arguments: ctx.args,
|
|
1619
1745
|
meta: {
|
|
1620
|
-
ip: id?.sourceIp ?? null,
|
|
1621
1746
|
user: id?.username ?? null,
|
|
1622
1747
|
info: ctx.info.parentTypeName + '.' + ctx.info.fieldName
|
|
1623
1748
|
},
|
|
1624
|
-
|
|
1625
|
-
? {
|
|
1626
|
-
userId: id.sub,
|
|
1627
|
-
username: id.username,
|
|
1628
|
-
groups: id.claims?.['cognito:groups'] ?? [],
|
|
1629
|
-
claims: id.claims,
|
|
1630
|
-
provider: 'Cognito'
|
|
1631
|
-
}
|
|
1632
|
-
: id != null
|
|
1633
|
-
? {
|
|
1634
|
-
userArn: id.userArn ?? null,
|
|
1635
|
-
accountId: id.accountId ?? null,
|
|
1636
|
-
username: id.username ?? null,
|
|
1637
|
-
provider: 'IAM'
|
|
1638
|
-
}
|
|
1639
|
-
: null
|
|
1749
|
+
${callerIdentity}
|
|
1640
1750
|
}
|
|
1641
1751
|
};
|
|
1642
1752
|
}
|
|
@@ -1647,12 +1757,15 @@ ${resultResponseCode}
|
|
|
1647
1757
|
let invokeInboundTranslation = (fieldName: string) =>
|
|
1648
1758
|
`${importUtil}
|
|
1649
1759
|
export function request(ctx) {
|
|
1760
|
+
const id = ctx.identity;
|
|
1761
|
+
const isCognito = id != null && id.sub != null;
|
|
1650
1762
|
return {
|
|
1651
1763
|
operation: 'Invoke',
|
|
1652
1764
|
payload: {
|
|
1653
1765
|
__inboundTranslation: true,
|
|
1654
1766
|
fieldName: '${fieldName}',
|
|
1655
|
-
arguments: ctx.args
|
|
1767
|
+
arguments: ctx.args,
|
|
1768
|
+
${callerIdentity}
|
|
1656
1769
|
}
|
|
1657
1770
|
};
|
|
1658
1771
|
}
|
|
@@ -1696,8 +1809,7 @@ export function response(ctx) {
|
|
|
1696
1809
|
let authorizeIndexedAccessRequest = authorizeIndexedAccess
|
|
1697
1810
|
|
|
1698
1811
|
/** @deprecated The response check is now part of authorizeIndexedAccess. */
|
|
1699
|
-
let authorizeIndexedAccessResponse = (~group as _: string) =>
|
|
1700
|
-
resultResponseCode->Pulumi.Input.make
|
|
1812
|
+
let authorizeIndexedAccessResponse = (~group as _: string) => resultResponseCode->Pulumi.Input.make
|
|
1701
1813
|
|
|
1702
1814
|
// ---------------------------------------------------------------------------
|
|
1703
1815
|
// Response-only helpers
|