@reventlessdev/reventless-aws 3.0.0-alpha.322 → 3.0.0-alpha.324
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,20 @@
|
|
|
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.324 (2026-08-24)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **aws:** keep a served bucket's read grant when serving moves distributions ([40b712a](https://github.com/ReventlessDev/reventless-core/commit/40b712a62d7b9d44621962984ff63c7719df642e))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 3.0.0-alpha.323 (2026-08-23)
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **querydb:** serve the previous page instead of refusing it ([48341c9](https://github.com/ReventlessDev/reventless-core/commit/48341c9f61b5155b441deeb0edc9abf461948346))
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
# 3.0.0-alpha.322 (2026-08-23)
|
|
7
21
|
|
|
8
22
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.324",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"sury": "11.0.0-rc.2",
|
|
17
17
|
"uuid": "^13.0.0",
|
|
18
18
|
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.13",
|
|
19
|
-
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
20
19
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
21
20
|
"@reventlessdev/rescript-node": "2.0.0-alpha.8",
|
|
22
|
-
"@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.
|
|
21
|
+
"@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.5",
|
|
22
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
23
23
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
24
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.249",
|
|
25
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.151",
|
|
26
24
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
27
|
-
"@reventlessdev/reventless-
|
|
28
|
-
"@reventlessdev/reventless-
|
|
29
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.123"
|
|
25
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.250",
|
|
26
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.151",
|
|
27
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.123",
|
|
28
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.114",
|
|
29
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.33"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"rescript": "12.3.0",
|
|
@@ -445,9 +445,19 @@ let makeUiBundleDistribution = (
|
|
|
445
445
|
// Exactly one policy per bucket — S3 permits no more. Grouping prefixes into
|
|
446
446
|
// one `servedBucket` is what makes that structural rather than a rule to
|
|
447
447
|
// remember.
|
|
448
|
+
//
|
|
449
|
+
// `retainOnDelete` is what makes moving a bucket's serving between
|
|
450
|
+
// distributions survivable. The policy resource is named after the
|
|
451
|
+
// distribution, so a handover is a create and a delete over the bucket's one
|
|
452
|
+
// physical policy — and Pulumi runs deletes last, so the old resource's
|
|
453
|
+
// DeleteBucketPolicy would wipe the grant the new one just wrote. Deploy
|
|
454
|
+
// green, every object 403. Retaining drops the stale entry from state without
|
|
455
|
+
// calling the provider; the most it can leave behind is a grant naming a
|
|
456
|
+
// distribution that no longer exists, which authorizes nothing.
|
|
448
457
|
servedBuckets->Array.forEach(sb => {
|
|
449
458
|
let _ = PulumiAws.S3.BucketPolicy.make(
|
|
450
459
|
~name=name ++ "-served-" ++ sb.id ++ "-policy",
|
|
460
|
+
~opts={retainOnDelete: true},
|
|
451
461
|
~args={
|
|
452
462
|
bucket: sb.bucketId,
|
|
453
463
|
policy: (sb.bucketArn->Pulumi.Output.fromInput, distribution.arn)
|
|
@@ -691,10 +701,12 @@ let makeServedBucketDistribution = (
|
|
|
691
701
|
}
|
|
692
702
|
|
|
693
703
|
// One policy per bucket — see the module doc above for why this is here and
|
|
694
|
-
// not in the consuming stack
|
|
704
|
+
// not in the consuming stack, and `makeUiBundleDistribution` for why the
|
|
705
|
+
// policy is retained rather than deleted.
|
|
695
706
|
servedBuckets->Array.forEach(sb => {
|
|
696
707
|
let _ = PulumiAws.S3.BucketPolicy.make(
|
|
697
708
|
~name=name ++ "-served-" ++ sb.id ++ "-policy",
|
|
709
|
+
~opts={retainOnDelete: true},
|
|
698
710
|
~args={
|
|
699
711
|
bucket: sb.bucketId,
|
|
700
712
|
policy: (sb.bucketArn->Pulumi.Output.fromInput, distribution.arn)
|
|
@@ -275,6 +275,8 @@ function makeUiBundleDistribution(pluginId, bundleVersion, assetsDir, spaFallbac
|
|
|
275
275
|
}
|
|
276
276
|
}]
|
|
277
277
|
}))
|
|
278
|
+
}, {
|
|
279
|
+
retainOnDelete: true
|
|
278
280
|
});
|
|
279
281
|
});
|
|
280
282
|
if (assetsDir !== undefined) {
|
|
@@ -409,6 +411,8 @@ function makeServedBucketDistribution(name, servedBuckets, customDomain) {
|
|
|
409
411
|
}
|
|
410
412
|
}]
|
|
411
413
|
}))
|
|
414
|
+
}, {
|
|
415
|
+
retainOnDelete: true
|
|
412
416
|
});
|
|
413
417
|
});
|
|
414
418
|
if (customDomain !== undefined) {
|
|
@@ -51,16 +51,32 @@ describe("listAllItemsConnection — paging", () => {
|
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
testSync("a filtered read examines more rows than it serves", () => {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// The budget reads as deep as the page needs, which for a backward cut is
|
|
55
|
+
// `_upTo` rather than `_first + _from`.
|
|
56
|
+
expect(
|
|
57
|
+
code->String.includes("parts.length > 0 ? ((_backward ? _upTo : _first + _from) > 1000"),
|
|
58
|
+
)->toBe(true)
|
|
59
|
+
expect(code->String.includes("const _page = _backward ? _rest : _rest.slice(0, _first);"))
|
|
60
|
+
->toBe(true)
|
|
56
61
|
expect(code->String.includes("hasNextPage: _more || !!_next,"))->toBe(true)
|
|
57
62
|
})
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
// `before` is served by re-reading the window the cursor names; only a previous
|
|
65
|
+
// page lying in an EARLIER window is out of reach, and `last` — which needs the
|
|
66
|
+
// end of the list — stays refused.
|
|
67
|
+
testSync("backward paging is served, and its one limit is named", () => {
|
|
68
|
+
expect(code->String.includes("ctx.args.before != null && ctx.args.before !== ''"))->toBe(true)
|
|
69
|
+
expect(code->String.includes("_backward && _upTo <= 0 && _window !== null"))->toBe(true)
|
|
61
70
|
expect(code->String.includes("UnsupportedPagination"))->toBe(true)
|
|
62
71
|
})
|
|
63
72
|
|
|
73
|
+
// The door must not advertise a previous page it cannot serve — that is what
|
|
74
|
+
// put a live Prev button in front of an error.
|
|
75
|
+
testSync("only a reachable previous page is advertised", () => {
|
|
76
|
+
expect(code->String.includes("hasPreviousPage: _from > 0,"))->toBe(true)
|
|
77
|
+
expect(code->String.includes("hasPreviousPage: !!ctx.args.after,"))->toBe(false)
|
|
78
|
+
})
|
|
79
|
+
|
|
64
80
|
testSync("a window emptied by the filter still yields a resumable boundary cursor", () => {
|
|
65
81
|
expect(
|
|
66
82
|
code->String.includes(
|
|
@@ -37,14 +37,19 @@ globalThis.describe("listAllItemsConnection — paging", () => {
|
|
|
37
37
|
globalThis.expect(code.includes("ctx.args.after + '_' + i")).toBe(false);
|
|
38
38
|
});
|
|
39
39
|
globalThis.test("a filtered read examines more rows than it serves", () => {
|
|
40
|
-
globalThis.expect(code.includes("parts.length > 0 ? (
|
|
41
|
-
globalThis.expect(code.includes("const _page = _rest.slice(0, _first);")).toBe(true);
|
|
40
|
+
globalThis.expect(code.includes("parts.length > 0 ? ((_backward ? _upTo : _first + _from) > 1000")).toBe(true);
|
|
41
|
+
globalThis.expect(code.includes("const _page = _backward ? _rest : _rest.slice(0, _first);")).toBe(true);
|
|
42
42
|
globalThis.expect(code.includes("hasNextPage: _more || !!_next,")).toBe(true);
|
|
43
43
|
});
|
|
44
|
-
globalThis.test("backward paging
|
|
45
|
-
globalThis.expect(code.includes("ctx.args.before != null
|
|
44
|
+
globalThis.test("backward paging is served, and its one limit is named", () => {
|
|
45
|
+
globalThis.expect(code.includes("ctx.args.before != null && ctx.args.before !== ''")).toBe(true);
|
|
46
|
+
globalThis.expect(code.includes("_backward && _upTo <= 0 && _window !== null")).toBe(true);
|
|
46
47
|
globalThis.expect(code.includes("UnsupportedPagination")).toBe(true);
|
|
47
48
|
});
|
|
49
|
+
globalThis.test("only a reachable previous page is advertised", () => {
|
|
50
|
+
globalThis.expect(code.includes("hasPreviousPage: _from > 0,")).toBe(true);
|
|
51
|
+
globalThis.expect(code.includes("hasPreviousPage: !!ctx.args.after,")).toBe(false);
|
|
52
|
+
});
|
|
48
53
|
globalThis.test("a window emptied by the filter still yields a resumable boundary cursor", () => {
|
|
49
54
|
globalThis.expect(code.includes("const _boundary = _next ? util.base64Encode(JSON.stringify({ t: _next, n: -1 })) : null;")).toBe(true);
|
|
50
55
|
globalThis.expect(code.includes("edges.length > 0 ? edges[edges.length - 1].cursor : _boundary")).toBe(true);
|