@reventlessdev/reventless-aws 3.0.0-alpha.182 → 3.0.0-alpha.183
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 +7 -0
- package/package.json +5 -5
- package/src/Platform.res +71 -34
- package/src/Platform.res.mjs +58 -70
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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.183 (2026-07-08)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **reventless-aws:** stop admin-base schema clobber of split-mode DomainApi ([afce85f](https://github.com/ReventlessDev/reventless-core/commit/afce85fa57474735cea3dcb1c2a151c2d8804f0e))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.182 (2026-07-07)
|
|
7
14
|
|
|
8
15
|
### 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.183",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
"sury": "11.0.0-alpha.4",
|
|
10
10
|
"uuid": "^13.0.0",
|
|
11
11
|
"@reventlessdev/rescript-aws-sdk": "2.2.0-alpha.20",
|
|
12
|
+
"@reventlessdev/rescript-effect": "0.1.0-alpha.25",
|
|
12
13
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.6",
|
|
13
14
|
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.46",
|
|
14
|
-
"@reventlessdev/rescript-effect": "0.1.0-alpha.25",
|
|
15
15
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.14",
|
|
16
16
|
"@reventlessdev/rescript-uuid": "1.1.0-alpha.14",
|
|
17
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
17
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.145",
|
|
18
18
|
"@reventlessdev/reventless-infra": "3.0.0-alpha.90",
|
|
19
19
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.24",
|
|
20
|
-
"@reventlessdev/reventless-
|
|
21
|
-
"@reventlessdev/reventless-
|
|
20
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.9",
|
|
21
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.68"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"rescript": "^12.3.0",
|
package/src/Platform.res
CHANGED
|
@@ -689,37 +689,56 @@ module MakeWithConfig = (
|
|
|
689
689
|
// - split mode: platformApi from splitApiOutputsRef
|
|
690
690
|
// - unified mode / not-yet-populated: domainApi
|
|
691
691
|
preAdminResolversSchemaHook: (~adminBarrier) => {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
692
|
+
// The admin-base SDL stitches AdminApi.baseFragment with an EMPTY plugin
|
|
693
|
+
// list, and startSchemaCreation REPLACES the whole schema. In split mode
|
|
694
|
+
// the admin schema belongs on the PlatformApi ONLY — the DomainApi carries
|
|
695
|
+
// plugin fields (emptyBaseFragment). If we pushed the admin-base-only SDL
|
|
696
|
+
// to the DomainApi it would wipe every plugin field, leaving exactly the
|
|
697
|
+
// admin-base set (the alpha 2026-07-08 clobber). So in split mode we push
|
|
698
|
+
// ONLY when the PlatformApi is known; if the ref is not yet populated we
|
|
699
|
+
// SKIP (never fall back to domainApi). Unified mode legitimately shares one
|
|
700
|
+
// API, so an unpopulated ref there means domainApi.
|
|
701
|
+
let targetApiOpt = switch (Config.splitApi, splitApiOutputsRef.contents) {
|
|
702
|
+
| (_, Some({platformApi})) => Some(platformApi)
|
|
703
|
+
| (false, None) => Some(domainApi)
|
|
704
|
+
| (true, None) => None
|
|
695
705
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
)
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
|
|
706
|
+
switch targetApiOpt {
|
|
707
|
+
| None =>
|
|
708
|
+
log.error(
|
|
709
|
+
~comp="preAdminResolversSchemaHook",
|
|
710
|
+
"split mode but the PlatformApi is not available at hook time — SKIPPING the admin schema push to avoid clobbering the DomainApi (pushing admin-base here would wipe every plugin field)",
|
|
711
|
+
)
|
|
712
|
+
adminBarrier
|
|
713
|
+
| Some(targetApi) =>
|
|
714
|
+
let adminBaseFragment = AppSync_Adapter.injectAwsAuthAll(
|
|
715
|
+
ReventlessCore.AdminApi.baseFragment(~cloner=Config.cloner),
|
|
716
|
+
~group="Admin",
|
|
717
|
+
)
|
|
718
|
+
let sdl = ReventlessCore.GraphQL_Stitcher.stitch(
|
|
719
|
+
~baseFragment=adminBaseFragment,
|
|
720
|
+
~pluginFragments=[],
|
|
721
|
+
)->AppSync_Adapter.stampSharedIamTypes
|
|
722
|
+
(targetApi, adminBarrier)
|
|
723
|
+
->Pulumi.Output.all2
|
|
724
|
+
->Pulumi.Output.flatMap(((api, _)) =>
|
|
725
|
+
api.id->Pulumi.Output.flatMap(apiId => {
|
|
726
|
+
log.info(~comp="preAdminResolversSchemaHook", `Pushing admin schema to ${apiId}`)
|
|
727
|
+
let client = AppSync_Adapter.getClient()
|
|
728
|
+
client
|
|
729
|
+
->AppSync_Adapter.startSchemaCreationRetrying({apiId, definition: sdl})
|
|
730
|
+
->Promise.then(async _ => {
|
|
731
|
+
log.info(
|
|
732
|
+
~comp="preAdminResolversSchemaHook",
|
|
733
|
+
"startSchemaCreation called, waiting for ACTIVE",
|
|
734
|
+
)
|
|
735
|
+
await AppSync_Adapter.waitForSchemaActive(client, apiId)
|
|
736
|
+
log.info(~comp="preAdminResolversSchemaHook", "schema is ACTIVE")
|
|
737
|
+
})
|
|
738
|
+
->Pulumi.Output.fromPromise
|
|
719
739
|
})
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
)
|
|
740
|
+
)
|
|
741
|
+
}
|
|
723
742
|
},
|
|
724
743
|
|
|
725
744
|
// Accumulate fragments across independent plugin deployments: each plugin
|
|
@@ -957,26 +976,44 @@ module MakeWithConfig = (
|
|
|
957
976
|
~sdl=s,
|
|
958
977
|
~typeName="Subscription",
|
|
959
978
|
)
|
|
979
|
+
// Identity-aware drift check (not a bare count): the live schema is
|
|
980
|
+
// "intact" only when it is a SUPERSET of every root field we would
|
|
981
|
+
// push. Comparing name SETS heals equal-cardinality drift and field
|
|
982
|
+
// *swaps* — an admin-base clobber that leaves the DomainApi with the
|
|
983
|
+
// SAME number of root fields but the WRONG ones (admin-base instead
|
|
984
|
+
// of plugin fields) has a matching count yet is missing every
|
|
985
|
+
// expected plugin field, so a count test would wrongly skip.
|
|
986
|
+
let missingFields = ReventlessCore.GraphQL_Stitcher.missingRootFields(
|
|
987
|
+
~expectedSdl=sdl,
|
|
988
|
+
~liveSdl,
|
|
989
|
+
)
|
|
960
990
|
let skipPush = switch storedHash {
|
|
961
991
|
| Some(prev) if prev == currentHash =>
|
|
962
|
-
let expected = countRoots(sdl)
|
|
963
|
-
let live = countRoots(liveSdl)
|
|
964
992
|
if liveSdl == "" {
|
|
965
993
|
log.info(
|
|
966
994
|
~comp="preResolversSchemaHook",
|
|
967
995
|
`hash matches but live schema could not be introspected — forcing repair push (check appsync:GetIntrospectionSchema permission)`,
|
|
968
996
|
)
|
|
969
997
|
false
|
|
970
|
-
} else if
|
|
998
|
+
} else if missingFields->Array.length > 0 {
|
|
971
999
|
log.info(
|
|
972
1000
|
~comp="preResolversSchemaHook",
|
|
973
|
-
`hash matches but live schema
|
|
1001
|
+
`hash matches but live schema is missing ${missingFields
|
|
1002
|
+
->Array.length
|
|
1003
|
+
->Int.toString} expected root field(s) (e.g. ${missingFields
|
|
1004
|
+
->Array.slice(~start=0, ~end=5)
|
|
1005
|
+
->Array.join(", ")}) — forcing repair push`,
|
|
974
1006
|
)
|
|
975
1007
|
false
|
|
976
1008
|
} else {
|
|
977
1009
|
log.info(
|
|
978
1010
|
~comp="preResolversSchemaHook",
|
|
979
|
-
`SDL unchanged (hash ${currentHash->String.slice(
|
|
1011
|
+
`SDL unchanged (hash ${currentHash->String.slice(
|
|
1012
|
+
~start=0,
|
|
1013
|
+
~end=12,
|
|
1014
|
+
)}…) and live schema is a superset of the expected root fields (${countRoots(
|
|
1015
|
+
liveSdl,
|
|
1016
|
+
)->Int.toString} live); skipping push`,
|
|
980
1017
|
)
|
|
981
1018
|
true
|
|
982
1019
|
}
|
package/src/Platform.res.mjs
CHANGED
|
@@ -645,23 +645,12 @@ function MakeWithConfig(Config) {
|
|
|
645
645
|
let client = AppSync_Adapter$ReventlessAws.getClient();
|
|
646
646
|
let liveSdl = await AppSync_Adapter$ReventlessAws.getIntrospectionSdl(client, apiId);
|
|
647
647
|
let countRoots = s => (GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Mutation") + GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Query") | 0) + GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Subscription") | 0;
|
|
648
|
-
let
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
skipPush = false;
|
|
655
|
-
} else if (live < expected) {
|
|
656
|
-
log.info("preResolversSchemaHook", undefined, `hash matches but live schema drifted (` + live.toString() + ` root field(s) live vs ` + expected.toString() + ` expected) — forcing repair push`);
|
|
657
|
-
skipPush = false;
|
|
658
|
-
} else {
|
|
659
|
-
log.info("preResolversSchemaHook", undefined, `SDL unchanged (hash ` + currentHash.slice(0, 12) + `…) and live schema intact (` + live.toString() + ` root fields); skipping push`);
|
|
660
|
-
skipPush = true;
|
|
661
|
-
}
|
|
662
|
-
} else {
|
|
663
|
-
skipPush = false;
|
|
664
|
-
}
|
|
648
|
+
let missingFields = GraphQL_Stitcher$ReventlessCore.missingRootFields(sdl, liveSdl);
|
|
649
|
+
let skipPush = storedHash !== undefined && storedHash === currentHash ? (
|
|
650
|
+
liveSdl === "" ? (log.info("preResolversSchemaHook", undefined, `hash matches but live schema could not be introspected — forcing repair push (check appsync:GetIntrospectionSchema permission)`), false) : (
|
|
651
|
+
missingFields.length !== 0 ? (log.info("preResolversSchemaHook", undefined, `hash matches but live schema is missing ` + missingFields.length.toString() + ` expected root field(s) (e.g. ` + missingFields.slice(0, 5).join(", ") + `) — forcing repair push`), false) : (log.info("preResolversSchemaHook", undefined, `SDL unchanged (hash ` + currentHash.slice(0, 12) + `…) and live schema is a superset of the expected root fields (` + countRoots(liveSdl).toString() + ` live); skipping push`), true)
|
|
652
|
+
)
|
|
653
|
+
) : false;
|
|
665
654
|
if (!skipPush) {
|
|
666
655
|
if (GraphQL_Stitcher$ReventlessCore.isCatastrophicSchemaShrink(liveSdl, sdl, deploySchemaShrinkThreshold)) {
|
|
667
656
|
return log.error("preResolversSchemaHook", undefined, `ABORTED schema push for ` + apiId + `: stitched SDL (` + countRoots(sdl).toString() + ` root field(s)) would catastrophically shrink the live schema (` + countRoots(liveSdl).toString() + ` root field(s), threshold ` + deploySchemaShrinkThreshold.toString() + `) — refusing to clobber resolvers (likely a stale concurrent-deploy scan)`);
|
|
@@ -692,24 +681,30 @@ function MakeWithConfig(Config) {
|
|
|
692
681
|
};
|
|
693
682
|
let hooks_preAdminResolversSchemaHook = adminBarrier => {
|
|
694
683
|
let match = splitApiOutputsRef.contents;
|
|
695
|
-
let
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
684
|
+
let targetApiOpt = match !== undefined ? match.platformApi : (
|
|
685
|
+
Config.splitApi ? undefined : domainApi
|
|
686
|
+
);
|
|
687
|
+
if (targetApiOpt !== undefined) {
|
|
688
|
+
let adminBaseFragment = AppSync_Adapter$ReventlessAws.injectAwsAuthAll(AdminApi$ReventlessCore.baseFragment(Config.cloner), "Admin", undefined);
|
|
689
|
+
let sdl = AppSync_Adapter$ReventlessAws.stampSharedIamTypes(GraphQL_Stitcher$ReventlessCore.stitch(adminBaseFragment, []));
|
|
690
|
+
return Output$Pulumi.flatMap(Pulumi.all([
|
|
691
|
+
targetApiOpt,
|
|
692
|
+
adminBarrier
|
|
693
|
+
]), param => Output$Pulumi.flatMap(param[0].id, apiId => {
|
|
694
|
+
log.info("preAdminResolversSchemaHook", undefined, `Pushing admin schema to ` + apiId);
|
|
695
|
+
let client = AppSync_Adapter$ReventlessAws.getClient();
|
|
696
|
+
return AppSync_Adapter$ReventlessAws.startSchemaCreationRetrying(client, {
|
|
697
|
+
apiId: apiId,
|
|
698
|
+
definition: sdl
|
|
699
|
+
}).then(async () => {
|
|
700
|
+
log.info("preAdminResolversSchemaHook", undefined, "startSchemaCreation called, waiting for ACTIVE");
|
|
701
|
+
await AppSync_Adapter$ReventlessAws.waitForSchemaActive(client, apiId, undefined, undefined);
|
|
702
|
+
return log.info("preAdminResolversSchemaHook", undefined, "schema is ACTIVE");
|
|
703
|
+
});
|
|
704
|
+
}));
|
|
705
|
+
}
|
|
706
|
+
log.error("preAdminResolversSchemaHook", undefined, "split mode but the PlatformApi is not available at hook time — SKIPPING the admin schema push to avoid clobbering the DomainApi (pushing admin-base here would wipe every plugin field)");
|
|
707
|
+
return adminBarrier;
|
|
713
708
|
};
|
|
714
709
|
let hooks_inboundAppSyncResolverHook = param => InboundTranslationResolvers_AppSync$ReventlessAws.make(resolveHookedApi(), param.runtime, param.fieldNames, param.opts);
|
|
715
710
|
let hooks_dcbAppSyncResolverHook = param => CommandGeneratorResolvers_AppSync$ReventlessAws.makeDcb(resolveHookedApi(), param.runtime, param.fieldNames, param.tags, param.opts);
|
|
@@ -1876,23 +1871,12 @@ function Make($star) {
|
|
|
1876
1871
|
let client = AppSync_Adapter$ReventlessAws.getClient();
|
|
1877
1872
|
let liveSdl = await AppSync_Adapter$ReventlessAws.getIntrospectionSdl(client, apiId);
|
|
1878
1873
|
let countRoots = s => (GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Mutation") + GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Query") | 0) + GraphQL_Stitcher$ReventlessCore.countRootTypeFields(s, "Subscription") | 0;
|
|
1879
|
-
let
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
skipPush = false;
|
|
1886
|
-
} else if (live < expected) {
|
|
1887
|
-
log.info("preResolversSchemaHook", undefined, `hash matches but live schema drifted (` + live.toString() + ` root field(s) live vs ` + expected.toString() + ` expected) — forcing repair push`);
|
|
1888
|
-
skipPush = false;
|
|
1889
|
-
} else {
|
|
1890
|
-
log.info("preResolversSchemaHook", undefined, `SDL unchanged (hash ` + currentHash.slice(0, 12) + `…) and live schema intact (` + live.toString() + ` root fields); skipping push`);
|
|
1891
|
-
skipPush = true;
|
|
1892
|
-
}
|
|
1893
|
-
} else {
|
|
1894
|
-
skipPush = false;
|
|
1895
|
-
}
|
|
1874
|
+
let missingFields = GraphQL_Stitcher$ReventlessCore.missingRootFields(sdl, liveSdl);
|
|
1875
|
+
let skipPush = storedHash !== undefined && storedHash === currentHash ? (
|
|
1876
|
+
liveSdl === "" ? (log.info("preResolversSchemaHook", undefined, `hash matches but live schema could not be introspected — forcing repair push (check appsync:GetIntrospectionSchema permission)`), false) : (
|
|
1877
|
+
missingFields.length !== 0 ? (log.info("preResolversSchemaHook", undefined, `hash matches but live schema is missing ` + missingFields.length.toString() + ` expected root field(s) (e.g. ` + missingFields.slice(0, 5).join(", ") + `) — forcing repair push`), false) : (log.info("preResolversSchemaHook", undefined, `SDL unchanged (hash ` + currentHash.slice(0, 12) + `…) and live schema is a superset of the expected root fields (` + countRoots(liveSdl).toString() + ` live); skipping push`), true)
|
|
1878
|
+
)
|
|
1879
|
+
) : false;
|
|
1896
1880
|
if (!skipPush) {
|
|
1897
1881
|
if (GraphQL_Stitcher$ReventlessCore.isCatastrophicSchemaShrink(liveSdl, sdl, deploySchemaShrinkThreshold)) {
|
|
1898
1882
|
return log.error("preResolversSchemaHook", undefined, `ABORTED schema push for ` + apiId + `: stitched SDL (` + countRoots(sdl).toString() + ` root field(s)) would catastrophically shrink the live schema (` + countRoots(liveSdl).toString() + ` root field(s), threshold ` + deploySchemaShrinkThreshold.toString() + `) — refusing to clobber resolvers (likely a stale concurrent-deploy scan)`);
|
|
@@ -1923,24 +1907,28 @@ function Make($star) {
|
|
|
1923
1907
|
};
|
|
1924
1908
|
let hooks_preAdminResolversSchemaHook = adminBarrier => {
|
|
1925
1909
|
let match = splitApiOutputsRef.contents;
|
|
1926
|
-
let
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1910
|
+
let targetApiOpt = match !== undefined ? match.platformApi : undefined;
|
|
1911
|
+
if (targetApiOpt !== undefined) {
|
|
1912
|
+
let adminBaseFragment = AppSync_Adapter$ReventlessAws.injectAwsAuthAll(AdminApi$ReventlessCore.baseFragment(false), "Admin", undefined);
|
|
1913
|
+
let sdl = AppSync_Adapter$ReventlessAws.stampSharedIamTypes(GraphQL_Stitcher$ReventlessCore.stitch(adminBaseFragment, []));
|
|
1914
|
+
return Output$Pulumi.flatMap(Pulumi.all([
|
|
1915
|
+
targetApiOpt,
|
|
1916
|
+
adminBarrier
|
|
1917
|
+
]), param => Output$Pulumi.flatMap(param[0].id, apiId => {
|
|
1918
|
+
log.info("preAdminResolversSchemaHook", undefined, `Pushing admin schema to ` + apiId);
|
|
1919
|
+
let client = AppSync_Adapter$ReventlessAws.getClient();
|
|
1920
|
+
return AppSync_Adapter$ReventlessAws.startSchemaCreationRetrying(client, {
|
|
1921
|
+
apiId: apiId,
|
|
1922
|
+
definition: sdl
|
|
1923
|
+
}).then(async () => {
|
|
1924
|
+
log.info("preAdminResolversSchemaHook", undefined, "startSchemaCreation called, waiting for ACTIVE");
|
|
1925
|
+
await AppSync_Adapter$ReventlessAws.waitForSchemaActive(client, apiId, undefined, undefined);
|
|
1926
|
+
return log.info("preAdminResolversSchemaHook", undefined, "schema is ACTIVE");
|
|
1927
|
+
});
|
|
1928
|
+
}));
|
|
1929
|
+
}
|
|
1930
|
+
log.error("preAdminResolversSchemaHook", undefined, "split mode but the PlatformApi is not available at hook time — SKIPPING the admin schema push to avoid clobbering the DomainApi (pushing admin-base here would wipe every plugin field)");
|
|
1931
|
+
return adminBarrier;
|
|
1944
1932
|
};
|
|
1945
1933
|
let hooks_inboundAppSyncResolverHook = param => InboundTranslationResolvers_AppSync$ReventlessAws.make(resolveHookedApi(), param.runtime, param.fieldNames, param.opts);
|
|
1946
1934
|
let hooks_dcbAppSyncResolverHook = param => CommandGeneratorResolvers_AppSync$ReventlessAws.makeDcb(resolveHookedApi(), param.runtime, param.fieldNames, param.tags, param.opts);
|