eoapi-cdk 8.1.1 → 8.2.0

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.
Files changed (62) hide show
  1. package/.jsii +594 -26
  2. package/lib/bastion-host/index.js +1 -1
  3. package/lib/database/index.d.ts +1 -0
  4. package/lib/database/index.js +5 -5
  5. package/lib/index.d.ts +2 -0
  6. package/lib/index.js +3 -1
  7. package/lib/ingestor-api/index.js +1 -1
  8. package/lib/stac-api/index.js +1 -1
  9. package/lib/stac-browser/index.js +1 -1
  10. package/lib/stac-item-loader/index.d.ts +322 -0
  11. package/lib/stac-item-loader/index.js +251 -0
  12. package/lib/stac-item-loader/runtime/Dockerfile +18 -0
  13. package/lib/stac-item-loader/runtime/pyproject.toml +17 -0
  14. package/lib/stac-item-loader/runtime/src/stac_item_loader/handler.py +241 -0
  15. package/lib/stactools-item-generator/index.d.ts +243 -0
  16. package/lib/stactools-item-generator/index.js +204 -0
  17. package/lib/stactools-item-generator/runtime/Dockerfile +20 -0
  18. package/lib/stactools-item-generator/runtime/pyproject.toml +16 -0
  19. package/lib/stactools-item-generator/runtime/src/stactools_item_generator/__init__.py +2 -0
  20. package/lib/stactools-item-generator/runtime/src/stactools_item_generator/handler.py +176 -0
  21. package/lib/stactools-item-generator/runtime/src/stactools_item_generator/item.py +77 -0
  22. package/lib/tipg-api/index.js +1 -1
  23. package/lib/titiler-pgstac-api/index.js +1 -1
  24. package/package.json +1 -1
  25. package/pyproject.toml +45 -0
  26. package/uv.lock +1065 -0
  27. package/.devcontainer/devcontainer.json +0 -4
  28. package/.github/pull_request_template.md +0 -4
  29. package/.github/workflows/build.yaml +0 -73
  30. package/.github/workflows/build_and_release.yaml +0 -13
  31. package/.github/workflows/conventional-pr.yaml +0 -26
  32. package/.github/workflows/deploy.yaml +0 -84
  33. package/.github/workflows/distribute.yaml +0 -46
  34. package/.github/workflows/docs.yaml +0 -26
  35. package/.github/workflows/lint.yaml +0 -26
  36. package/.github/workflows/tox.yaml +0 -26
  37. package/.nvmrc +0 -1
  38. package/.pre-commit-config.yaml +0 -23
  39. package/CHANGELOG.md +0 -471
  40. package/diagrams/bastion_diagram.excalidraw +0 -1416
  41. package/diagrams/bastion_diagram.png +0 -0
  42. package/diagrams/ingestor_diagram.excalidraw +0 -2274
  43. package/diagrams/ingestor_diagram.png +0 -0
  44. package/integration_tests/cdk/README.md +0 -55
  45. package/integration_tests/cdk/app.py +0 -186
  46. package/integration_tests/cdk/cdk.json +0 -32
  47. package/integration_tests/cdk/config.py +0 -52
  48. package/integration_tests/cdk/package-lock.json +0 -42
  49. package/integration_tests/cdk/package.json +0 -7
  50. package/integration_tests/cdk/requirements.txt +0 -7
  51. package/lib/database/lambda/package-lock.json +0 -1324
  52. package/lib/ingestor-api/runtime/tests/conftest.py +0 -270
  53. package/lib/ingestor-api/runtime/tests/test_collection.py +0 -87
  54. package/lib/ingestor-api/runtime/tests/test_collection_endpoint.py +0 -41
  55. package/lib/ingestor-api/runtime/tests/test_ingestor.py +0 -60
  56. package/lib/ingestor-api/runtime/tests/test_registration.py +0 -207
  57. package/lib/ingestor-api/runtime/tests/test_utils.py +0 -35
  58. package/lib/ingestor-api/runtime/tests/test_validators.py +0 -164
  59. package/ruff.toml +0 -23
  60. package/tox.ini +0 -16
  61. package/tsconfig.tsbuildinfo +0 -1
  62. /package/lib/{ingestor-api/runtime/tests → stac-item-loader/runtime/src/stac_item_loader}/__init__.py +0 -0
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.StactoolsItemGenerator = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
7
+ const constructs_1 = require("constructs");
8
+ const aws_ecr_assets_1 = require("aws-cdk-lib/aws-ecr-assets");
9
+ const path = require("path");
10
+ /**
11
+ * AWS CDK Construct for STAC Item Generation Infrastructure
12
+ *
13
+ * The StactoolsItemGenerator creates a serverless, event-driven system for generating
14
+ * STAC (SpatioTemporal Asset Catalog) items from source data. This construct
15
+ * implements the first phase of a two-stage ingestion pipeline that transforms
16
+ * raw geospatial data into standardized STAC metadata.
17
+ *
18
+ * ## Architecture Overview
19
+ *
20
+ * This construct creates the following AWS resources:
21
+ * - **SNS Topic**: Entry point for triggering item generation workflows
22
+ * - **SQS Queue**: Buffers generation requests (120-second visibility timeout)
23
+ * - **Dead Letter Queue**: Captures failed messages after 5 processing attempts
24
+ * - **Lambda Function**: Containerized function that generates STAC items using stactools
25
+ *
26
+ * ## Data Flow
27
+ *
28
+ * 1. External systems publish ItemRequest messages to the SNS topic with metadata about assets
29
+ * 2. The SQS queue buffers these messages and triggers the Lambda function
30
+ * 3. The Lambda function:
31
+ * - Uses `uvx` to install the required stactools package
32
+ * - Executes the `create-item` CLI command with provided arguments
33
+ * - Publishes generated STAC items to the ItemLoad topic
34
+ * 4. Failed processing attempts are sent to the dead letter queue
35
+ *
36
+ * ## Operational Characteristics
37
+ *
38
+ * - **Scalability**: Lambda scales automatically based on queue depth (up to maxConcurrency)
39
+ * - **Flexibility**: Supports any stactools package through dynamic installation
40
+ * - **Reliability**: Dead letter queue captures failed generation attempts
41
+ * - **Isolation**: Each generation task runs in a fresh container environment
42
+ * - **Observability**: CloudWatch logs retained for one week
43
+ *
44
+ * ## Message Schema
45
+ *
46
+ * The function expects messages matching the ItemRequest model:
47
+ *
48
+ * ```json
49
+ * {
50
+ * "package_name": "stactools-glad-global-forest-change",
51
+ * "group_name": "gladglobalforestchange",
52
+ * "create_item_args": [
53
+ * "https://example.com/data.tif"
54
+ * ],
55
+ * "collection_id": "glad-global-forest-change-1.11"
56
+ * }
57
+ * ```
58
+ *
59
+ * ## Usage Example
60
+ *
61
+ * ```typescript
62
+ * // Create item loader first (or get existing topic ARN)
63
+ * const loader = new StacItemLoader(this, 'ItemLoader', {
64
+ * pgstacDb: database
65
+ * });
66
+ *
67
+ * // Create item generator that feeds the loader
68
+ * const generator = new StactoolsItemGenerator(this, 'ItemGenerator', {
69
+ * itemLoadTopicArn: loader.topic.topicArn,
70
+ * lambdaTimeoutSeconds: 120, // Allow time for package installation
71
+ * maxConcurrency: 100, // Control parallel processing
72
+ * batchSize: 10 // Process 10 requests per invocation
73
+ * });
74
+ *
75
+ * // Grant permission to publish to the loader topic
76
+ * loader.topic.grantPublish(generator.lambdaFunction);
77
+ * ```
78
+ *
79
+ * ## Publishing Generation Requests
80
+ *
81
+ * Send messages to the generator topic to trigger item creation:
82
+ *
83
+ * ```bash
84
+ * aws sns publish --topic-arn $ITEM_GEN_TOPIC --message '{
85
+ * "package_name": "stactools-glad-global-forest-change",
86
+ * "group_name": "gladglobalforestchange",
87
+ * "create_item_args": [
88
+ * "https://storage.googleapis.com/earthenginepartners-hansen/GFC-2023-v1.11/Hansen_GFC-2023-v1.11_gain_40N_080W.tif"
89
+ * ],
90
+ * "collection_id": "glad-global-forest-change-1.11"
91
+ * }'
92
+ * ```
93
+ *
94
+ * ## Batch Processing Example
95
+ *
96
+ * For processing many assets, you can loop through URLs:
97
+ *
98
+ * ```bash
99
+ * while IFS= read -r url; do
100
+ * aws sns publish --topic-arn "$ITEM_GEN_TOPIC" --message "{
101
+ * \"package_name\": \"stactools-glad-glclu2020\",
102
+ * \"group_name\": \"gladglclu2020\",
103
+ * \"create_item_args\": [\"$url\"]
104
+ * }"
105
+ * done < urls.txt
106
+ * ```
107
+ *
108
+ * ## Monitoring and Troubleshooting
109
+ *
110
+ * - Monitor Lambda logs: `/aws/lambda/{FunctionName}`
111
+ * - Check dead letter queue for failed generation attempts
112
+ * - Use CloudWatch metrics to track processing rates and errors
113
+ * - Failed items can be replayed from the dead letter queue
114
+ *
115
+ * ## Supported Stactools Packages
116
+ *
117
+ * Any package available on PyPI that follows the stactools plugin pattern
118
+ * can be used. Examples include:
119
+ * - `stactools-glad-global-forest-change`
120
+ * - `stactools-glad-glclu2020`
121
+ * - `stactools-landsat`
122
+ * - `stactools-sentinel2`
123
+ *
124
+ * @see {@link https://github.com/stactools-packages} for available stactools packages
125
+ * @see {@link https://stactools.readthedocs.io/} for stactools documentation
126
+ */
127
+ class StactoolsItemGenerator extends constructs_1.Construct {
128
+ constructor(scope, id, props) {
129
+ super(scope, id);
130
+ const timeoutSeconds = props.lambdaTimeoutSeconds ?? 120;
131
+ const lambdaRuntime = props.lambdaRuntime ?? aws_cdk_lib_1.aws_lambda.Runtime.PYTHON_3_11;
132
+ // Create dead letter queue
133
+ this.deadLetterQueue = new aws_cdk_lib_1.aws_sqs.Queue(this, "DeadLetterQueue", {
134
+ retentionPeriod: aws_cdk_lib_1.Duration.days(14),
135
+ });
136
+ // Create main queue
137
+ this.queue = new aws_cdk_lib_1.aws_sqs.Queue(this, "Queue", {
138
+ visibilityTimeout: aws_cdk_lib_1.Duration.seconds(timeoutSeconds + 10),
139
+ encryption: aws_cdk_lib_1.aws_sqs.QueueEncryption.SQS_MANAGED,
140
+ deadLetterQueue: {
141
+ maxReceiveCount: 5,
142
+ queue: this.deadLetterQueue,
143
+ },
144
+ });
145
+ // Create SNS topic
146
+ this.topic = new aws_cdk_lib_1.aws_sns.Topic(this, "Topic", {
147
+ displayName: `${id}-ItemGenTopic`,
148
+ });
149
+ // Subscribe the queue to the topic
150
+ this.topic.addSubscription(new aws_cdk_lib_1.aws_sns_subscriptions.SqsSubscription(this.queue));
151
+ // Create the lambda function
152
+ this.lambdaFunction = new aws_cdk_lib_1.aws_lambda.DockerImageFunction(this, "Function", {
153
+ code: aws_cdk_lib_1.aws_lambda.DockerImageCode.fromImageAsset(path.join(__dirname, ".."), {
154
+ file: "stactools-item-generator/runtime/Dockerfile",
155
+ platform: aws_ecr_assets_1.Platform.LINUX_AMD64,
156
+ buildArgs: {
157
+ PYTHON_VERSION: lambdaRuntime.toString().replace("python", ""),
158
+ },
159
+ }),
160
+ memorySize: props.memorySize ?? 1024,
161
+ timeout: aws_cdk_lib_1.Duration.seconds(timeoutSeconds),
162
+ logRetention: aws_cdk_lib_1.aws_logs.RetentionDays.ONE_WEEK,
163
+ environment: {
164
+ ITEM_LOAD_TOPIC_ARN: props.itemLoadTopicArn,
165
+ LOG_LEVEL: "INFO",
166
+ ...props.environment,
167
+ },
168
+ });
169
+ // Add SQS event source to the lambda
170
+ this.lambdaFunction.addEventSource(new aws_cdk_lib_1.aws_lambda_event_sources.SqsEventSource(this.queue, {
171
+ batchSize: props.batchSize ?? 10,
172
+ reportBatchItemFailures: true,
173
+ maxConcurrency: props.maxConcurrency ?? 100,
174
+ }));
175
+ // Grant permissions to publish to the item load topic
176
+ // Note: This will be granted externally since we only have the ARN
177
+ // The consuming construct should handle this permission
178
+ // Create outputs
179
+ new aws_cdk_lib_1.CfnOutput(this, "TopicArn", {
180
+ value: this.topic.topicArn,
181
+ description: "ARN of the StactoolsItemGenerator SNS Topic",
182
+ exportName: "stactools-item-generator-topic-arn",
183
+ });
184
+ new aws_cdk_lib_1.CfnOutput(this, "QueueUrl", {
185
+ value: this.queue.queueUrl,
186
+ description: "URL of the StactoolsItemGenerator SQS Queue",
187
+ exportName: "stactools-item-generator-queue-url",
188
+ });
189
+ new aws_cdk_lib_1.CfnOutput(this, "DeadLetterQueueUrl", {
190
+ value: this.deadLetterQueue.queueUrl,
191
+ description: "URL of the StactoolsItemGenerator Dead Letter Queue",
192
+ exportName: "stactools-item-generator-deadletter-queue-url",
193
+ });
194
+ new aws_cdk_lib_1.CfnOutput(this, "FunctionName", {
195
+ value: this.lambdaFunction.functionName,
196
+ description: "Name of the StactoolsItemGenerator Lambda Function",
197
+ exportName: "stactools-item-generator-function-name",
198
+ });
199
+ }
200
+ }
201
+ exports.StactoolsItemGenerator = StactoolsItemGenerator;
202
+ _a = JSII_RTTI_SYMBOL_1;
203
+ StactoolsItemGenerator[_a] = { fqn: "eoapi-cdk.StactoolsItemGenerator", version: "8.2.0" };
204
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVNxQjtBQUNyQiwyQ0FBdUM7QUFDdkMsK0RBQXNEO0FBQ3RELDZCQUE2QjtBQWlHN0I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0hHO0FBQ0gsTUFBYSxzQkFBdUIsU0FBUSxzQkFBUztJQW9DbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFrQztRQUMxRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLE1BQU0sY0FBYyxHQUFHLEtBQUssQ0FBQyxvQkFBb0IsSUFBSSxHQUFHLENBQUM7UUFDekQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLGFBQWEsSUFBSSx3QkFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUM7UUFFeEUsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxxQkFBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsaUJBQWlCLEVBQUU7WUFDNUQsZUFBZSxFQUFFLHNCQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztTQUNuQyxDQUFDLENBQUM7UUFFSCxvQkFBb0I7UUFDcEIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLHFCQUFHLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxPQUFPLEVBQUU7WUFDeEMsaUJBQWlCLEVBQUUsc0JBQVEsQ0FBQyxPQUFPLENBQUMsY0FBYyxHQUFHLEVBQUUsQ0FBQztZQUN4RCxVQUFVLEVBQUUscUJBQUcsQ0FBQyxlQUFlLENBQUMsV0FBVztZQUMzQyxlQUFlLEVBQUU7Z0JBQ2YsZUFBZSxFQUFFLENBQUM7Z0JBQ2xCLEtBQUssRUFBRSxJQUFJLENBQUMsZUFBZTthQUM1QjtTQUNGLENBQUMsQ0FBQztRQUVILG1CQUFtQjtRQUNuQixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUkscUJBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRTtZQUN4QyxXQUFXLEVBQUUsR0FBRyxFQUFFLGVBQWU7U0FDbEMsQ0FBQyxDQUFDO1FBRUgsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUN4QixJQUFJLG1DQUFnQixDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQ2pELENBQUM7UUFFRiw2QkFBNkI7UUFDN0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLHdCQUFNLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRTtZQUNyRSxJQUFJLEVBQUUsd0JBQU0sQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUN0RSxJQUFJLEVBQUUsNkNBQTZDO2dCQUNuRCxRQUFRLEVBQUUseUJBQVEsQ0FBQyxXQUFXO2dCQUM5QixTQUFTLEVBQUU7b0JBQ1QsY0FBYyxFQUFFLGFBQWEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQztpQkFDL0Q7YUFDRixDQUFDO1lBQ0YsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVLElBQUksSUFBSTtZQUNwQyxPQUFPLEVBQUUsc0JBQVEsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDO1lBQ3pDLFlBQVksRUFBRSxzQkFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRO1lBQ3pDLFdBQVcsRUFBRTtnQkFDWCxtQkFBbUIsRUFBRSxLQUFLLENBQUMsZ0JBQWdCO2dCQUMzQyxTQUFTLEVBQUUsTUFBTTtnQkFDakIsR0FBRyxLQUFLLENBQUMsV0FBVzthQUNyQjtTQUNGLENBQUMsQ0FBQztRQUVILHFDQUFxQztRQUNyQyxJQUFJLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FDaEMsSUFBSSxzQ0FBa0IsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNoRCxTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsSUFBSSxFQUFFO1lBQ2hDLHVCQUF1QixFQUFFLElBQUk7WUFDN0IsY0FBYyxFQUFFLEtBQUssQ0FBQyxjQUFjLElBQUksR0FBRztTQUM1QyxDQUFDLENBQ0gsQ0FBQztRQUVGLHNEQUFzRDtRQUN0RCxtRUFBbUU7UUFDbkUsd0RBQXdEO1FBRXhELGlCQUFpQjtRQUNqQixJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRTtZQUM5QixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRO1lBQzFCLFdBQVcsRUFBRSw2Q0FBNkM7WUFDMUQsVUFBVSxFQUFFLG9DQUFvQztTQUNqRCxDQUFDLENBQUM7UUFFSCxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRTtZQUM5QixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRO1lBQzFCLFdBQVcsRUFBRSw2Q0FBNkM7WUFDMUQsVUFBVSxFQUFFLG9DQUFvQztTQUNqRCxDQUFDLENBQUM7UUFFSCxJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLG9CQUFvQixFQUFFO1lBQ3hDLEtBQUssRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVE7WUFDcEMsV0FBVyxFQUFFLHFEQUFxRDtZQUNsRSxVQUFVLEVBQUUsK0NBQStDO1NBQzVELENBQUMsQ0FBQztRQUVILElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsY0FBYyxFQUFFO1lBQ2xDLEtBQUssRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVk7WUFDdkMsV0FBVyxFQUFFLG9EQUFvRDtZQUNqRSxVQUFVLEVBQUUsd0NBQXdDO1NBQ3JELENBQUMsQ0FBQztJQUNMLENBQUM7O0FBM0hILHdEQTRIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIGF3c19sYW1iZGEgYXMgbGFtYmRhLFxuICBhd3Nfc3FzIGFzIHNxcyxcbiAgYXdzX3NucyBhcyBzbnMsXG4gIGF3c19zbnNfc3Vic2NyaXB0aW9ucyBhcyBzbnNTdWJzY3JpcHRpb25zLFxuICBhd3NfbGFtYmRhX2V2ZW50X3NvdXJjZXMgYXMgbGFtYmRhRXZlbnRTb3VyY2VzLFxuICBhd3NfbG9ncyBhcyBsb2dzLFxuICBEdXJhdGlvbixcbiAgQ2ZuT3V0cHV0LFxufSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBQbGF0Zm9ybSB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWNyLWFzc2V0c1wiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gcHJvcGVydGllcyBmb3IgdGhlIFN0YWN0b29sc0l0ZW1HZW5lcmF0b3IgY29uc3RydWN0LlxuICpcbiAqIFRoZSBTdGFjdG9vbHNJdGVtR2VuZXJhdG9yIGlzIHBhcnQgb2YgYSB0d28tcGhhc2Ugc2VydmVybGVzcyBTVEFDIGluZ2VzdGlvbiBwaXBlbGluZVxuICogdGhhdCBnZW5lcmF0ZXMgU1RBQyBpdGVtcyBmcm9tIHNvdXJjZSBkYXRhLiBUaGlzIGNvbnN0cnVjdCBjcmVhdGVzIHRoZVxuICogaW5mcmFzdHJ1Y3R1cmUgZm9yIHRoZSBmaXJzdCBwaGFzZSBvZiB0aGUgcGlwZWxpbmUgLSBwcm9jZXNzaW5nIG1ldGFkYXRhXG4gKiBhYm91dCBhc3NldHMgYW5kIHRyYW5zZm9ybWluZyB0aGVtIGludG8gc3RhbmRhcmRpemVkIFNUQUMgaXRlbXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGdlbmVyYXRvciA9IG5ldyBTdGFjdG9vbHNJdGVtR2VuZXJhdG9yKHRoaXMsICdJdGVtR2VuZXJhdG9yJywge1xuICogICBpdGVtTG9hZFRvcGljQXJuOiBsb2FkZXIudG9waWMudG9waWNBcm4sXG4gKiAgIGxhbWJkYVRpbWVvdXRTZWNvbmRzOiAxMjAsXG4gKiAgIG1heENvbmN1cnJlbmN5OiAxMDAsXG4gKiAgIGJhdGNoU2l6ZTogMTBcbiAqIH0pO1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YWN0b29sc0l0ZW1HZW5lcmF0b3JQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgbGFtYmRhIHJ1bnRpbWUgdG8gdXNlIGZvciB0aGUgaXRlbSBnZW5lcmF0aW9uIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBUaGUgZnVuY3Rpb24gaXMgY29udGFpbmVyaXplZCB1c2luZyBEb2NrZXIgYW5kIGNhbiBhY2NvbW1vZGF0ZSB2YXJpb3VzXG4gICAqIHN0YWN0b29scyBwYWNrYWdlcy4gVGhlIHJ1bnRpbWUgdmVyc2lvbiBzaG91bGQgYmUgY29tcGF0aWJsZSB3aXRoIHRoZVxuICAgKiBwYWNrYWdlcyB5b3UgcGxhbiB0byB1c2UgZm9yIFNUQUMgaXRlbSBnZW5lcmF0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMVxuICAgKi9cbiAgcmVhZG9ubHkgbGFtYmRhUnVudGltZT86IGxhbWJkYS5SdW50aW1lO1xuXG4gIC8qKlxuICAgKiBUaGUgdGltZW91dCBmb3IgdGhlIGl0ZW0gZ2VuZXJhdGlvbiBsYW1iZGEgaW4gc2Vjb25kcy5cbiAgICpcbiAgICogVGhpcyBzaG91bGQgYWNjb21tb2RhdGUgdGhlIHRpbWUgbmVlZGVkIHRvOlxuICAgKiAtIEluc3RhbGwgc3RhY3Rvb2xzIHBhY2thZ2VzIHVzaW5nIHV2eFxuICAgKiAtIERvd25sb2FkIGFuZCBwcm9jZXNzIHNvdXJjZSBkYXRhXG4gICAqIC0gR2VuZXJhdGUgU1RBQyBtZXRhZGF0YVxuICAgKiAtIFB1Ymxpc2ggcmVzdWx0cyB0byBTTlNcbiAgICpcbiAgICogVGhlIFNRUyB2aXNpYmlsaXR5IHRpbWVvdXQgd2lsbCBiZSBzZXQgdG8gdGhpcyB2YWx1ZSBwbHVzIDEwIHNlY29uZHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IDEyMFxuICAgKi9cbiAgcmVhZG9ubHkgbGFtYmRhVGltZW91dFNlY29uZHM/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIE1lbW9yeSBzaXplIGZvciB0aGUgbGFtYmRhIGZ1bmN0aW9uIGluIE1CLlxuICAgKlxuICAgKiBIaWdoZXIgbWVtb3J5IGFsbG9jYXRpb24gbWF5IGJlIG5lZWRlZCBmb3IgcHJvY2Vzc2luZyBsYXJnZSBnZW9zcGF0aWFsXG4gICAqIGRhdGFzZXRzIG9yIHdoZW4gc3RhY3Rvb2xzIHBhY2thZ2VzIGhhdmUgaGlnaCBtZW1vcnkgcmVxdWlyZW1lbnRzLlxuICAgKiBNb3JlIG1lbW9yeSBhbHNvIHByb3ZpZGVzIHByb3BvcnRpb25hbGx5IG1vcmUgQ1BVIHBvd2VyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMDI0XG4gICAqL1xuICByZWFkb25seSBtZW1vcnlTaXplPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBNYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IGV4ZWN1dGlvbnMuXG4gICAqXG4gICAqIFRoaXMgY29udHJvbHMgaG93IG1hbnkgaXRlbSBnZW5lcmF0aW9uIHRhc2tzIGNhbiBydW4gc2ltdWx0YW5lb3VzbHkuXG4gICAqIEhpZ2hlciBjb25jdXJyZW5jeSBlbmFibGVzIGZhc3RlciBwcm9jZXNzaW5nIG9mIGxhcmdlIGJhdGNoZXMgYnV0XG4gICAqIG1heSBzdHJhaW4gZG93bnN0cmVhbSBzeXN0ZW1zIG9yIGV4dGVybmFsIGRhdGEgc291cmNlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgMTAwXG4gICAqL1xuICByZWFkb25seSBtYXhDb25jdXJyZW5jeT86IG51bWJlcjtcblxuICAvKipcbiAgICogU1FTIGJhdGNoIHNpemUgZm9yIGxhbWJkYSBldmVudCBzb3VyY2UuXG4gICAqXG4gICAqIFRoaXMgZGV0ZXJtaW5lcyBob3cgbWFueSBnZW5lcmF0aW9uIHJlcXVlc3RzIGFyZSBwcm9jZXNzZWQgdG9nZXRoZXJcbiAgICogaW4gYSBzaW5nbGUgbGFtYmRhIGludm9jYXRpb24uIFVubGlrZSB0aGUgbG9hZGVyLCBnZW5lcmF0aW9uIHR5cGljYWxseVxuICAgKiBwcm9jZXNzZXMgaXRlbXMgaW5kaXZpZHVhbGx5LCBzbyBzbWFsbGVyIGJhdGNoIHNpemVzIGFyZSBjb21tb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IDEwXG4gICAqL1xuICByZWFkb25seSBiYXRjaFNpemU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZvciB0aGUgbGFtYmRhIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBUaGVzZSB3aWxsIGJlIG1lcmdlZCB3aXRoIGRlZmF1bHQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGluY2x1ZGluZ1xuICAgKiBJVEVNX0xPQURfVE9QSUNfQVJOIGFuZCBMT0dfTEVWRUwuIFVzZSB0aGlzIGZvciBjdXN0b20gY29uZmlndXJhdGlvblxuICAgKiBvciB0byBwYXNzIGNyZWRlbnRpYWxzIGZvciBleHRlcm5hbCBkYXRhIHNvdXJjZXMuXG4gICAqL1xuICByZWFkb25seSBlbnZpcm9ubWVudD86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgLyoqXG4gICAqIEFSTiBvZiB0aGUgU05TIHRvcGljIHRvIHB1Ymxpc2ggZ2VuZXJhdGVkIGl0ZW1zIHRvLlxuICAgKlxuICAgKiBUaGlzIGlzIHR5cGljYWxseSB0aGUgdG9waWMgZnJvbSBhIFN0YWNJdGVtTG9hZGVyIGNvbnN0cnVjdC5cbiAgICogR2VuZXJhdGVkIFNUQUMgaXRlbXMgd2lsbCBiZSBwdWJsaXNoZWQgaGVyZSBmb3IgZG93bnN0cmVhbVxuICAgKiBwcm9jZXNzaW5nIGFuZCBkYXRhYmFzZSBpbnNlcnRpb24uXG4gICAqL1xuICByZWFkb25seSBpdGVtTG9hZFRvcGljQXJuOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQVdTIENESyBDb25zdHJ1Y3QgZm9yIFNUQUMgSXRlbSBHZW5lcmF0aW9uIEluZnJhc3RydWN0dXJlXG4gKlxuICogVGhlIFN0YWN0b29sc0l0ZW1HZW5lcmF0b3IgY3JlYXRlcyBhIHNlcnZlcmxlc3MsIGV2ZW50LWRyaXZlbiBzeXN0ZW0gZm9yIGdlbmVyYXRpbmdcbiAqIFNUQUMgKFNwYXRpb1RlbXBvcmFsIEFzc2V0IENhdGFsb2cpIGl0ZW1zIGZyb20gc291cmNlIGRhdGEuIFRoaXMgY29uc3RydWN0XG4gKiBpbXBsZW1lbnRzIHRoZSBmaXJzdCBwaGFzZSBvZiBhIHR3by1zdGFnZSBpbmdlc3Rpb24gcGlwZWxpbmUgdGhhdCB0cmFuc2Zvcm1zXG4gKiByYXcgZ2Vvc3BhdGlhbCBkYXRhIGludG8gc3RhbmRhcmRpemVkIFNUQUMgbWV0YWRhdGEuXG4gKlxuICogIyMgQXJjaGl0ZWN0dXJlIE92ZXJ2aWV3XG4gKlxuICogVGhpcyBjb25zdHJ1Y3QgY3JlYXRlcyB0aGUgZm9sbG93aW5nIEFXUyByZXNvdXJjZXM6XG4gKiAtICoqU05TIFRvcGljKio6IEVudHJ5IHBvaW50IGZvciB0cmlnZ2VyaW5nIGl0ZW0gZ2VuZXJhdGlvbiB3b3JrZmxvd3NcbiAqIC0gKipTUVMgUXVldWUqKjogQnVmZmVycyBnZW5lcmF0aW9uIHJlcXVlc3RzICgxMjAtc2Vjb25kIHZpc2liaWxpdHkgdGltZW91dClcbiAqIC0gKipEZWFkIExldHRlciBRdWV1ZSoqOiBDYXB0dXJlcyBmYWlsZWQgbWVzc2FnZXMgYWZ0ZXIgNSBwcm9jZXNzaW5nIGF0dGVtcHRzXG4gKiAtICoqTGFtYmRhIEZ1bmN0aW9uKio6IENvbnRhaW5lcml6ZWQgZnVuY3Rpb24gdGhhdCBnZW5lcmF0ZXMgU1RBQyBpdGVtcyB1c2luZyBzdGFjdG9vbHNcbiAqXG4gKiAjIyBEYXRhIEZsb3dcbiAqXG4gKiAxLiBFeHRlcm5hbCBzeXN0ZW1zIHB1Ymxpc2ggSXRlbVJlcXVlc3QgbWVzc2FnZXMgdG8gdGhlIFNOUyB0b3BpYyB3aXRoIG1ldGFkYXRhIGFib3V0IGFzc2V0c1xuICogMi4gVGhlIFNRUyBxdWV1ZSBidWZmZXJzIHRoZXNlIG1lc3NhZ2VzIGFuZCB0cmlnZ2VycyB0aGUgTGFtYmRhIGZ1bmN0aW9uXG4gKiAzLiBUaGUgTGFtYmRhIGZ1bmN0aW9uOlxuICogICAgLSBVc2VzIGB1dnhgIHRvIGluc3RhbGwgdGhlIHJlcXVpcmVkIHN0YWN0b29scyBwYWNrYWdlXG4gKiAgICAtIEV4ZWN1dGVzIHRoZSBgY3JlYXRlLWl0ZW1gIENMSSBjb21tYW5kIHdpdGggcHJvdmlkZWQgYXJndW1lbnRzXG4gKiAgICAtIFB1Ymxpc2hlcyBnZW5lcmF0ZWQgU1RBQyBpdGVtcyB0byB0aGUgSXRlbUxvYWQgdG9waWNcbiAqIDQuIEZhaWxlZCBwcm9jZXNzaW5nIGF0dGVtcHRzIGFyZSBzZW50IHRvIHRoZSBkZWFkIGxldHRlciBxdWV1ZVxuICpcbiAqICMjIE9wZXJhdGlvbmFsIENoYXJhY3RlcmlzdGljc1xuICpcbiAqIC0gKipTY2FsYWJpbGl0eSoqOiBMYW1iZGEgc2NhbGVzIGF1dG9tYXRpY2FsbHkgYmFzZWQgb24gcXVldWUgZGVwdGggKHVwIHRvIG1heENvbmN1cnJlbmN5KVxuICogLSAqKkZsZXhpYmlsaXR5Kio6IFN1cHBvcnRzIGFueSBzdGFjdG9vbHMgcGFja2FnZSB0aHJvdWdoIGR5bmFtaWMgaW5zdGFsbGF0aW9uXG4gKiAtICoqUmVsaWFiaWxpdHkqKjogRGVhZCBsZXR0ZXIgcXVldWUgY2FwdHVyZXMgZmFpbGVkIGdlbmVyYXRpb24gYXR0ZW1wdHNcbiAqIC0gKipJc29sYXRpb24qKjogRWFjaCBnZW5lcmF0aW9uIHRhc2sgcnVucyBpbiBhIGZyZXNoIGNvbnRhaW5lciBlbnZpcm9ubWVudFxuICogLSAqKk9ic2VydmFiaWxpdHkqKjogQ2xvdWRXYXRjaCBsb2dzIHJldGFpbmVkIGZvciBvbmUgd2Vla1xuICpcbiAqICMjIE1lc3NhZ2UgU2NoZW1hXG4gKlxuICogVGhlIGZ1bmN0aW9uIGV4cGVjdHMgbWVzc2FnZXMgbWF0Y2hpbmcgdGhlIEl0ZW1SZXF1ZXN0IG1vZGVsOlxuICpcbiAqIGBgYGpzb25cbiAqIHtcbiAqICAgXCJwYWNrYWdlX25hbWVcIjogXCJzdGFjdG9vbHMtZ2xhZC1nbG9iYWwtZm9yZXN0LWNoYW5nZVwiLFxuICogICBcImdyb3VwX25hbWVcIjogXCJnbGFkZ2xvYmFsZm9yZXN0Y2hhbmdlXCIsXG4gKiAgIFwiY3JlYXRlX2l0ZW1fYXJnc1wiOiBbXG4gKiAgICAgXCJodHRwczovL2V4YW1wbGUuY29tL2RhdGEudGlmXCJcbiAqICAgXSxcbiAqICAgXCJjb2xsZWN0aW9uX2lkXCI6IFwiZ2xhZC1nbG9iYWwtZm9yZXN0LWNoYW5nZS0xLjExXCJcbiAqIH1cbiAqIGBgYFxuICpcbiAqICMjIFVzYWdlIEV4YW1wbGVcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBDcmVhdGUgaXRlbSBsb2FkZXIgZmlyc3QgKG9yIGdldCBleGlzdGluZyB0b3BpYyBBUk4pXG4gKiBjb25zdCBsb2FkZXIgPSBuZXcgU3RhY0l0ZW1Mb2FkZXIodGhpcywgJ0l0ZW1Mb2FkZXInLCB7XG4gKiAgIHBnc3RhY0RiOiBkYXRhYmFzZVxuICogfSk7XG4gKlxuICogLy8gQ3JlYXRlIGl0ZW0gZ2VuZXJhdG9yIHRoYXQgZmVlZHMgdGhlIGxvYWRlclxuICogY29uc3QgZ2VuZXJhdG9yID0gbmV3IFN0YWN0b29sc0l0ZW1HZW5lcmF0b3IodGhpcywgJ0l0ZW1HZW5lcmF0b3InLCB7XG4gKiAgIGl0ZW1Mb2FkVG9waWNBcm46IGxvYWRlci50b3BpYy50b3BpY0FybixcbiAqICAgbGFtYmRhVGltZW91dFNlY29uZHM6IDEyMCwgICAgLy8gQWxsb3cgdGltZSBmb3IgcGFja2FnZSBpbnN0YWxsYXRpb25cbiAqICAgbWF4Q29uY3VycmVuY3k6IDEwMCwgICAgICAgICAgLy8gQ29udHJvbCBwYXJhbGxlbCBwcm9jZXNzaW5nXG4gKiAgIGJhdGNoU2l6ZTogMTAgICAgICAgICAgICAgICAgIC8vIFByb2Nlc3MgMTAgcmVxdWVzdHMgcGVyIGludm9jYXRpb25cbiAqIH0pO1xuICpcbiAqIC8vIEdyYW50IHBlcm1pc3Npb24gdG8gcHVibGlzaCB0byB0aGUgbG9hZGVyIHRvcGljXG4gKiBsb2FkZXIudG9waWMuZ3JhbnRQdWJsaXNoKGdlbmVyYXRvci5sYW1iZGFGdW5jdGlvbik7XG4gKiBgYGBcbiAqXG4gKiAjIyBQdWJsaXNoaW5nIEdlbmVyYXRpb24gUmVxdWVzdHNcbiAqXG4gKiBTZW5kIG1lc3NhZ2VzIHRvIHRoZSBnZW5lcmF0b3IgdG9waWMgdG8gdHJpZ2dlciBpdGVtIGNyZWF0aW9uOlxuICpcbiAqIGBgYGJhc2hcbiAqIGF3cyBzbnMgcHVibGlzaCAtLXRvcGljLWFybiAkSVRFTV9HRU5fVE9QSUMgLS1tZXNzYWdlICd7XG4gKiAgIFwicGFja2FnZV9uYW1lXCI6IFwic3RhY3Rvb2xzLWdsYWQtZ2xvYmFsLWZvcmVzdC1jaGFuZ2VcIixcbiAqICAgXCJncm91cF9uYW1lXCI6IFwiZ2xhZGdsb2JhbGZvcmVzdGNoYW5nZVwiLFxuICogICBcImNyZWF0ZV9pdGVtX2FyZ3NcIjogW1xuICogICAgIFwiaHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL2VhcnRoZW5naW5lcGFydG5lcnMtaGFuc2VuL0dGQy0yMDIzLXYxLjExL0hhbnNlbl9HRkMtMjAyMy12MS4xMV9nYWluXzQwTl8wODBXLnRpZlwiXG4gKiAgIF0sXG4gKiAgIFwiY29sbGVjdGlvbl9pZFwiOiBcImdsYWQtZ2xvYmFsLWZvcmVzdC1jaGFuZ2UtMS4xMVwiXG4gKiB9J1xuICogYGBgXG4gKlxuICogIyMgQmF0Y2ggUHJvY2Vzc2luZyBFeGFtcGxlXG4gKlxuICogRm9yIHByb2Nlc3NpbmcgbWFueSBhc3NldHMsIHlvdSBjYW4gbG9vcCB0aHJvdWdoIFVSTHM6XG4gKlxuICogYGBgYmFzaFxuICogd2hpbGUgSUZTPSByZWFkIC1yIHVybDsgZG9cbiAqICAgYXdzIHNucyBwdWJsaXNoIC0tdG9waWMtYXJuIFwiJElURU1fR0VOX1RPUElDXCIgLS1tZXNzYWdlIFwie1xuICogICAgIFxcXCJwYWNrYWdlX25hbWVcXFwiOiBcXFwic3RhY3Rvb2xzLWdsYWQtZ2xjbHUyMDIwXFxcIixcbiAqICAgICBcXFwiZ3JvdXBfbmFtZVxcXCI6IFxcXCJnbGFkZ2xjbHUyMDIwXFxcIixcbiAqICAgICBcXFwiY3JlYXRlX2l0ZW1fYXJnc1xcXCI6IFtcXFwiJHVybFxcXCJdXG4gKiAgIH1cIlxuICogZG9uZSA8IHVybHMudHh0XG4gKiBgYGBcbiAqXG4gKiAjIyBNb25pdG9yaW5nIGFuZCBUcm91Ymxlc2hvb3RpbmdcbiAqXG4gKiAtIE1vbml0b3IgTGFtYmRhIGxvZ3M6IGAvYXdzL2xhbWJkYS97RnVuY3Rpb25OYW1lfWBcbiAqIC0gQ2hlY2sgZGVhZCBsZXR0ZXIgcXVldWUgZm9yIGZhaWxlZCBnZW5lcmF0aW9uIGF0dGVtcHRzXG4gKiAtIFVzZSBDbG91ZFdhdGNoIG1ldHJpY3MgdG8gdHJhY2sgcHJvY2Vzc2luZyByYXRlcyBhbmQgZXJyb3JzXG4gKiAtIEZhaWxlZCBpdGVtcyBjYW4gYmUgcmVwbGF5ZWQgZnJvbSB0aGUgZGVhZCBsZXR0ZXIgcXVldWVcbiAqXG4gKiAjIyBTdXBwb3J0ZWQgU3RhY3Rvb2xzIFBhY2thZ2VzXG4gKlxuICogQW55IHBhY2thZ2UgYXZhaWxhYmxlIG9uIFB5UEkgdGhhdCBmb2xsb3dzIHRoZSBzdGFjdG9vbHMgcGx1Z2luIHBhdHRlcm5cbiAqIGNhbiBiZSB1c2VkLiBFeGFtcGxlcyBpbmNsdWRlOlxuICogLSBgc3RhY3Rvb2xzLWdsYWQtZ2xvYmFsLWZvcmVzdC1jaGFuZ2VgXG4gKiAtIGBzdGFjdG9vbHMtZ2xhZC1nbGNsdTIwMjBgXG4gKiAtIGBzdGFjdG9vbHMtbGFuZHNhdGBcbiAqIC0gYHN0YWN0b29scy1zZW50aW5lbDJgXG4gKlxuICogQHNlZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3N0YWN0b29scy1wYWNrYWdlc30gZm9yIGF2YWlsYWJsZSBzdGFjdG9vbHMgcGFja2FnZXNcbiAqIEBzZWUge0BsaW5rIGh0dHBzOi8vc3RhY3Rvb2xzLnJlYWR0aGVkb2NzLmlvL30gZm9yIHN0YWN0b29scyBkb2N1bWVudGF0aW9uXG4gKi9cbmV4cG9ydCBjbGFzcyBTdGFjdG9vbHNJdGVtR2VuZXJhdG9yIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFRoZSBTUVMgcXVldWUgdGhhdCBidWZmZXJzIGl0ZW0gZ2VuZXJhdGlvbiByZXF1ZXN0cy5cbiAgICpcbiAgICogVGhpcyBxdWV1ZSByZWNlaXZlcyBtZXNzYWdlcyBmcm9tIHRoZSBTTlMgdG9waWMgY29udGFpbmluZyBJdGVtUmVxdWVzdFxuICAgKiBwYXlsb2Fkcy4gSXQncyBjb25maWd1cmVkIHdpdGggYSB2aXNpYmlsaXR5IHRpbWVvdXQgdGhhdCBtYXRjaGVzIHRoZVxuICAgKiBMYW1iZGEgdGltZW91dCBwbHVzIGJ1ZmZlciB0aW1lIHRvIHByZXZlbnQgZHVwbGljYXRlIHByb2Nlc3NpbmcuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcXVldWU6IHNxcy5RdWV1ZTtcblxuICAvKipcbiAgICogRGVhZCBsZXR0ZXIgcXVldWUgZm9yIGZhaWxlZCBpdGVtIGdlbmVyYXRpb24gYXR0ZW1wdHMuXG4gICAqXG4gICAqIE1lc3NhZ2VzIHRoYXQgZmFpbCBwcm9jZXNzaW5nIGFmdGVyIDUgYXR0ZW1wdHMgYXJlIHNlbnQgaGVyZSBmb3JcbiAgICogaW5zcGVjdGlvbiBhbmQgcG90ZW50aWFsIHJlcGxheS4gVGhpcyBoZWxwcyB3aXRoIGRlYnVnZ2luZyBzdGFjdG9vbHNcbiAgICogcGFja2FnZSBpc3N1ZXMsIG5ldHdvcmsgZmFpbHVyZXMsIG9yIG1hbGZvcm1lZCByZXF1ZXN0cy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBkZWFkTGV0dGVyUXVldWU6IHNxcy5RdWV1ZTtcblxuICAvKipcbiAgICogVGhlIFNOUyB0b3BpYyB0aGF0IHJlY2VpdmVzIGl0ZW0gZ2VuZXJhdGlvbiByZXF1ZXN0cy5cbiAgICpcbiAgICogRXh0ZXJuYWwgc3lzdGVtcyBwdWJsaXNoIEl0ZW1SZXF1ZXN0IG1lc3NhZ2VzIHRvIHRoaXMgdG9waWMgdG8gdHJpZ2dlclxuICAgKiBTVEFDIGl0ZW0gZ2VuZXJhdGlvbi4gVGhlIHRvcGljIGZhbnMgb3V0IHRvIHRoZSBTUVMgcXVldWUgZm9yIHByb2Nlc3NpbmcuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdG9waWM6IHNucy5Ub3BpYztcblxuICAvKipcbiAgICogVGhlIGNvbnRhaW5lcml6ZWQgTGFtYmRhIGZ1bmN0aW9uIHRoYXQgZ2VuZXJhdGVzIFNUQUMgaXRlbXMuXG4gICAqXG4gICAqIFRoaXMgRG9ja2VyLWJhc2VkIGZ1bmN0aW9uIGR5bmFtaWNhbGx5IGluc3RhbGxzIHN0YWN0b29scyBwYWNrYWdlc1xuICAgKiB1c2luZyB1dngsIHByb2Nlc3NlcyBzb3VyY2UgZGF0YSwgYW5kIHB1Ymxpc2hlcyBnZW5lcmF0ZWQgU1RBQyBpdGVtc1xuICAgKiB0byB0aGUgY29uZmlndXJlZCBJdGVtTG9hZCBTTlMgdG9waWMuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbGFtYmRhRnVuY3Rpb246IGxhbWJkYS5Eb2NrZXJJbWFnZUZ1bmN0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBTdGFjdG9vbHNJdGVtR2VuZXJhdG9yUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3QgdGltZW91dFNlY29uZHMgPSBwcm9wcy5sYW1iZGFUaW1lb3V0U2Vjb25kcyA/PyAxMjA7XG4gICAgY29uc3QgbGFtYmRhUnVudGltZSA9IHByb3BzLmxhbWJkYVJ1bnRpbWUgPz8gbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTE7XG5cbiAgICAvLyBDcmVhdGUgZGVhZCBsZXR0ZXIgcXVldWVcbiAgICB0aGlzLmRlYWRMZXR0ZXJRdWV1ZSA9IG5ldyBzcXMuUXVldWUodGhpcywgXCJEZWFkTGV0dGVyUXVldWVcIiwge1xuICAgICAgcmV0ZW50aW9uUGVyaW9kOiBEdXJhdGlvbi5kYXlzKDE0KSxcbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBtYWluIHF1ZXVlXG4gICAgdGhpcy5xdWV1ZSA9IG5ldyBzcXMuUXVldWUodGhpcywgXCJRdWV1ZVwiLCB7XG4gICAgICB2aXNpYmlsaXR5VGltZW91dDogRHVyYXRpb24uc2Vjb25kcyh0aW1lb3V0U2Vjb25kcyArIDEwKSxcbiAgICAgIGVuY3J5cHRpb246IHNxcy5RdWV1ZUVuY3J5cHRpb24uU1FTX01BTkFHRUQsXG4gICAgICBkZWFkTGV0dGVyUXVldWU6IHtcbiAgICAgICAgbWF4UmVjZWl2ZUNvdW50OiA1LFxuICAgICAgICBxdWV1ZTogdGhpcy5kZWFkTGV0dGVyUXVldWUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQ3JlYXRlIFNOUyB0b3BpY1xuICAgIHRoaXMudG9waWMgPSBuZXcgc25zLlRvcGljKHRoaXMsIFwiVG9waWNcIiwge1xuICAgICAgZGlzcGxheU5hbWU6IGAke2lkfS1JdGVtR2VuVG9waWNgLFxuICAgIH0pO1xuXG4gICAgLy8gU3Vic2NyaWJlIHRoZSBxdWV1ZSB0byB0aGUgdG9waWNcbiAgICB0aGlzLnRvcGljLmFkZFN1YnNjcmlwdGlvbihcbiAgICAgIG5ldyBzbnNTdWJzY3JpcHRpb25zLlNxc1N1YnNjcmlwdGlvbih0aGlzLnF1ZXVlKVxuICAgICk7XG5cbiAgICAvLyBDcmVhdGUgdGhlIGxhbWJkYSBmdW5jdGlvblxuICAgIHRoaXMubGFtYmRhRnVuY3Rpb24gPSBuZXcgbGFtYmRhLkRvY2tlckltYWdlRnVuY3Rpb24odGhpcywgXCJGdW5jdGlvblwiLCB7XG4gICAgICBjb2RlOiBsYW1iZGEuRG9ja2VySW1hZ2VDb2RlLmZyb21JbWFnZUFzc2V0KHBhdGguam9pbihfX2Rpcm5hbWUsIFwiLi5cIiksIHtcbiAgICAgICAgZmlsZTogXCJzdGFjdG9vbHMtaXRlbS1nZW5lcmF0b3IvcnVudGltZS9Eb2NrZXJmaWxlXCIsXG4gICAgICAgIHBsYXRmb3JtOiBQbGF0Zm9ybS5MSU5VWF9BTUQ2NCxcbiAgICAgICAgYnVpbGRBcmdzOiB7XG4gICAgICAgICAgUFlUSE9OX1ZFUlNJT046IGxhbWJkYVJ1bnRpbWUudG9TdHJpbmcoKS5yZXBsYWNlKFwicHl0aG9uXCIsIFwiXCIpLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBtZW1vcnlTaXplOiBwcm9wcy5tZW1vcnlTaXplID8/IDEwMjQsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKHRpbWVvdXRTZWNvbmRzKSxcbiAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9XRUVLLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgSVRFTV9MT0FEX1RPUElDX0FSTjogcHJvcHMuaXRlbUxvYWRUb3BpY0FybixcbiAgICAgICAgTE9HX0xFVkVMOiBcIklORk9cIixcbiAgICAgICAgLi4ucHJvcHMuZW52aXJvbm1lbnQsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gQWRkIFNRUyBldmVudCBzb3VyY2UgdG8gdGhlIGxhbWJkYVxuICAgIHRoaXMubGFtYmRhRnVuY3Rpb24uYWRkRXZlbnRTb3VyY2UoXG4gICAgICBuZXcgbGFtYmRhRXZlbnRTb3VyY2VzLlNxc0V2ZW50U291cmNlKHRoaXMucXVldWUsIHtcbiAgICAgICAgYmF0Y2hTaXplOiBwcm9wcy5iYXRjaFNpemUgPz8gMTAsXG4gICAgICAgIHJlcG9ydEJhdGNoSXRlbUZhaWx1cmVzOiB0cnVlLFxuICAgICAgICBtYXhDb25jdXJyZW5jeTogcHJvcHMubWF4Q29uY3VycmVuY3kgPz8gMTAwLFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgLy8gR3JhbnQgcGVybWlzc2lvbnMgdG8gcHVibGlzaCB0byB0aGUgaXRlbSBsb2FkIHRvcGljXG4gICAgLy8gTm90ZTogVGhpcyB3aWxsIGJlIGdyYW50ZWQgZXh0ZXJuYWxseSBzaW5jZSB3ZSBvbmx5IGhhdmUgdGhlIEFSTlxuICAgIC8vIFRoZSBjb25zdW1pbmcgY29uc3RydWN0IHNob3VsZCBoYW5kbGUgdGhpcyBwZXJtaXNzaW9uXG5cbiAgICAvLyBDcmVhdGUgb3V0cHV0c1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJUb3BpY0FyblwiLCB7XG4gICAgICB2YWx1ZTogdGhpcy50b3BpYy50b3BpY0FybixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkFSTiBvZiB0aGUgU3RhY3Rvb2xzSXRlbUdlbmVyYXRvciBTTlMgVG9waWNcIixcbiAgICAgIGV4cG9ydE5hbWU6IFwic3RhY3Rvb2xzLWl0ZW0tZ2VuZXJhdG9yLXRvcGljLWFyblwiLFxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBcIlF1ZXVlVXJsXCIsIHtcbiAgICAgIHZhbHVlOiB0aGlzLnF1ZXVlLnF1ZXVlVXJsLFxuICAgICAgZGVzY3JpcHRpb246IFwiVVJMIG9mIHRoZSBTdGFjdG9vbHNJdGVtR2VuZXJhdG9yIFNRUyBRdWV1ZVwiLFxuICAgICAgZXhwb3J0TmFtZTogXCJzdGFjdG9vbHMtaXRlbS1nZW5lcmF0b3ItcXVldWUtdXJsXCIsXG4gICAgfSk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwiRGVhZExldHRlclF1ZXVlVXJsXCIsIHtcbiAgICAgIHZhbHVlOiB0aGlzLmRlYWRMZXR0ZXJRdWV1ZS5xdWV1ZVVybCxcbiAgICAgIGRlc2NyaXB0aW9uOiBcIlVSTCBvZiB0aGUgU3RhY3Rvb2xzSXRlbUdlbmVyYXRvciBEZWFkIExldHRlciBRdWV1ZVwiLFxuICAgICAgZXhwb3J0TmFtZTogXCJzdGFjdG9vbHMtaXRlbS1nZW5lcmF0b3ItZGVhZGxldHRlci1xdWV1ZS11cmxcIixcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJGdW5jdGlvbk5hbWVcIiwge1xuICAgICAgdmFsdWU6IHRoaXMubGFtYmRhRnVuY3Rpb24uZnVuY3Rpb25OYW1lLFxuICAgICAgZGVzY3JpcHRpb246IFwiTmFtZSBvZiB0aGUgU3RhY3Rvb2xzSXRlbUdlbmVyYXRvciBMYW1iZGEgRnVuY3Rpb25cIixcbiAgICAgIGV4cG9ydE5hbWU6IFwic3RhY3Rvb2xzLWl0ZW0tZ2VuZXJhdG9yLWZ1bmN0aW9uLW5hbWVcIixcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,20 @@
1
+ ARG PYTHON_VERSION=3.11
2
+ FROM public.ecr.aws/lambda/python:${PYTHON_VERSION}
3
+ COPY --from=ghcr.io/astral-sh/uv:0.7.8 /uv /uvx /bin/
4
+
5
+ ENV UV_CACHE_DIR=/tmp/uv-cache/
6
+ ENV UV_COMPILE_BYTECODE=1
7
+ ENV PYTHONUNBUFFERED=1
8
+ ENV HOME=/tmp
9
+ ENV PATH=/tmp/.local/bin:$PATH
10
+
11
+ WORKDIR ${LAMBDA_TASK_ROOT}
12
+
13
+ COPY stactools-item-generator/runtime/pyproject.toml pyproject.toml
14
+ COPY stactools-item-generator/runtime/src/stactools_item_generator/ ${LAMBDA_TASK_ROOT}/stactools_item_generator/
15
+
16
+ RUN uv export --no-dev --no-editable -o requirements.txt && \
17
+ uv pip install --target ${LAMBDA_TASK_ROOT} -r requirements.txt && \
18
+ uv tool install --with requests stactools;
19
+
20
+ CMD ["stactools_item_generator.handler.handler"]
@@ -0,0 +1,16 @@
1
+ [project]
2
+ name = "stactools-item-generator"
3
+ version = "0.1.0"
4
+ description = "An application for generating STAC metadata with any stactools package"
5
+ authors = [
6
+ { name = "hrodmn", email = "henry@developmentseed.org" }
7
+ ]
8
+ requires-python = ">=3.11"
9
+ dependencies = [
10
+ "pydantic>=2.11.0",
11
+ "stac-pydantic>=3.2.0",
12
+ ]
13
+
14
+ [build-system]
15
+ requires = ["hatchling"]
16
+ build-backend = "hatchling.build"
@@ -0,0 +1,2 @@
1
+ def main() -> None:
2
+ print("Hello from stactools-uvx!")
@@ -0,0 +1,176 @@
1
+ """AWS Lambda handler for STAC Item Generation."""
2
+
3
+ import json
4
+ import logging
5
+ import os
6
+ import subprocess
7
+ import traceback
8
+ from typing import TYPE_CHECKING, Annotated, Any, Dict, List, Optional, TypedDict
9
+
10
+ import boto3
11
+ from pydantic import ValidationError
12
+
13
+ if TYPE_CHECKING:
14
+ from aws_lambda_typing.context import Context
15
+ else:
16
+ Context = Annotated[object, "Context object"]
17
+
18
+ from stactools_item_generator.item import ItemRequest, create_stac_item
19
+
20
+ logger = logging.getLogger()
21
+ if logger.hasHandlers():
22
+ logger.handlers.clear()
23
+
24
+ log_handler = logging.StreamHandler() # <--- Renamed handler variable
25
+
26
+ log_level_name = os.environ.get("LOG_LEVEL", "INFO").upper()
27
+ log_level = logging._nameToLevel.get(log_level_name, logging.INFO)
28
+ logger.setLevel(log_level)
29
+
30
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
31
+ log_handler.setFormatter(formatter)
32
+ logger.addHandler(log_handler)
33
+
34
+
35
+ def get_topic_arn() -> str:
36
+ item_load_topic_arn = os.environ.get("ITEM_LOAD_TOPIC_ARN")
37
+ if not item_load_topic_arn:
38
+ logger.error("Environment variable ITEM_LOAD_TOPIC_ARN is not set.")
39
+ raise EnvironmentError("ITEM_LOAD_TOPIC_ARN must be set")
40
+
41
+ return item_load_topic_arn
42
+
43
+
44
+ def process_record(record: Dict[str, Any], sns_client) -> None:
45
+ """
46
+ Processes a single SQS record (within a batch).
47
+ Extracts the request, calls create_stac_item, and publishes the result.
48
+ Raises exceptions on failure.
49
+ """
50
+ message_id = record.get("messageId", "UNKNOWN_ID")
51
+ logger.info(f"Processing record: {message_id}")
52
+ message_str = None
53
+ try:
54
+ sqs_body_str = record["body"]
55
+ logger.debug(f"[{message_id}] SQS message body: {sqs_body_str}")
56
+ sns_notification = json.loads(sqs_body_str)
57
+
58
+ message_str = sns_notification["Message"]
59
+ logger.debug(f"[{message_id}] SNS Message content: {message_str}")
60
+
61
+ message_data = json.loads(message_str)
62
+ item_request = ItemRequest(**message_data)
63
+ logger.info(
64
+ f"[{message_id}] Parsed ItemRequest for package: {item_request.package_name}"
65
+ )
66
+ logger.debug(f"[{message_id}] Full ItemRequest: {item_request.model_dump_json()}")
67
+
68
+ stac_item = create_stac_item(item_request)
69
+ logger.info(f"[{message_id}] Successfully created STAC item: {stac_item.id}")
70
+ logger.debug(
71
+ f"[{message_id}] Generated STAC Item JSON (sample): "
72
+ f"{ {k: v for k, v in stac_item.model_dump().items() if k in ['id', 'collection', 'properties']} }"
73
+ )
74
+
75
+ stac_item_json = stac_item.model_dump_json()
76
+
77
+ item_load_topic_arn = get_topic_arn()
78
+ logger.info(
79
+ f"[{message_id}] Publishing STAC item {stac_item.id} to {item_load_topic_arn}"
80
+ )
81
+ response = sns_client.publish(
82
+ TopicArn=item_load_topic_arn,
83
+ Message=stac_item_json,
84
+ )
85
+ logger.info(
86
+ f"[{message_id}] SNS publish response MessageId: {response.get('MessageId')}"
87
+ )
88
+
89
+ except json.JSONDecodeError as e:
90
+ logger.error(f"[{message_id}] Failed to decode JSON: {e}")
91
+ logger.error(f"[{message_id}] Problematic data (SQS Body): {record.get('body')}")
92
+ raise
93
+ except ValidationError as e:
94
+ logger.error(f"[{message_id}] Failed to validate ItemRequest: {e}")
95
+ logger.error(f"[{message_id}] Validation errors:\n{e.errors()}")
96
+ problem_data = message_str if message_str is not None else record.get("body")
97
+ logger.error(
98
+ f"[{message_id}] Problematic data (SNS Message or SQS Body): {problem_data}"
99
+ )
100
+ raise
101
+ except (
102
+ subprocess.CalledProcessError
103
+ ) as e: # <--- Catching the imported exception type
104
+ logger.error(f"[{message_id}] Subprocess command failed:")
105
+ logger.error(f"[{message_id}] Command: {' '.join(e.cmd)}")
106
+ logger.error(f"[{message_id}] Return code: {e.returncode}")
107
+ logger.error(f"[{message_id}] Stdout: {e.stdout}")
108
+ logger.error(f"[{message_id}] Stderr: {e.stderr}")
109
+ raise
110
+ except Exception as e:
111
+ logger.error(
112
+ f"[{message_id}] An unexpected error occurred processing record: {e}"
113
+ )
114
+ logger.error(traceback.format_exc())
115
+ raise
116
+
117
+
118
+ class BatchItemFailure(TypedDict):
119
+ itemIdentifier: str
120
+
121
+
122
+ class PartialBatchFailureResponse(TypedDict):
123
+ batchItemFailures: List[BatchItemFailure]
124
+
125
+
126
+ def handler(
127
+ event: Dict[str, Any], context: Context
128
+ ) -> Optional[PartialBatchFailureResponse]:
129
+ """
130
+ AWS Lambda handler function triggered by SQS with batching enabled.
131
+
132
+ Processes messages in batches, attempts to generate STAC items, publishes
133
+ successful results to SNS, and reports partial batch failures to SQS.
134
+ """
135
+ try:
136
+ sns_client = boto3.client("sns", region_name=os.getenv("AWS_DEFAULT_REGION"))
137
+ except Exception as e:
138
+ logging.error(f"Error: {str(e)}")
139
+ raise EnvironmentError("AWS_DEFAULT_REGION must be set") from e
140
+
141
+ records = event.get("Records", [])
142
+ aws_request_id = getattr(context, "aws_request_id", "N/A")
143
+ remaining_time = getattr(context, "get_remaining_time_in_millis", lambda: "N/A")()
144
+
145
+ logger.info(f"Received batch with {len(records)} records.")
146
+ logger.debug(
147
+ f"Lambda Context: RequestId={aws_request_id}, RemainingTime={remaining_time}ms"
148
+ )
149
+
150
+ batch_item_failures: List[BatchItemFailure] = []
151
+
152
+ for record in records:
153
+ message_id = record.get("messageId")
154
+ if not message_id:
155
+ logger.warning("Record missing messageId, cannot report failure for it.")
156
+ continue
157
+
158
+ try:
159
+ process_record(record, sns_client)
160
+ logger.info(f"[{message_id}] Successfully processed.")
161
+
162
+ except Exception:
163
+ logger.error(f"[{message_id}] Marked as failed.")
164
+ batch_item_failures.append({"itemIdentifier": message_id})
165
+
166
+ if batch_item_failures:
167
+ logger.warning(
168
+ f"Finished processing batch. {len(batch_item_failures)} failure(s) reported."
169
+ )
170
+ logger.info(
171
+ f"Returning failed item identifiers: {[f['itemIdentifier'] for f in batch_item_failures]}"
172
+ )
173
+ return {"batchItemFailures": batch_item_failures}
174
+ else:
175
+ logger.info("Finished processing batch. All records successful.")
176
+ return None
@@ -0,0 +1,77 @@
1
+ import json
2
+ import logging
3
+ import subprocess
4
+ from tempfile import NamedTemporaryFile
5
+ from typing import Dict, List, Optional
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+ from stac_pydantic.item import Item
9
+
10
+ logger = logging.getLogger()
11
+ logger.setLevel(logging.INFO)
12
+
13
+
14
+ class ItemRequest(BaseModel):
15
+ package_name: str = Field(..., description="Name of the stactools package")
16
+ group_name: str = Field(..., description="Group name for the STAC item")
17
+ create_item_args: List[str] = Field(
18
+ ..., description="Arguments for create-item command"
19
+ )
20
+ create_item_options: Dict[str, str] = Field(
21
+ default_factory=dict, description="Options for create-item command"
22
+ )
23
+ collection_id: Optional[str] = Field(
24
+ None, description="value for the collection field of the item json"
25
+ )
26
+
27
+ model_config = ConfigDict(
28
+ json_schema_extra={
29
+ "example": {
30
+ "package_name": "stactools-glad-glclu2020",
31
+ "group_name": "gladglclu2020",
32
+ "create_item_args": [
33
+ "https://storage.googleapis.com/earthenginepartners-hansen/GLCLU2000-2020/v2/2000/50N_090W.tif"
34
+ ],
35
+ }
36
+ }
37
+ )
38
+
39
+
40
+ def create_stac_item(request: ItemRequest) -> Item:
41
+ """
42
+ Create a STAC item using a stactools package
43
+ """
44
+ logger.info(f"Received request: {json.dumps(request.model_dump())}")
45
+
46
+ if not request.package_name:
47
+ raise ValueError("Missing required parameter: package_name")
48
+
49
+ command = [
50
+ "uvx",
51
+ "--with",
52
+ f"requests,{request.package_name}",
53
+ "--from",
54
+ "stactools",
55
+ "stac",
56
+ request.group_name,
57
+ "create-item",
58
+ *request.create_item_args,
59
+ ]
60
+
61
+ for option, value in request.create_item_options.items():
62
+ command.extend([f"--{option}", value])
63
+
64
+ logger.info(f"Executing command: {' '.join(command)}")
65
+
66
+ with NamedTemporaryFile(suffix=".json") as output:
67
+ command.append(output.name)
68
+ result = subprocess.run(command, capture_output=True, text=True, check=True)
69
+
70
+ logger.info(f"Command output: {result.stdout}")
71
+ with open(output.name) as f:
72
+ item_dict = json.load(f)
73
+
74
+ if request.collection_id:
75
+ item_dict["collection"] = request.collection_id
76
+
77
+ return Item(**item_dict)
@@ -57,5 +57,5 @@ class TiPgApiLambda extends constructs_1.Construct {
57
57
  }
58
58
  exports.TiPgApiLambda = TiPgApiLambda;
59
59
  _a = JSII_RTTI_SYMBOL_1;
60
- TiPgApiLambda[_a] = { fqn: "eoapi-cdk.TiPgApiLambda", version: "8.1.1" };
60
+ TiPgApiLambda[_a] = { fqn: "eoapi-cdk.TiPgApiLambda", version: "8.2.0" };
61
61
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVdxQjtBQUNyQiwyQ0FBdUM7QUFFdkMsNkJBQTZCO0FBRTNCLE1BQWEsYUFBYyxTQUFRLHNCQUFTO0lBSTFDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBeUI7UUFDakUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSx3QkFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFO1lBQzVELFdBQVc7WUFDWCxPQUFPLEVBQUUsd0JBQU0sQ0FBQyxPQUFPLENBQUMsV0FBVztZQUNuQyxPQUFPLEVBQUUsaUJBQWlCO1lBQzFCLFVBQVUsRUFBRSxJQUFJO1lBQ2hCLFlBQVksRUFBRSxzQkFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRO1lBQ3pDLE9BQU8sRUFBRSxzQkFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDN0IsSUFBSSxFQUFFLHdCQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsRUFBRTtnQkFDNUQsSUFBSSxFQUFFLDZCQUE2QjtnQkFDbkMsU0FBUyxFQUFFLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRTthQUN0QyxDQUFDO1lBQ0YsR0FBRyxFQUFFLEtBQUssQ0FBQyxHQUFHO1lBQ2QsVUFBVSxFQUFFLEtBQUssQ0FBQyxlQUFlO1lBQ2pDLGlCQUFpQixFQUFFLElBQUk7WUFDdkIsV0FBVyxFQUFFO2dCQUNYLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBUztnQkFDM0MsZ0JBQWdCLEVBQUUsR0FBRztnQkFDckIsZ0JBQWdCLEVBQUUsR0FBRztnQkFDckIsR0FBRyxLQUFLLENBQUMsTUFBTTthQUNoQjtZQUNELGlFQUFpRTtZQUNqRSxHQUFHLEtBQUssQ0FBQyxxQkFBcUI7U0FDL0IsQ0FBQyxDQUFDO1FBRUgsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFFbEQsSUFBSSxLQUFLLENBQUMsR0FBRyxFQUFDLENBQUM7WUFDYixJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLHFCQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSw2QkFBNkIsQ0FBQyxDQUFDO1FBQzNHLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLDhCQUFZLENBQUMsT0FBTyxDQUN0QyxJQUFJLEVBQ0osR0FBRyxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxTQUFTLFdBQVcsRUFDdEM7WUFDRSxvQkFBb0IsRUFBRSxLQUFLLENBQUMsaUJBQWlCO2dCQUMzQyxDQUFDLENBQUM7b0JBQ0UsVUFBVSxFQUFFLEtBQUssQ0FBQyxpQkFBaUI7aUJBQ3BDO2dCQUNILENBQUMsQ0FBQyxTQUFTO1lBQ2Isa0JBQWtCLEVBQ2hCLElBQUksMkNBQXlCLENBQUMscUJBQXFCLENBQ2pELGFBQWEsRUFDYixJQUFJLENBQUMsa0JBQWtCLEVBQ3ZCLEtBQUssQ0FBQyxpQkFBaUI7Z0JBQ3JCLENBQUMsQ0FBQztvQkFDRSxnQkFBZ0IsRUFDZCxJQUFJLDhCQUFZLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxlQUFlLENBQ2pELE1BQU0sRUFDTiw4QkFBWSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQzlCLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQzdCLENBQ0Y7aUJBQ0o7Z0JBQ0gsQ0FBQyxDQUFDLFNBQVMsQ0FDZDtTQUNKLENBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUksQ0FBQztRQUV4QixJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLGlCQUFpQixFQUFFO1lBQ3JDLFVBQVUsRUFBRSxHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsVUFBVTtZQUNqRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEdBQUc7U0FDaEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUF2RUgsc0NBd0VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgU3RhY2ssXG4gIGF3c19hcGlnYXRld2F5djIgYXMgYXBpZ2F0ZXdheXYyLFxuICBhd3NfYXBpZ2F0ZXdheXYyX2ludGVncmF0aW9ucyBhcyBhcGlnYXRld2F5djJfaW50ZWdyYXRpb25zLFxuICBhd3NfZWMyIGFzIGVjMixcbiAgYXdzX2xhbWJkYSBhcyBsYW1iZGEsXG4gIGF3c19sb2dzIGFzIGxvZ3MsXG4gIGF3c19yZHMgYXMgcmRzLFxuICBhd3Nfc2VjcmV0c21hbmFnZXIgYXMgc2VjcmV0c21hbmFnZXIsXG4gIENmbk91dHB1dCxcbiAgRHVyYXRpb24sXG59IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IEN1c3RvbUxhbWJkYUZ1bmN0aW9uUHJvcHMgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbiAgZXhwb3J0IGNsYXNzIFRpUGdBcGlMYW1iZGEgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAgIHJlYWRvbmx5IHVybDogc3RyaW5nO1xuICAgIHB1YmxpYyB0aVBnTGFtYmRhRnVuY3Rpb246IGxhbWJkYS5GdW5jdGlvbjtcblxuICAgIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBUaVBnQXBpTGFtYmRhUHJvcHMpIHtcbiAgICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICAgIHRoaXMudGlQZ0xhbWJkYUZ1bmN0aW9uID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCBcImxhbWJkYVwiLCB7XG4gICAgICAgIC8vIGRlZmF1bHRzXG4gICAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzExLFxuICAgICAgICBoYW5kbGVyOiBcImhhbmRsZXIuaGFuZGxlclwiLFxuICAgICAgICBtZW1vcnlTaXplOiAxMDI0LFxuICAgICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfV0VFSyxcbiAgICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Eb2NrZXJCdWlsZChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nKSwge1xuICAgICAgICAgIGZpbGU6IFwidGlwZy1hcGkvcnVudGltZS9Eb2NrZXJmaWxlXCIsXG4gICAgICAgICAgYnVpbGRBcmdzOiB7IFBZVEhPTl9WRVJTSU9OOiAnMy4xMScgfSxcbiAgICAgICAgfSksXG4gICAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgICB2cGNTdWJuZXRzOiBwcm9wcy5zdWJuZXRTZWxlY3Rpb24sXG4gICAgICAgIGFsbG93UHVibGljU3VibmV0OiB0cnVlLFxuICAgICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICAgIFBHU1RBQ19TRUNSRVRfQVJOOiBwcm9wcy5kYlNlY3JldC5zZWNyZXRBcm4sXG4gICAgICAgICAgREJfTUlOX0NPTk5fU0laRTogXCIxXCIsXG4gICAgICAgICAgREJfTUFYX0NPTk5fU0laRTogXCIxXCIsXG4gICAgICAgICAgLi4ucHJvcHMuYXBpRW52LFxuICAgICAgICB9LFxuICAgICAgICAvLyBvdmVyd3JpdGVzIGRlZmF1bHRzIHdpdGggdXNlci1wcm92aWRlZCBjb25maWd1cmFibGUgcHJvcGVydGllc1xuICAgICAgICAuLi5wcm9wcy5sYW1iZGFGdW5jdGlvbk9wdGlvbnNcbiAgICAgIH0pO1xuXG4gICAgICBwcm9wcy5kYlNlY3JldC5ncmFudFJlYWQodGhpcy50aVBnTGFtYmRhRnVuY3Rpb24pO1xuXG4gICAgICBpZiAocHJvcHMudnBjKXtcbiAgICAgICAgdGhpcy50aVBnTGFtYmRhRnVuY3Rpb24uY29ubmVjdGlvbnMuYWxsb3dUbyhwcm9wcy5kYiwgZWMyLlBvcnQudGNwKDU0MzIpLCBcImFsbG93IGNvbm5lY3Rpb25zIGZyb20gdGlwZ1wiKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdGlwZ0FwaSA9IG5ldyBhcGlnYXRld2F5djIuSHR0cEFwaShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS10aXBnLWFwaWAsXG4gICAgICAgIHtcbiAgICAgICAgICBkZWZhdWx0RG9tYWluTWFwcGluZzogcHJvcHMudGlwZ0FwaURvbWFpbk5hbWVcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIGRvbWFpbk5hbWU6IHByb3BzLnRpcGdBcGlEb21haW5OYW1lLFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICBkZWZhdWx0SW50ZWdyYXRpb246XG4gICAgICAgICAgICBuZXcgYXBpZ2F0ZXdheXYyX2ludGVncmF0aW9ucy5IdHRwTGFtYmRhSW50ZWdyYXRpb24oXG4gICAgICAgICAgICAgIFwiaW50ZWdyYXRpb25cIixcbiAgICAgICAgICAgICAgdGhpcy50aVBnTGFtYmRhRnVuY3Rpb24sXG4gICAgICAgICAgICAgIHByb3BzLnRpcGdBcGlEb21haW5OYW1lXG4gICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlck1hcHBpbmc6XG4gICAgICAgICAgICAgICAgICAgICAgbmV3IGFwaWdhdGV3YXl2Mi5QYXJhbWV0ZXJNYXBwaW5nKCkub3ZlcndyaXRlSGVhZGVyKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJob3N0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBhcGlnYXRld2F5djIuTWFwcGluZ1ZhbHVlLmN1c3RvbShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcHMudGlwZ0FwaURvbWFpbk5hbWUubmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgICAgICksXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIHRoaXMudXJsID0gdGlwZ0FwaS51cmwhO1xuXG4gICAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwidGlwZy1hcGktb3V0cHV0XCIsIHtcbiAgICAgICAgZXhwb3J0TmFtZTogYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS10aXAtdXJsYCxcbiAgICAgICAgdmFsdWU6IHRoaXMudXJsLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgZXhwb3J0IGludGVyZmFjZSBUaVBnQXBpTGFtYmRhUHJvcHMge1xuICAgIC8qKlxuICAgICAqIFZQQyBpbnRvIHdoaWNoIHRoZSBsYW1iZGEgc2hvdWxkIGJlIGRlcGxveWVkLlxuICAgICAqL1xuICAgIHJlYWRvbmx5IHZwYz86IGVjMi5JVnBjO1xuXG4gICAgLyoqXG4gICAgICogUkRTIEluc3RhbmNlIHdpdGggaW5zdGFsbGVkIHBnU1RBQyBvciBwZ2JvdW5jZXIgc2VydmVyLlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGRiOiByZHMuSURhdGFiYXNlSW5zdGFuY2UgfCBlYzIuSUluc3RhbmNlO1xuXG4gICAgLyoqXG4gICAgICogU3VibmV0IGludG8gd2hpY2ggdGhlIGxhbWJkYSBzaG91bGQgYmUgZGVwbG95ZWQuXG4gICAgICovXG4gICAgcmVhZG9ubHkgc3VibmV0U2VsZWN0aW9uPzogZWMyLlN1Ym5ldFNlbGVjdGlvbjtcblxuICAgIC8qKlxuICAgICAqIFNlY3JldCBjb250YWluaW5nIGNvbm5lY3Rpb24gaW5mb3JtYXRpb24gZm9yIHBnU1RBQyBkYXRhYmFzZS5cbiAgICAgKi9cbiAgICByZWFkb25seSBkYlNlY3JldDogc2VjcmV0c21hbmFnZXIuSVNlY3JldDtcblxuICAgIC8qKlxuICAgICAqIEN1c3RvbWl6ZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIHNlbmQgdG8gdGl0aWxlci1wZ3N0YWMgcnVudGltZS5cbiAgICAgKi9cbiAgICByZWFkb25seSBhcGlFbnY/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuXG4gICAgLyoqXG4gICAgICogQ3VzdG9tIERvbWFpbiBOYW1lIGZvciB0aXBnIEFQSS4gSWYgZGVmaW5lZCwgd2lsbCBjcmVhdGUgdGhlXG4gICAgICogZG9tYWluIG5hbWUgYW5kIGludGVncmF0ZSBpdCB3aXRoIHRoZSB0aXBnIEFQSS5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IC0gdW5kZWZpbmVkXG4gICAgICovXG4gICAgcmVhZG9ubHkgdGlwZ0FwaURvbWFpbk5hbWU/OiBhcGlnYXRld2F5djIuSURvbWFpbk5hbWU7XG5cbiAgICAvKipcbiAgICAgKiBDYW4gYmUgdXNlZCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBsYW1iZGEgZnVuY3Rpb24gcHJvcGVydGllcy5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IC0gZGVmaW5lZCBpbiB0aGUgY29uc3RydWN0LlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGxhbWJkYUZ1bmN0aW9uT3B0aW9ucz86IEN1c3RvbUxhbWJkYUZ1bmN0aW9uUHJvcHM7XG4gIH1cbiJdfQ==
@@ -77,5 +77,5 @@ class TitilerPgstacApiLambda extends constructs_1.Construct {
77
77
  }
78
78
  exports.TitilerPgstacApiLambda = TitilerPgstacApiLambda;
79
79
  _a = JSII_RTTI_SYMBOL_1;
80
- TitilerPgstacApiLambda[_a] = { fqn: "eoapi-cdk.TitilerPgstacApiLambda", version: "8.1.1" };
80
+ TitilerPgstacApiLambda[_a] = { fqn: "eoapi-cdk.TitilerPgstacApiLambda", version: "8.2.0" };
81
81
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQVlxQjtBQUNyQiwyQ0FBdUM7QUFFdkMsNkJBQTZCO0FBRTNCLDRFQUE0RTtBQUM1RSxJQUFJLHVCQUF1QixHQUEyQjtJQUNwRCxrQ0FBa0MsRUFBRSxpQkFBaUI7SUFDckQsZUFBZSxFQUFFLEtBQUs7SUFDdEIsOEJBQThCLEVBQUUsV0FBVztJQUMzQyw2QkFBNkIsRUFBRSxPQUFPO0lBQ3RDLG9DQUFvQyxFQUFFLEtBQUs7SUFDM0MscUJBQXFCLEVBQUUsS0FBSztJQUM1QixtQkFBbUIsRUFBRSxHQUFHO0lBQ3hCLGdCQUFnQixFQUFFLFFBQVE7SUFDMUIsV0FBVyxFQUFFLE1BQU07SUFDbkIsZ0JBQWdCLEVBQUUsU0FBUztJQUMzQixrQkFBa0IsRUFBRSxHQUFHO0lBQ3ZCLGtCQUFrQixFQUFFLEdBQUc7Q0FDeEIsQ0FBQTtBQUVELE1BQWEsc0JBQXVCLFNBQVEsc0JBQVM7SUFJbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUFrQztRQUMxRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLElBQUksQ0FBQywyQkFBMkIsR0FBRyxJQUFJLHdCQUFNLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUU7WUFDckUsV0FBVztZQUNYLE9BQU8sRUFBRSx3QkFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXO1lBQ25DLE9BQU8sRUFBRSxpQkFBaUI7WUFDMUIsVUFBVSxFQUFFLElBQUk7WUFDaEIsWUFBWSxFQUFFLHNCQUFRLENBQUMsYUFBYSxDQUFDLFFBQVE7WUFDN0MsT0FBTyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM3QixJQUFJLEVBQUUsd0JBQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxFQUFFO2dCQUM1RCxJQUFJLEVBQUUsdUNBQXVDO2dCQUM3QyxTQUFTLEVBQUUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFO2FBQ3RDLENBQUM7WUFDRixHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7WUFDZCxVQUFVLEVBQUUsS0FBSyxDQUFDLGVBQWU7WUFDakMsaUJBQWlCLEVBQUUsSUFBSTtZQUN2Qix3RUFBd0U7WUFDeEUsV0FBVyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyx1QkFBdUIsRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsbUJBQW1CLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsdUJBQXVCO1lBQ3BKLGlFQUFpRTtZQUNqRSxHQUFHLEtBQUssQ0FBQyxxQkFBcUI7U0FDL0IsQ0FBQyxDQUFDO1FBRUgsZ0RBQWdEO1FBQ2hELElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xCLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUM3QixJQUFJLENBQUMsMkJBQTJCLENBQUMsZUFBZSxDQUFDLElBQUkscUJBQUcsQ0FBQyxlQUFlLENBQUM7b0JBQ3ZFLE9BQU8sRUFBRSxDQUFDLGNBQWMsQ0FBQztvQkFDekIsU0FBUyxFQUFFLENBQUMsZ0JBQWdCLE1BQU0sSUFBSSxDQUFDO2lCQUN4QyxDQUFDLENBQUMsQ0FBQztZQUNOLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBRTNELElBQUksS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2QsSUFBSSxDQUFDLDJCQUEyQixDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxxQkFBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsZ0NBQWdDLENBQUMsQ0FBQztRQUN2SCxDQUFDO1FBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSw4QkFBWSxDQUFDLE9BQU8sQ0FDdEMsSUFBSSxFQUNKLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxxQkFBcUIsRUFDaEQ7WUFDRSxvQkFBb0IsRUFBRSxLQUFLLENBQUMsMEJBQTBCO2dCQUNwRCxDQUFDLENBQUM7b0JBQ0UsVUFBVSxFQUFFLEtBQUssQ0FBQywwQkFBMEI7aUJBQzdDO2dCQUNILENBQUMsQ0FBQyxTQUFTO1lBQ2Isa0JBQWtCLEVBQ2hCLElBQUksMkNBQXlCLENBQUMscUJBQXFCLENBQ2pELGFBQWEsRUFDYixJQUFJLENBQUMsMkJBQTJCLEVBQ2hDLEtBQUssQ0FBQywwQkFBMEI7Z0JBQzlCLENBQUMsQ0FBQztvQkFDRSxnQkFBZ0IsRUFDZCxJQUFJLDhCQUFZLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxlQUFlLENBQ2pELE1BQU0sRUFDTiw4QkFBWSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQzlCLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQ3RDLENBQ0Y7aUJBQ0o7Z0JBQ0gsQ0FBQyxDQUFDLFNBQVMsQ0FDZDtTQUNKLENBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUksQ0FBQztRQUV4QixJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLDJCQUEyQixFQUFFO1lBQy9DLFVBQVUsRUFBRSxHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMscUJBQXFCO1lBQzVELEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRztTQUNoQixDQUFDLENBQUM7SUFDTCxDQUFDOztBQTdFSCx3REE4RUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBTdGFjayxcbiAgYXdzX2FwaWdhdGV3YXl2MiBhcyBhcGlnYXRld2F5djIsXG4gIGF3c19hcGlnYXRld2F5djJfaW50ZWdyYXRpb25zIGFzIGFwaWdhdGV3YXl2Ml9pbnRlZ3JhdGlvbnMsXG4gIGF3c19pYW0gYXMgaWFtLFxuICBhd3NfZWMyIGFzIGVjMixcbiAgYXdzX3JkcyBhcyByZHMsXG4gIGF3c19sYW1iZGEgYXMgbGFtYmRhLFxuICBhd3Nfc2VjcmV0c21hbmFnZXIgYXMgc2VjcmV0c21hbmFnZXIsXG4gIENmbk91dHB1dCxcbiAgRHVyYXRpb24sXG4gIGF3c19sb2dzLFxufSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBDdXN0b21MYW1iZGFGdW5jdGlvblByb3BzIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuXG4gIC8vIGRlZmF1bHQgc2V0dGluZ3MgdGhhdCBjYW4gYmUgb3ZlcnJpZGRlbiBieSB0aGUgdXNlci1wcm92aWRlZCBlbnZpcm9ubWVudC5cbiAgbGV0IGRlZmF1bHRUaXRpbGVyUGdzdGFjRW52IDp7IFtrZXk6IHN0cmluZ106IGFueSB9ID0ge1xuICAgIFwiQ1BMX1ZTSUxfQ1VSTF9BTExPV0VEX0VYVEVOU0lPTlNcIjogXCIudGlmLC5USUYsLnRpZmZcIixcbiAgICBcIkdEQUxfQ0FDSEVNQVhcIjogXCIyMDBcIixcbiAgICBcIkdEQUxfRElTQUJMRV9SRUFERElSX09OX09QRU5cIjogXCJFTVBUWV9ESVJcIixcbiAgICBcIkdEQUxfSU5HRVNURURfQllURVNfQVRfT1BFTlwiOiBcIjMyNzY4XCIsXG4gICAgXCJHREFMX0hUVFBfTUVSR0VfQ09OU0VDVVRJVkVfUkFOR0VTXCI6IFwiWUVTXCIsXG4gICAgXCJHREFMX0hUVFBfTVVMVElQTEVYXCI6IFwiWUVTXCIsXG4gICAgXCJHREFMX0hUVFBfVkVSU0lPTlwiOiBcIjJcIixcbiAgICBcIlBZVEhPTldBUk5JTkdTXCI6IFwiaWdub3JlXCIsXG4gICAgXCJWU0lfQ0FDSEVcIjogXCJUUlVFXCIsXG4gICAgXCJWU0lfQ0FDSEVfU0laRVwiOiBcIjUwMDAwMDBcIixcbiAgICBcIkRCX01JTl9DT05OX1NJWkVcIjogXCIxXCIsXG4gICAgXCJEQl9NQVhfQ09OTl9TSVpFXCI6IFwiMVwiXG4gIH1cblxuICBleHBvcnQgY2xhc3MgVGl0aWxlclBnc3RhY0FwaUxhbWJkYSBleHRlbmRzIENvbnN0cnVjdCB7XG4gICAgcmVhZG9ubHkgdXJsOiBzdHJpbmc7XG4gICAgcHVibGljIHRpdGlsZXJQZ3N0YWNMYW1iZGFGdW5jdGlvbjogbGFtYmRhLkZ1bmN0aW9uO1xuXG4gICAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFRpdGlsZXJQZ1N0YWNBcGlMYW1iZGFQcm9wcykge1xuICAgICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgICAgdGhpcy50aXRpbGVyUGdzdGFjTGFtYmRhRnVuY3Rpb24gPSBuZXcgbGFtYmRhLkZ1bmN0aW9uKHRoaXMsIFwibGFtYmRhXCIsIHtcbiAgICAgICAgLy8gZGVmYXVsdHNcbiAgICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTEsXG4gICAgICAgIGhhbmRsZXI6IFwiaGFuZGxlci5oYW5kbGVyXCIsXG4gICAgICAgIG1lbW9yeVNpemU6IDMwMDgsXG4gICAgICAgIGxvZ1JldGVudGlvbjogYXdzX2xvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfV0VFSyxcbiAgICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Eb2NrZXJCdWlsZChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nKSwge1xuICAgICAgICAgIGZpbGU6IFwidGl0aWxlci1wZ3N0YWMtYXBpL3J1bnRpbWUvRG9ja2VyZmlsZVwiLFxuICAgICAgICAgIGJ1aWxkQXJnczogeyBQWVRIT05fVkVSU0lPTjogJzMuMTEnIH1cbiAgICAgICAgfSksXG4gICAgICAgIHZwYzogcHJvcHMudnBjLFxuICAgICAgICB2cGNTdWJuZXRzOiBwcm9wcy5zdWJuZXRTZWxlY3Rpb24sXG4gICAgICAgIGFsbG93UHVibGljU3VibmV0OiB0cnVlLFxuICAgICAgICAvLyBpZiB1c2VyIHByb3ZpZGVkIGVudmlyb25tZW50IHZhcmlhYmxlcywgbWVyZ2UgdGhlbSB3aXRoIHRoZSBkZWZhdWx0cy5cbiAgICAgICAgZW52aXJvbm1lbnQ6IHByb3BzLmFwaUVudiA/IHsgLi4uZGVmYXVsdFRpdGlsZXJQZ3N0YWNFbnYsIC4uLnByb3BzLmFwaUVudiwgXCJQR1NUQUNfU0VDUkVUX0FSTlwiOiBwcm9wcy5kYlNlY3JldC5zZWNyZXRBcm4gfSA6IGRlZmF1bHRUaXRpbGVyUGdzdGFjRW52LFxuICAgICAgICAvLyBvdmVyd3JpdGVzIGRlZmF1bHRzIHdpdGggdXNlci1wcm92aWRlZCBjb25maWd1cmFibGUgcHJvcGVydGllc1xuICAgICAgICAuLi5wcm9wcy5sYW1iZGFGdW5jdGlvbk9wdGlvbnMsXG4gICAgICB9KTtcblxuICAgICAgLy8gZ3JhbnQgYWNjZXNzIHRvIGJ1Y2tldHMgdXNpbmcgYWRkVG9Sb2xlUG9saWN5XG4gICAgICBpZiAocHJvcHMuYnVja2V0cykge1xuICAgICAgICBwcm9wcy5idWNrZXRzLmZvckVhY2goYnVja2V0ID0+IHtcbiAgICAgICAgICB0aGlzLnRpdGlsZXJQZ3N0YWNMYW1iZGFGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3kobmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgYWN0aW9uczogW1wiczM6R2V0T2JqZWN0XCJdLFxuICAgICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6czM6Ojoke2J1Y2tldH0vKmBdLFxuICAgICAgICAgIH0pKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHByb3BzLmRiU2VjcmV0LmdyYW50UmVhZCh0aGlzLnRpdGlsZXJQZ3N0YWNMYW1iZGFGdW5jdGlvbik7XG5cbiAgICAgIGlmIChwcm9wcy52cGMpIHtcbiAgICAgICAgdGhpcy50aXRpbGVyUGdzdGFjTGFtYmRhRnVuY3Rpb24uY29ubmVjdGlvbnMuYWxsb3dUbyhwcm9wcy5kYiwgZWMyLlBvcnQudGNwKDU0MzIpLCBcImFsbG93IGNvbm5lY3Rpb25zIGZyb20gdGl0aWxlclwiKTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc3RhY0FwaSA9IG5ldyBhcGlnYXRld2F5djIuSHR0cEFwaShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS10aXRpbGVyLXBnc3RhYy1hcGlgLFxuICAgICAgICB7XG4gICAgICAgICAgZGVmYXVsdERvbWFpbk1hcHBpbmc6IHByb3BzLnRpdGlsZXJQZ3N0YWNBcGlEb21haW5OYW1lXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBkb21haW5OYW1lOiBwcm9wcy50aXRpbGVyUGdzdGFjQXBpRG9tYWluTmFtZSxcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgZGVmYXVsdEludGVncmF0aW9uOlxuICAgICAgICAgICAgbmV3IGFwaWdhdGV3YXl2Ml9pbnRlZ3JhdGlvbnMuSHR0cExhbWJkYUludGVncmF0aW9uKFxuICAgICAgICAgICAgICBcImludGVncmF0aW9uXCIsXG4gICAgICAgICAgICAgIHRoaXMudGl0aWxlclBnc3RhY0xhbWJkYUZ1bmN0aW9uLFxuICAgICAgICAgICAgICBwcm9wcy50aXRpbGVyUGdzdGFjQXBpRG9tYWluTmFtZVxuICAgICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJNYXBwaW5nOlxuICAgICAgICAgICAgICAgICAgICAgIG5ldyBhcGlnYXRld2F5djIuUGFyYW1ldGVyTWFwcGluZygpLm92ZXJ3cml0ZUhlYWRlcihcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiaG9zdFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgYXBpZ2F0ZXdheXYyLk1hcHBpbmdWYWx1ZS5jdXN0b20oXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHByb3BzLnRpdGlsZXJQZ3N0YWNBcGlEb21haW5OYW1lLm5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgICAgICApLFxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICB0aGlzLnVybCA9IHN0YWNBcGkudXJsITtcblxuICAgICAgbmV3IENmbk91dHB1dCh0aGlzLCBcInRpdGlsZXItcGdzdGFjLWFwaS1vdXRwdXRcIiwge1xuICAgICAgICBleHBvcnROYW1lOiBgJHtTdGFjay5vZih0aGlzKS5zdGFja05hbWV9LXRpdGlsZXItcGdzdGFjLXVybGAsXG4gICAgICAgIHZhbHVlOiB0aGlzLnVybCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGV4cG9ydCBpbnRlcmZhY2UgVGl0aWxlclBnU3RhY0FwaUxhbWJkYVByb3BzIHtcbiAgICAvKipcbiAgICAgKiBWUEMgaW50byB3aGljaCB0aGUgbGFtYmRhIHNob3VsZCBiZSBkZXBsb3llZC5cbiAgICAgKi9cbiAgICByZWFkb25seSB2cGM/OiBlYzIuSVZwYztcblxuICAgIC8qKlxuICAgICAqIFJEUyBJbnN0YW5jZSB3aXRoIGluc3RhbGxlZCBwZ1NUQUMgb3IgcGdib3VuY2VyIHNlcnZlci5cbiAgICAgKi9cbiAgICByZWFkb25seSBkYjogcmRzLklEYXRhYmFzZUluc3RhbmNlIHwgZWMyLklJbnN0YW5jZTtcblxuICAgIC8qKlxuICAgICAqIFN1Ym5ldCBpbnRvIHdoaWNoIHRoZSBsYW1iZGEgc2hvdWxkIGJlIGRlcGxveWVkLlxuICAgICAqL1xuICAgIHJlYWRvbmx5IHN1Ym5ldFNlbGVjdGlvbj86IGVjMi5TdWJuZXRTZWxlY3Rpb247XG5cbiAgICAvKipcbiAgICAgKiBTZWNyZXQgY29udGFpbmluZyBjb25uZWN0aW9uIGluZm9ybWF0aW9uIGZvciBwZ1NUQUMgZGF0YWJhc2UuXG4gICAgICovXG4gICAgcmVhZG9ubHkgZGJTZWNyZXQ6IHNlY3JldHNtYW5hZ2VyLklTZWNyZXQ7XG5cbiAgICAvKipcbiAgICAgKiBDdXN0b21pemVkIGVudmlyb25tZW50IHZhcmlhYmxlcyB0byBzZW5kIHRvIHRpdGlsZXItcGdzdGFjIHJ1bnRpbWUuIFRoZXNlIHdpbGwgYmUgbWVyZ2VkIHdpdGggYGRlZmF1bHRUaXRpbGVyUGdzdGFjRW52YC5cbiAgICAgKiBUaGUgZGF0YWJhc2Ugc2VjcmV0IGFybiBpcyBhdXRvbWF0aWNhbGx5IGFkZGVkIHRvIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXQgZGVwbG95bWVudC5cbiAgICAvKi9cbiAgICByZWFkb25seSBhcGlFbnY/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuXG4gICAgLyoqXG4gICAgICogbGlzdCBvZiBidWNrZXRzIHRoZSBsYW1iZGEgd2lsbCBiZSBncmFudGVkIGFjY2VzcyB0by5cbiAgICAgKi9cbiAgICByZWFkb25seSBidWNrZXRzPzogc3RyaW5nW107XG5cbiAgICAvKipcbiAgICAgKiBDdXN0b20gRG9tYWluIE5hbWUgT3B0aW9ucyBmb3IgVGl0aWxlciBQZ3N0YWMgQVBJLFxuICAgICAqXG4gICAgICogQGRlZmF1bHQgLSB1bmRlZmluZWQuXG4gICAgICovXG4gICAgcmVhZG9ubHkgdGl0aWxlclBnc3RhY0FwaURvbWFpbk5hbWU/OiBhcGlnYXRld2F5djIuSURvbWFpbk5hbWU7XG5cbiAgICAvKipcbiAgICAgKiBDYW4gYmUgdXNlZCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBsYW1iZGEgZnVuY3Rpb24gcHJvcGVydGllcy5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IC0gZGVmaW5lZCBpbiB0aGUgY29uc3RydWN0LlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGxhbWJkYUZ1bmN0aW9uT3B0aW9ucz86IEN1c3RvbUxhbWJkYUZ1bmN0aW9uUHJvcHM7XG4gIH1cbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eoapi-cdk",
3
- "version": "8.1.1",
3
+ "version": "8.2.0",
4
4
  "description": "A set of constructs deploying pgSTAC with CDK",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
package/pyproject.toml ADDED
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "eoapi-cdk"
3
+ version = "0.0"
4
+ requires-python = ">=3.11"
5
+ dependencies = [
6
+ "stactools-item-generator",
7
+ "stac-item-loader",
8
+ ]
9
+
10
+ [tool.uv.sources]
11
+ stactools-item-generator = { workspace = true }
12
+ stac-item-loader = { workspace = true }
13
+
14
+ [tool.uv.workspace]
15
+ members = ["lib/stac-item-loader/runtime", "lib/stactools-item-generator/runtime"]
16
+
17
+ [dependency-groups]
18
+ deploy = [
19
+ "aws-cdk-lib==2.190.0",
20
+ "constructs==10.3.0",
21
+ "pydantic>=2.11.5",
22
+ "pydantic-settings[yaml]>=2.8.1",
23
+ "python-dotenv>=1.1.0",
24
+ "pyyaml>=6.0.2",
25
+ "types-pyyaml>=6.0.12.20250516",
26
+ ]
27
+ dev = [
28
+ "aws-lambda-typing>=2.20.0",
29
+ "httpx>=0.28.1",
30
+ "pytest>=8.3.5",
31
+ "pytest-mock>=3.14.0",
32
+ "pytest-postgresql>=7.0.1",
33
+ ]
34
+
35
+ [tool.pytest.ini_options]
36
+ addopts = "-vv --ignore=cdk.out --no-header --tb=native"
37
+ pythonpath = "."
38
+ testpaths = [
39
+ "lib/stactools-item-generator/runtime/tests",
40
+ "lib/stac-item-loader/runtime/tests",
41
+ ]
42
+
43
+ [tool.ruff]
44
+
45
+ [tool.ruff.lint]