diff --git a/assets/error_codes.txt b/assets/error_codes.txt
new file mode 100644
index 0000000..41d51f3
--- /dev/null
+++ b/assets/error_codes.txt
@@ -0,0 +1,95 @@
+const cooldownConflictError = 4000
+const waypointNoAccessError = 4001
+const tokenEmptyError = 4100
+const tokenMissingSubjectError = 4101
+const tokenInvalidSubjectError = 4102
+const missingTokenRequestError = 4103
+const invalidTokenRequestError = 4104
+const invalidTokenSubjectError = 4105
+const accountNotExistsError = 4106
+const agentNotExistsError = 4107
+const accountHasNoAgentError = 4108
+const registerAgentExistsError = 4109
+const registerAgentSymbolReservedError = 4110
+const registerAgentConflictSymbolError = 4111
+const navigateInTransitError = 4200
+const navigateInvalidDestinationError = 4201
+const navigateOutsideSystemError = 4202
+const navigateInsufficientFuelError = 4203
+const navigateSameDestinationError = 4204
+const shipExtractInvalidWaypointError = 4205
+const shipExtractPermissionError = 4206
+const shipJumpNoSystemError = 4207
+const shipJumpSameSystemError = 4208
+const shipJumpMissingModuleError = 4210
+const shipJumpNoValidWaypointError = 4211
+const shipJumpMissingAntimatterError = 4212
+const shipInTransitError = 4214
+const shipMissingSensorArraysError = 4215
+const purchaseShipCreditsError = 4216
+const shipCargoExceedsLimitError = 4217
+const shipCargoMissingError = 4218
+const shipCargoUnitCountError = 4219
+const shipSurveyVerificationError = 4220
+const shipSurveyExpirationError = 4221
+const shipSurveyWaypointTypeError = 4222
+const shipSurveyOrbitError = 4223
+const shipSurveyExhaustedError = 4224
+const shipRefuelDockedError = 4225
+const shipRefuelInvalidWaypointError = 4226
+const shipMissingMountsError = 4227
+const shipCargoFullError = 4228
+const shipJumpFromGateToGateError = 4229
+const waypointChartedError = 4230
+const shipTransferShipNotFound = 4231
+const shipTransferAgentConflict = 4232
+const shipTransferSameShipConflict = 4233
+const shipTransferLocationConflict = 4234
+const warpInsideSystemError = 4235
+const shipNotInOrbitError = 4236
+const shipInvalidRefineryGoodError = 4237
+const shipInvalidRefineryTypeError = 4238
+const shipMissingRefineryError = 4239
+const shipMissingSurveyorError = 4240
+const shipMissingWarpDriveError = 4241
+const shipMissingMineralProcessorError = 4242
+const shipMissingMiningLasersError = 4243
+const shipNotDockedError = 4244
+const purchaseShipNotPresentError = 4245
+const shipMountNoShipyardError = 4246
+const shipMissingMountError = 4247
+const shipMountInsufficientCreditsError = 4248
+const shipMissingPowerError = 4249
+const shipMissingSlotsError = 4250
+const shipMissingMountsError = 4251
+const shipMissingCrewError = 4252
+const shipExtractDestabilizedError = 4253
+const shipJumpInvalidOriginError = 4254
+const shipJumpInvalidWaypointError = 4255
+const shipJumpOriginUnderConstructionError = 4256
+const shipMissingGasProcessorError = 4257
+const shipMissingGasSiphonsError = 4258
+const shipSiphonInvalidWaypointError = 4259
+const shipSiphonPermissionError = 4260
+const waypointNoYieldError = 4261
+const shipJumpDestinationUnderConstructionError = 4262
+const acceptContractNotAuthorizedError = 4500
+const acceptContractConflictError = 4501
+const fulfillContractDeliveryError = 4502
+const contractDeadlineError = 4503
+const contractFulfilledError = 4504
+const contractNotAcceptedError = 4505
+const contractNotAuthorizedError = 4506
+const shipDeliverTermsError = 4508
+const shipDeliverFulfilledError = 4509
+const shipDeliverInvalidLocationError = 4510
+const existingContractError = 4511
+const marketTradeInsufficientCreditsError = 4600
+const marketTradeNoPurchaseError = 4601
+const marketTradeNotSoldError = 4602
+const marketNotFoundError = 4603
+const marketTradeUnitLimitError = 4604
+const waypointNoFactionError = 4700
+const constructionMaterialNotRequired = 4800
+const constructionMaterialFulfilled = 4801
+const shipConstructionInvalidLocationError = 4802
\ No newline at end of file
diff --git a/assets/space-traders-sdk-authentication.png b/assets/space-traders-sdk-authentication.png
new file mode 100644
index 0000000..9e2c7da
Binary files /dev/null and b/assets/space-traders-sdk-authentication.png differ
diff --git a/assets/space-traders-sdk-error-handling.png b/assets/space-traders-sdk-error-handling.png
new file mode 100644
index 0000000..2410a92
Binary files /dev/null and b/assets/space-traders-sdk-error-handling.png differ
diff --git a/assets/space-traders-sdk-retries.png b/assets/space-traders-sdk-retries.png
new file mode 100644
index 0000000..828e774
Binary files /dev/null and b/assets/space-traders-sdk-retries.png differ
diff --git a/sdk/README.md b/sdk/README.md
index 5b24152..ac4bc77 100644
--- a/sdk/README.md
+++ b/sdk/README.md
@@ -59,6 +59,33 @@ By default, the connector read the token from the process variable with the name
If you use a different variable for the token, or store the token as a connector secret, you need to adjust the
authentication property of the connector.
+![SDK property authentication](../assets/space-traders-sdk-authentication.png)
+
+### API Retries
+
+API calls can fail due to various reasons. One reason is that the SpaceTraders API is rate limited. It fails a call if
+you send too many requests per second.
+
+The SDK allows to configure the number of retries and the delay between retries.
+
+By default, it retries the call 10 times with a delay of 1 second between retries.
+
+![SDK property retries](../assets/space-traders-sdk-retries.png)
+
+### API Error handling
+
+API calls can fail due to various reasons, for example, network issues or invalid parameters.
+
+The SDK allows to configure the error handling. A common use case is to throw a BPMN error if the call fails with a
+specific error code (e.g. `4236`). The BPMN error can be caught by an error boundary event with the given
+error code and handled in the process.
+
+By default, the SDK throws a BPMN error if the call returns a `400` status code. The BPMN error code is the name to the
+SpaceTrader's error code (e.g. `shipNotInOrbitError` for the code `4236`). All error codes are listed
+[here](https://docs.spacetraders.io/api-guide/response-errors/).
+
+![SDK property error handling](../assets/space-traders-sdk-error-handling.png)
+
## Useful resources and tools
Resources:
diff --git a/sdk/spacetraders.json b/sdk/spacetraders.json
index 6948a98..8b1e6a3 100644
--- a/sdk/spacetraders.json
+++ b/sdk/spacetraders.json
@@ -6,7 +6,7 @@
"icon": {
"contents": "data:image/png;base64,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"
},
- "version": 2,
+ "version": 3,
"appliesTo": [
"bpmn:Task"
],
@@ -30,6 +30,16 @@
"id": "responseMapping",
"label": "Response Mapping"
},
+ {
+ "id": "error",
+ "label": "API Error handling",
+ "tooltip": "Handle error response codes from SpaceTrader's API in the process as BPMN error events."
+ },
+ {
+ "id": "retries",
+ "label": "API Retries",
+ "tooltip": "Define retries if SpaceTrader's API returns an error response. Useful to handle API rate limiting."
+ },
{
"id": "modificationWarning",
"label": "Generated (DO NOT MODIFY)"
@@ -6955,6 +6965,86 @@
"equals": "register"
},
"optional": true
+ },
+ {
+ "id": "customErrorHandling",
+ "label": "How to handle errors?",
+ "description": "By default, it maps the an error to a BPMN error event. The error code is the name of the SpaceTrader's error.",
+ "group": "error",
+ "binding": {
+ "type": "zeebe:property",
+ "name": "custom_error_handling"
+ },
+ "type": "Dropdown",
+ "choices": [
+ {
+ "name": "BPMN error by name (default)",
+ "value": "by_error_name"
+ },
+ {
+ "name": "Custom",
+ "value": "custom"
+ }
+ ],
+ "value": "by_error_name"
+ },
+ {
+ "id": "errorExpression",
+ "label": "Error expression",
+ "value": "={\n status: error.code,\n error_code: extract(error.message, \"\\d{4}\")[1],\n error_codes: {\n \"4000\":\"cooldownConflictError\",\n \"4001\":\"waypointNoAccessError\",\n \"4100\":\"tokenEmptyError\",\n \"4101\":\"tokenMissingSubjectError\",\n \"4102\":\"tokenInvalidSubjectError\",\n \"4103\":\"missingTokenRequestError\",\n \"4104\":\"invalidTokenRequestError\",\n \"4105\":\"invalidTokenSubjectError\",\n \"4106\":\"accountNotExistsError\",\n \"4107\":\"agentNotExistsError\",\n \"4108\":\"accountHasNoAgentError\",\n \"4109\":\"registerAgentExistsError\",\n \"4110\":\"registerAgentSymbolReservedError\",\n \"4111\":\"registerAgentConflictSymbolError\",\n \"4200\":\"navigateInTransitError\",\n \"4201\":\"navigateInvalidDestinationError\",\n \"4202\":\"navigateOutsideSystemError\",\n \"4203\":\"navigateInsufficientFuelError\",\n \"4204\":\"navigateSameDestinationError\",\n \"4205\":\"shipExtractInvalidWaypointError\",\n \"4206\":\"shipExtractPermissionError\",\n \"4207\":\"shipJumpNoSystemError\",\n \"4208\":\"shipJumpSameSystemError\",\n \"4210\":\"shipJumpMissingModuleError\",\n \"4211\":\"shipJumpNoValidWaypointError\",\n \"4212\":\"shipJumpMissingAntimatterError\",\n \"4214\":\"shipInTransitError\",\n \"4215\":\"shipMissingSensorArraysError\",\n \"4216\":\"purchaseShipCreditsError\",\n \"4217\":\"shipCargoExceedsLimitError\",\n \"4218\":\"shipCargoMissingError\",\n \"4219\":\"shipCargoUnitCountError\",\n \"4220\":\"shipSurveyVerificationError\",\n \"4221\":\"shipSurveyExpirationError\",\n \"4222\":\"shipSurveyWaypointTypeError\",\n \"4223\":\"shipSurveyOrbitError\",\n \"4224\":\"shipSurveyExhaustedError\",\n \"4225\":\"shipRefuelDockedError\",\n \"4226\":\"shipRefuelInvalidWaypointError\",\n \"4227\":\"shipMissingMountsError\",\n \"4228\":\"shipCargoFullError\",\n \"4229\":\"shipJumpFromGateToGateError\",\n \"4230\":\"waypointChartedError\",\n \"4231\":\"shipTransferShipNotFound\",\n \"4232\":\"shipTransferAgentConflict\",\n \"4233\":\"shipTransferSameShipConflict\",\n \"4234\":\"shipTransferLocationConflict\",\n \"4235\":\"warpInsideSystemError\",\n \"4236\":\"shipNotInOrbitError\",\n \"4237\":\"shipInvalidRefineryGoodError\",\n \"4238\":\"shipInvalidRefineryTypeError\",\n \"4239\":\"shipMissingRefineryError\",\n \"4240\":\"shipMissingSurveyorError\",\n \"4241\":\"shipMissingWarpDriveError\",\n \"4242\":\"shipMissingMineralProcessorError\",\n \"4243\":\"shipMissingMiningLasersError\",\n \"4244\":\"shipNotDockedError\",\n \"4245\":\"purchaseShipNotPresentError\",\n \"4246\":\"shipMountNoShipyardError\",\n \"4247\":\"shipMissingMountError\",\n \"4248\":\"shipMountInsufficientCreditsError\",\n \"4249\":\"shipMissingPowerError\",\n \"4250\":\"shipMissingSlotsError\",\n \"4251\":\"shipMissingMountsError\",\n \"4252\":\"shipMissingCrewError\",\n \"4253\":\"shipExtractDestabilizedError\",\n \"4254\":\"shipJumpInvalidOriginError\",\n \"4255\":\"shipJumpInvalidWaypointError\",\n \"4256\":\"shipJumpOriginUnderConstructionError\",\n \"4257\":\"shipMissingGasProcessorError\",\n \"4258\":\"shipMissingGasSiphonsError\",\n \"4259\":\"shipSiphonInvalidWaypointError\",\n \"4260\":\"shipSiphonPermissionError\",\n \"4261\":\"waypointNoYieldError\",\n \"4262\":\"shipJumpDestinationUnderConstructionError\",\n \"4500\":\"acceptContractNotAuthorizedError\",\n \"4501\":\"acceptContractConflictError\",\n \"4502\":\"fulfillContractDeliveryError\",\n \"4503\":\"contractDeadlineError\",\n \"4504\":\"contractFulfilledError\",\n \"4505\":\"contractNotAcceptedError\",\n \"4506\":\"contractNotAuthorizedError\",\n \"4508\":\"shipDeliverTermsError\",\n \"4509\":\"shipDeliverFulfilledError\",\n \"4510\":\"shipDeliverInvalidLocationError\",\n \"4511\":\"existingContractError\",\n \"4600\":\"marketTradeInsufficientCreditsError\",\n \"4601\":\"marketTradeNoPurchaseError\",\n \"4602\":\"marketTradeNotSoldError\",\n \"4603\":\"marketNotFoundError\",\n \"4604\":\"marketTradeUnitLimitError\",\n \"4700\":\"waypointNoFactionError\",\n \"4800\":\"constructionMaterialNotRequired\",\n \"4801\":\"constructionMaterialFulfilled\",\n \"4802\":\"shipConstructionInvalidLocationError\"\n },\n bpmn_error_code: get or else(get value(error_codes, error_code), error_code),\n bpmn_error_message: substring(extract(error.message, \"\\\"message\\\":\\\"(\\w|\\d|\\s|\\.|\\-)+\")[1], 12),\n result: \n if status = \"400\" \n then bpmnError(bpmn_error_code, bpmn_error_message)\n else null\n}.result",
+ "group": "error",
+ "binding": {
+ "key": "errorExpression",
+ "type": "zeebe:taskHeader"
+ },
+ "type": "Hidden",
+ "condition": {
+ "property": "customErrorHandling",
+ "equals": "by_error_name"
+ }
+ },
+ {
+ "id": "customErrorExpression",
+ "label": "Error expression",
+ "description": "Expression to handle errors. Details in the documentation.",
+ "value": "=if error.code = \"400\"\nthen bpmnError(\"error-1\", \"Something wrong.\")\nelse null",
+ "feel": "required",
+ "group": "error",
+ "binding": {
+ "key": "errorExpression",
+ "type": "zeebe:taskHeader"
+ },
+ "type": "Text",
+ "condition": {
+ "property": "customErrorHandling",
+ "equals": "custom"
+ }
+ },
+ {
+ "id": "retryCount",
+ "label": "Retries",
+ "description": "Number of retries",
+ "value": "10",
+ "feel": "optional",
+ "group": "retries",
+ "binding": {
+ "property": "retries",
+ "type": "zeebe:taskDefinition"
+ },
+ "type": "String"
+ },
+ {
+ "id": "retryBackoff",
+ "label": "Retry backoff",
+ "description": "ISO-8601 duration to wait between retries",
+ "value": "PT1S",
+ "feel": "optional",
+ "group": "retries",
+ "binding": {
+ "key": "retryBackoff",
+ "type": "zeebe:taskHeader"
+ },
+ "type": "String"
}
]
}
\ No newline at end of file