eoapi-cdk 11.3.1 → 11.4.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.
package/.jsii CHANGED
@@ -4081,7 +4081,7 @@
4081
4081
  "stability": "experimental"
4082
4082
  },
4083
4083
  "homepage": "https://github.com/developmentseed/eoapi-cdk.git",
4084
- "jsiiVersion": "5.9.10 (build 0e9cf43)",
4084
+ "jsiiVersion": "5.9.34 (build 8773a22)",
4085
4085
  "keywords": [],
4086
4086
  "license": "ISC",
4087
4087
  "metadata": {
@@ -4300,7 +4300,7 @@
4300
4300
  "kind": "interface",
4301
4301
  "locationInModule": {
4302
4302
  "filename": "lib/database/index.ts",
4303
- "line": 462
4303
+ "line": 495
4304
4304
  },
4305
4305
  "name": "DatabaseParameters",
4306
4306
  "properties": [
@@ -4313,7 +4313,7 @@
4313
4313
  "immutable": true,
4314
4314
  "locationInModule": {
4315
4315
  "filename": "lib/database/index.ts",
4316
- "line": 478
4316
+ "line": 511
4317
4317
  },
4318
4318
  "name": "effectiveCacheSize",
4319
4319
  "type": {
@@ -4329,7 +4329,7 @@
4329
4329
  "immutable": true,
4330
4330
  "locationInModule": {
4331
4331
  "filename": "lib/database/index.ts",
4332
- "line": 488
4332
+ "line": 521
4333
4333
  },
4334
4334
  "name": "maintenanceWorkMem",
4335
4335
  "type": {
@@ -4345,7 +4345,7 @@
4345
4345
  "immutable": true,
4346
4346
  "locationInModule": {
4347
4347
  "filename": "lib/database/index.ts",
4348
- "line": 466
4348
+ "line": 499
4349
4349
  },
4350
4350
  "name": "maxConnections",
4351
4351
  "type": {
@@ -4361,7 +4361,7 @@
4361
4361
  "immutable": true,
4362
4362
  "locationInModule": {
4363
4363
  "filename": "lib/database/index.ts",
4364
- "line": 493
4364
+ "line": 526
4365
4365
  },
4366
4366
  "name": "maxLocksPerTransaction",
4367
4367
  "type": {
@@ -4377,7 +4377,7 @@
4377
4377
  "immutable": true,
4378
4378
  "locationInModule": {
4379
4379
  "filename": "lib/database/index.ts",
4380
- "line": 508
4380
+ "line": 541
4381
4381
  },
4382
4382
  "name": "randomPageCost",
4383
4383
  "type": {
@@ -4393,7 +4393,7 @@
4393
4393
  "immutable": true,
4394
4394
  "locationInModule": {
4395
4395
  "filename": "lib/database/index.ts",
4396
- "line": 503
4396
+ "line": 536
4397
4397
  },
4398
4398
  "name": "seqPageCost",
4399
4399
  "type": {
@@ -4410,7 +4410,7 @@
4410
4410
  "immutable": true,
4411
4411
  "locationInModule": {
4412
4412
  "filename": "lib/database/index.ts",
4413
- "line": 473
4413
+ "line": 506
4414
4414
  },
4415
4415
  "name": "sharedBuffers",
4416
4416
  "type": {
@@ -4426,7 +4426,7 @@
4426
4426
  "immutable": true,
4427
4427
  "locationInModule": {
4428
4428
  "filename": "lib/database/index.ts",
4429
- "line": 498
4429
+ "line": 531
4430
4430
  },
4431
4431
  "name": "tempBuffers",
4432
4432
  "type": {
@@ -4442,7 +4442,7 @@
4442
4442
  "immutable": true,
4443
4443
  "locationInModule": {
4444
4444
  "filename": "lib/database/index.ts",
4445
- "line": 483
4445
+ "line": 516
4446
4446
  },
4447
4447
  "name": "workMem",
4448
4448
  "type": {
@@ -4988,7 +4988,7 @@
4988
4988
  },
4989
4989
  "locationInModule": {
4990
4990
  "filename": "lib/database/index.ts",
4991
- "line": 131
4991
+ "line": 130
4992
4992
  },
4993
4993
  "parameters": [
4994
4994
  {
@@ -5014,7 +5014,7 @@
5014
5014
  "kind": "class",
5015
5015
  "locationInModule": {
5016
5016
  "filename": "lib/database/index.ts",
5017
- "line": 119
5017
+ "line": 118
5018
5018
  },
5019
5019
  "methods": [
5020
5020
  {
@@ -5023,7 +5023,7 @@
5023
5023
  },
5024
5024
  "locationInModule": {
5025
5025
  "filename": "lib/database/index.ts",
5026
- "line": 307
5026
+ "line": 308
5027
5027
  },
5028
5028
  "name": "getParameters",
5029
5029
  "parameters": [
@@ -5062,7 +5062,7 @@
5062
5062
  "immutable": true,
5063
5063
  "locationInModule": {
5064
5064
  "filename": "lib/database/index.ts",
5065
- "line": 125
5065
+ "line": 124
5066
5066
  },
5067
5067
  "name": "connectionTarget",
5068
5068
  "type": {
@@ -5085,7 +5085,7 @@
5085
5085
  "immutable": true,
5086
5086
  "locationInModule": {
5087
5087
  "filename": "lib/database/index.ts",
5088
- "line": 124
5088
+ "line": 123
5089
5089
  },
5090
5090
  "name": "pgstacVersion",
5091
5091
  "type": {
@@ -5099,7 +5099,7 @@
5099
5099
  "immutable": true,
5100
5100
  "locationInModule": {
5101
5101
  "filename": "lib/database/index.ts",
5102
- "line": 128
5102
+ "line": 127
5103
5103
  },
5104
5104
  "name": "pgbouncerHealthCheck",
5105
5105
  "optional": true,
@@ -5114,7 +5114,7 @@
5114
5114
  "immutable": true,
5115
5115
  "locationInModule": {
5116
5116
  "filename": "lib/database/index.ts",
5117
- "line": 129
5117
+ "line": 128
5118
5118
  },
5119
5119
  "name": "pgbouncerInstanceId",
5120
5120
  "optional": true,
@@ -5129,7 +5129,7 @@
5129
5129
  "immutable": true,
5130
5130
  "locationInModule": {
5131
5131
  "filename": "lib/database/index.ts",
5132
- "line": 127
5132
+ "line": 126
5133
5133
  },
5134
5134
  "name": "secretBootstrapper",
5135
5135
  "optional": true,
@@ -5144,7 +5144,7 @@
5144
5144
  "immutable": true,
5145
5145
  "locationInModule": {
5146
5146
  "filename": "lib/database/index.ts",
5147
- "line": 126
5147
+ "line": 125
5148
5148
  },
5149
5149
  "name": "securityGroup",
5150
5150
  "optional": true,
@@ -5158,7 +5158,7 @@
5158
5158
  },
5159
5159
  "locationInModule": {
5160
5160
  "filename": "lib/database/index.ts",
5161
- "line": 120
5161
+ "line": 119
5162
5162
  },
5163
5163
  "name": "db",
5164
5164
  "type": {
@@ -5171,7 +5171,7 @@
5171
5171
  },
5172
5172
  "locationInModule": {
5173
5173
  "filename": "lib/database/index.ts",
5174
- "line": 121
5174
+ "line": 120
5175
5175
  },
5176
5176
  "name": "pgstacSecret",
5177
5177
  "type": {
@@ -5194,7 +5194,7 @@
5194
5194
  "kind": "interface",
5195
5195
  "locationInModule": {
5196
5196
  "filename": "lib/database/index.ts",
5197
- "line": 347
5197
+ "line": 348
5198
5198
  },
5199
5199
  "name": "PgStacDatabaseProps",
5200
5200
  "properties": [
@@ -5208,7 +5208,7 @@
5208
5208
  "immutable": true,
5209
5209
  "locationInModule": {
5210
5210
  "filename": "lib/database/index.ts",
5211
- "line": 416
5211
+ "line": 417
5212
5212
  },
5213
5213
  "name": "addPatchManager",
5214
5214
  "optional": true,
@@ -5226,7 +5226,7 @@
5226
5226
  "immutable": true,
5227
5227
  "locationInModule": {
5228
5228
  "filename": "lib/database/index.ts",
5229
- "line": 381
5229
+ "line": 382
5230
5230
  },
5231
5231
  "name": "addPgbouncer",
5232
5232
  "optional": true,
@@ -5244,7 +5244,7 @@
5244
5244
  "immutable": true,
5245
5245
  "locationInModule": {
5246
5246
  "filename": "lib/database/index.ts",
5247
- "line": 440
5247
+ "line": 473
5248
5248
  },
5249
5249
  "name": "bootstrapperLambdaFunctionOptions",
5250
5250
  "optional": true,
@@ -5255,14 +5255,15 @@
5255
5255
  {
5256
5256
  "abstract": true,
5257
5257
  "docs": {
5258
- "remarks": "A custom resource property is going to be created\nto trigger the boostrapping lambda function. This parameter allows the user to specify additional properties\non top of the defaults ones.",
5258
+ "example": "customResourceProperties: {\n update_collection_extent: \"TRUE\",\n use_queue: \"TRUE\",\n pg_cron_schedule: \"*\\/10 * * * *\",\n}",
5259
+ "remarks": "These are merged with the defaults and forwarded\nto the handler as `event[\"ResourceProperties\"]`.\n\n## Supported pgSTAC settings\n\nEach setting follows honest boolean semantics: `\"TRUE\"` enables, `\"FALSE\"`\ndisables (reverts to pgSTAC's built-in default), and omitting the key\nentirely is a no-op — the database is left as-is. This means upgrading\nwithout changing config never silently alters a manually-managed setting.\n\n| Property | Default | Description |\n|----------------------------|----------|-------------|\n| `context` | (unset) | Enable `CONTEXT=ON` in pgSTAC (item count on search). |\n| `mosaic_index` | `\"TRUE\"` | Create a partial index on searches of type `mosaic`. Set `\"FALSE\"` to drop it. |\n| `update_collection_extent` | (unset) | Automatically update collection spatial/temporal extents on item ingest. Combine with `use_queue` to reduce per-transaction overhead. |\n| `use_queue` | (unset) | Process extent updates asynchronously via an internal queue. `\"TRUE\"` installs pg_cron and schedules the drain job; `\"FALSE\"` removes the job. Requires `pg_cron` (see below). |\n| `pg_cron_schedule` | `\"*\\/10 * * * *\"` | Cron schedule for `CALL run_queued_queries()`. Only used when `use_queue` is `\"TRUE\"`. |\n\n## pg_cron requirement\n\nWhen `use_queue` is `\"TRUE\"`, the bootstrapper installs the `pg_cron`\nextension and schedules a job to periodically drain the queue.\n`pg_cron` must be present in `shared_preload_libraries` **before**\ndeployment or the bootstrap will fail. Add it via `props.parameters`:\n\n```\nparameters: { shared_preload_libraries: \"pg_cron\" }\n```",
5259
5260
  "stability": "experimental",
5260
- "summary": "Lambda function Custom Resource properties."
5261
+ "summary": "Additional properties passed to the bootstrapper Lambda as CloudFormation Custom Resource properties."
5261
5262
  },
5262
5263
  "immutable": true,
5263
5264
  "locationInModule": {
5264
5265
  "filename": "lib/database/index.ts",
5265
- "line": 431
5266
+ "line": 464
5266
5267
  },
5267
5268
  "name": "customResourceProperties",
5268
5269
  "optional": true,
@@ -5286,7 +5287,7 @@
5286
5287
  "immutable": true,
5287
5288
  "locationInModule": {
5288
5289
  "filename": "lib/database/index.ts",
5289
- "line": 459
5290
+ "line": 492
5290
5291
  },
5291
5292
  "name": "forceBootstrap",
5292
5293
  "optional": true,
@@ -5304,7 +5305,7 @@
5304
5305
  "immutable": true,
5305
5306
  "locationInModule": {
5306
5307
  "filename": "lib/database/index.ts",
5307
- "line": 423
5308
+ "line": 424
5308
5309
  },
5309
5310
  "name": "maintenanceWindow",
5310
5311
  "optional": true,
@@ -5323,7 +5324,7 @@
5323
5324
  "immutable": true,
5324
5325
  "locationInModule": {
5325
5326
  "filename": "lib/database/index.ts",
5326
- "line": 408
5327
+ "line": 409
5327
5328
  },
5328
5329
  "name": "pgbouncerAmiSsmParameter",
5329
5330
  "optional": true,
@@ -5341,7 +5342,7 @@
5341
5342
  "immutable": true,
5342
5343
  "locationInModule": {
5343
5344
  "filename": "lib/database/index.ts",
5344
- "line": 388
5345
+ "line": 389
5345
5346
  },
5346
5347
  "name": "pgbouncerInstanceProps",
5347
5348
  "optional": true,
@@ -5359,7 +5360,7 @@
5359
5360
  "immutable": true,
5360
5361
  "locationInModule": {
5361
5362
  "filename": "lib/database/index.ts",
5362
- "line": 353
5363
+ "line": 354
5363
5364
  },
5364
5365
  "name": "pgstacDbName",
5365
5366
  "optional": true,
@@ -5377,7 +5378,7 @@
5377
5378
  "immutable": true,
5378
5379
  "locationInModule": {
5379
5380
  "filename": "lib/database/index.ts",
5380
- "line": 374
5381
+ "line": 375
5381
5382
  },
5382
5383
  "name": "pgstacUsername",
5383
5384
  "optional": true,
@@ -5395,7 +5396,7 @@
5395
5396
  "immutable": true,
5396
5397
  "locationInModule": {
5397
5398
  "filename": "lib/database/index.ts",
5398
- "line": 360
5399
+ "line": 361
5399
5400
  },
5400
5401
  "name": "pgstacVersion",
5401
5402
  "optional": true,
@@ -5413,7 +5414,7 @@
5413
5414
  "immutable": true,
5414
5415
  "locationInModule": {
5415
5416
  "filename": "lib/database/index.ts",
5416
- "line": 367
5417
+ "line": 368
5417
5418
  },
5418
5419
  "name": "secretsPrefix",
5419
5420
  "optional": true,
@@ -7999,6 +8000,6 @@
7999
8000
  "symbolId": "lib/titiler-pgstac-api/index:TitilerPgstacApiLambdaRuntimeProps"
8000
8001
  }
8001
8002
  },
8002
- "version": "11.3.1",
8003
- "fingerprint": "te+s2VXr/r9dyNnAEBlk66pcgb7rMGXcqJypR7IwGVc="
8003
+ "version": "11.4.0",
8004
+ "fingerprint": "XAgc9qDybKGNxcDQS+Srt8N+/5AJbD+nSQHWHr6Q12o="
8004
8005
  }
@@ -158,5 +158,5 @@ class BastionHost extends constructs_1.Construct {
158
158
  }
159
159
  exports.BastionHost = BastionHost;
160
160
  _a = JSII_RTTI_SYMBOL_1;
161
- BastionHost[_a] = { fqn: "eoapi-cdk.BastionHost", version: "11.3.1" };
161
+ BastionHost[_a] = { fqn: "eoapi-cdk.BastionHost", version: "11.4.0" };
162
162
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQU1xQjtBQUNyQiwyQ0FBdUM7QUFFdkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpR0c7QUFDSCxNQUFhLFdBQVksU0FBUSxzQkFBUztJQUd4QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXVCO1FBQy9ELEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXJDLHFCQUFxQjtRQUNyQixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUkscUJBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRTtZQUNyRCxHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7WUFDZCxVQUFVLEVBQUUsRUFBRSxVQUFVLEVBQUUscUJBQUcsQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFO1lBQ2pELFlBQVksRUFBRSxHQUFHLFNBQVMsZUFBZTtZQUN6QyxZQUFZLEVBQUUscUJBQUcsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUMvQixxQkFBRyxDQUFDLGFBQWEsQ0FBQyxtQkFBbUIsRUFDckMscUJBQUcsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUN0QjtZQUNELFlBQVksRUFBRSxxQkFBRyxDQUFDLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQztnQkFDL0MsVUFBVSxFQUFFLHFCQUFHLENBQUMscUJBQXFCLENBQUMsY0FBYztnQkFDcEQsT0FBTyxFQUFFLHFCQUFHLENBQUMsa0JBQWtCLENBQUMsTUFBTTthQUN2QyxDQUFDO1lBQ0YsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO1lBQ3hCLHlCQUF5QixFQUFFLElBQUk7U0FDaEMsQ0FBQyxDQUFDO1FBRUgsb0JBQW9CO1FBQ3BCLElBQUksS0FBSyxDQUFDLGVBQWUsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNsQyxJQUFJLHFCQUFHLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUU7Z0JBQ3pCLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVU7Z0JBQ3BDLElBQUksRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUM7YUFDMUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQy9CLEtBQUssQ0FBQyxFQUFFLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsRUFDdEMscUJBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUNsQixvQ0FBb0MsQ0FDckMsQ0FBQztRQUVGLGtDQUFrQztRQUNsQyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQ2pDLHFCQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDbkIscUJBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLEVBQ2pDLFlBQVksQ0FDYixDQUFDO1FBQ0osQ0FBQztRQUVELHFCQUFxQjtRQUNyQixJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FDM0IsSUFBSSxxQkFBRyxDQUFDLGVBQWUsQ0FBQztZQUN0QixPQUFPLEVBQUU7Z0JBQ1AsZUFBZTtnQkFDZiwrQkFBK0I7Z0JBQy9CLGVBQWU7YUFDaEI7WUFDRCxTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7U0FDakIsQ0FBQyxDQUNILENBQUM7UUFFRixJQUFJLHVCQUFTLENBQUMsSUFBSSxFQUFFLG9CQUFvQixFQUFFO1lBQ3hDLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVU7WUFDL0IsVUFBVSxFQUFFLEdBQUcsU0FBUyxjQUFjO1NBQ3ZDLENBQUMsQ0FBQztRQUNILElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsMkJBQTJCLEVBQUU7WUFDL0MsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsZ0JBQWdCO1lBQ3JDLFVBQVUsRUFBRSxHQUFHLFNBQVMscUJBQXFCO1NBQzlDLENBQUMsQ0FBQztRQUNILElBQUksdUJBQVMsQ0FBQyxJQUFJLEVBQUUsaUNBQWlDLEVBQUU7WUFDckQsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMscUJBQXFCO1lBQzFDLFVBQVUsRUFBRSxHQUFHLFNBQVMsa0JBQWtCO1NBQzNDLENBQUMsQ0FBQztJQUNMLENBQUM7O0FBekVILGtDQTBFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIFN0YWNrLFxuICBhd3NfZWMyIGFzIGVjMixcbiAgYXdzX2lhbSBhcyBpYW0sXG4gIGF3c19yZHMgYXMgcmRzLFxuICBDZm5PdXRwdXQsXG59IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcblxuLyoqXG4gKiBUaGUgZGF0YWJhc2UgaXMgbG9jYXRlZCBpbiBhbiBpc29sYXRlZCBzdWJuZXQsIG1lYW5pbmcgdGhhdCBpdCBpcyBub3QgYWNjZXNzaWJsZSBmcm9tIHRoZSBwdWJsaWMgaW50ZXJuZXQuIEFzIHN1Y2gsIHRvIGludGVyYWN0IHdpdGggdGhlIGRhdGFiYXNlIGRpcmVjdGx5LCBhIHVzZXIgbXVzdCB0dW5uZWwgdGhyb3VnaCBhIGJhc3Rpb24gaG9zdC5cbiAqXG4gKiAjIyMgQ29uZmlndXJpbmdcbiAqXG4gKiBUaGlzIGNvZGViYXNlIGNvbnRyb2xzIF93aG9fIGlzIGFsbG93ZWQgdG8gY29ubmVjdCB0byB0aGUgYmFzdGlvbiBob3N0LiBUaGlzIHJlcXVpcmVzIHR3byBzdGVwczpcbiAqXG4gKiAxLiBBZGRpbmcgdGhlIElQIGFkZHJlc3MgZnJvbSB3aGljaCB5b3UgYXJlIGNvbm5lY3RpbmcgdG8gdGhlIGBpcHY0QWxsb3dsaXN0YCBhcnJheVxuICogMS4gQ3JlYXRpbmcgYSBiYXN0aW9uIGhvc3Qgc3lzdGVtIHVzZXIgYnkgYWRkaW5nIHRoZSB1c2VyJ3MgY29uZmlndXJhdGlvbiBpbmZvcm0gdG8gYHVzZXJkYXRhLnlhbWxgXG4gKlxuICogIyMjIyBBZGRpbmcgYW4gSVAgYWRkcmVzcyB0byB0aGUgYGlwdjRBbGxvd2xpc3RgIGFycmF5XG4gKlxuICogVGhlIGBCYXN0aW9uSG9zdGAgY29uc3RydWN0IHRha2VzIGluIGFuIGBpcHY0QWxsb3dsaXN0YCBhcnJheSBhcyBhbiBhcmd1bWVudC4gRmluZCB5b3VyIElQIGFkZHJlc3MgKGVnIGBjdXJsIGFwaS5pcGlmeS5vcmdgKSBhbmQgYWRkIHRoYXQgdG8gdGhlIGFycmF5IGFsb25nIHdpdGggdGhlIHRyYWlsaW5nIENJRFIgYmxvY2sgKGxpa2VseSBgLzMyYCB0byBpbmRpY2F0ZSB0aGF0IHlvdSBhcmUgYWRkaW5nIGEgc2luZ2xlIElQIGFkZHJlc3MpLlxuICpcbiAqICMjIyMgQ3JlYXRpbmcgYSB1c2VyIHZpYSBgdXNlcmRhdGEueWFtbGBcbiAqXG4gKiBBZGQgYW4gZW50cnkgdG8gdGhlIGB1c2Vyc2AgYXJyYXkgd2l0aCBhIHVzZXJuYW1lIChsaWtlbHkgbWF0Y2hpbmcgeW91ciBsb2NhbCBzeXN0ZW1zIHVzZXJuYW1lLCB3aGljaCB5b3UgY2FuIGdldCBieSBydW5uaW5nIHRoZSBgd2hvYW1pYCBjb21tYW5kIGluIHlvdXIgdGVybWluYWwpIGFuZCBhIHB1YmxpYyBrZXkgKGxpa2VseSB5b3VyIGRlZmF1bHQgcHVibGljIGtleSwgd2hpY2ggeW91IGNhbiBnZXQgYnkgcnVubmluZyBgY2F0IH4vLnNzaC9pZF8qLnB1YmAgaW4geW91ciB0ZXJtaW5hbCkuXG4gKlxuICogIyMjIyBUaXBzICYgVHJpY2tzIHdoZW4gdXNpbmcgdGhlIEJhc3Rpb24gSG9zdFxuICpcbiAqICoqQ29ubmVjdGluZyB0byBSRFMgSW5zdGFuY2UgdmlhIFNTTSoqXG4gKlxuICogYGBgc2hcbiAqIGF3cyBzc20gc3RhcnQtc2Vzc2lvbiAtLXRhcmdldCAkSU5TVEFOQ0VfSUQgXFxcbiAqIC0tZG9jdW1lbnQtbmFtZSBBV1MtU3RhcnRQb3J0Rm9yd2FyZGluZ1Nlc3Npb25Ub1JlbW90ZUhvc3QgXFxcbiAqIC0tcGFyYW1ldGVycyAne1xuICogXCJob3N0XCI6IFtcbiAqIFwiZXhhbXBsZS1kYi5jNWFiY2RlZmdoaWoudXMtd2VzdC0yLnJkcy5hbWF6b25hd3MuY29tXCJcbiAqIF0sXG4gKiBcInBvcnROdW1iZXJcIjogW1xuICogXCI1NDMyXCJcbiAqIF0sXG4gKiBcImxvY2FsUG9ydE51bWJlclwiOiBbXG4gKiBcIjk5OTlcIlxuICogXVxuICogfScgXFxcbiAqIC0tcHJvZmlsZSAkQVdTX1BST0ZJTEVcbiAqIGBgYFxuICpcbiAqIGBgYHNoXG4gKiBwc3FsIC1oIGxvY2FsaG9zdCAtcCA5OTk5ICMgY29udGludWUgYWRkaW5nIHVzZXJuYW1lICgtVSkgYW5kIGRiICgtZCkgaGVyZS4uLlxuICogYGBgXG4gKlxuICogQ29ubmVjdCBkaXJlY3RseSB0byBCYXN0aW9uIEhvc3Q6XG4gKlxuICogYGBgc2hcbiAqIGF3cyBzc20gc3RhcnQtc2Vzc2lvbiAtLXRhcmdldCAkSU5TVEFOQ0VfSUQgLS1wcm9maWxlICRBV1NfUFJPRklMRVxuICogYGBgXG4gKlxuICogKipTZXR0aW5nIHVwIGFuIFNTSCB0dW5uZWwqKlxuICpcbiAqIEluIHlvdXIgYH4vLnNzaC9jb25maWdgIGZpbGUsIGFkZCBhbiBlbnRyeSBsaWtlOlxuICpcbiAqIGBgYFxuICogSG9zdCBkYi10dW5uZWxcbiAqIEhvc3RuYW1lIHt0aGUtYmFzdGlvbi1ob3N0LWFkZHJlc3N9XG4gKiBMb2NhbEZvcndhcmQgOTk5OSB7dGhlLWRiLWhvc3RuYW1lfTo1NDMyXG4gKiBgYGBcbiAqXG4gKiBUaGVuIGEgdHVubmVsIGNhbiBiZSBvcGVuZWQgdmlhOlxuICpcbiAqIGBgYFxuICogc3NoIC1OIGRiLXR1bm5lbFxuICogYGBgXG4gKlxuICogQW5kIGEgY29ubmVjdGlvbiB0byB0aGUgREIgY2FuIGJlIG1hZGUgdmlhOlxuICpcbiAqIGBgYFxuICogcHNxbCAtaCAxMjcuMC4wLjEgLXAgOTk5OSAtVSB7dXNlcm5hbWV9IC1kIHtkYXRhYmFzZX1cbiAqIGBgYFxuICpcbiAqICoqSGFuZGxpbmcgYFJFTU9URSBIT1NUIElERU5USUZJQ0FUSU9OIEhBUyBDSEFOR0VEIWAgZXJyb3IqKlxuICpcbiAqIElmIHlvdSd2ZSByZWRlcGxveWVkIGEgYmFzdGlvbiBob3N0IHRoYXQgeW91J3ZlIHByZXZpb3VzbHkgY29ubmVjdGVkIHRvLCB5b3UgbWF5IHNlZSBhbiBlcnJvciBsaWtlOlxuICpcbiAqIGBgYFxuICogQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBcbiAqIEAgICAgV0FSTklORzogUkVNT1RFIEhPU1QgSURFTlRJRklDQVRJT04gSEFTIENIQU5HRUQhICAgICBAXG4gKiBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFxuICogSVQgSVMgUE9TU0lCTEUgVEhBVCBTT01FT05FIElTIERPSU5HIFNPTUVUSElORyBOQVNUWSFcbiAqIFNvbWVvbmUgY291bGQgYmUgZWF2ZXNkcm9wcGluZyBvbiB5b3UgcmlnaHQgbm93IChtYW4taW4tdGhlLW1pZGRsZSBhdHRhY2spIVxuICogSXQgaXMgYWxzbyBwb3NzaWJsZSB0aGF0IGEgaG9zdCBrZXkgaGFzIGp1c3QgYmVlbiBjaGFuZ2VkLlxuICogVGhlIGZpbmdlcnByaW50IGZvciB0aGUgRUNEU0Ega2V5IHNlbnQgYnkgdGhlIHJlbW90ZSBob3N0IGlzXG4gKiBTSEEyNTY6bVBueEFPWFRwYjA2UEZnSTFRYzhUTVEyZTliN2dvVTh5Mk5kUzVoeklyOC5cbiAqIFBsZWFzZSBjb250YWN0IHlvdXIgc3lzdGVtIGFkbWluaXN0cmF0b3IuXG4gKiBBZGQgY29ycmVjdCBob3N0IGtleSBpbiAvVXNlcnMvdXNlcm5hbWUvLnNzaC9rbm93bl9ob3N0cyB0byBnZXQgcmlkIG9mIHRoaXMgbWVzc2FnZS5cbiAqIE9mZmVuZGluZyBFQ0RTQSBrZXkgaW4gL1VzZXJzL3VzZXJuYW1lLy5zc2gva25vd25faG9zdHM6MjhcbiAqIEVDRFNBIGhvc3Qga2V5IGZvciBlYzItMTItMzQtNTYtNzg5LnVzLXdlc3QtMi5jb21wdXRlLmFtYXpvbmF3cy5jb20gaGFzIGNoYW5nZWQgYW5kIHlvdSBoYXZlIHJlcXVlc3RlZCBzdHJpY3QgY2hlY2tpbmcuXG4gKiBIb3N0IGtleSB2ZXJpZmljYXRpb24gZmFpbGVkLlxuICogYGBgXG4gKlxuICogVGhpcyBpcyBkdWUgdG8gdGhlIHNlcnZlcidzIGZpbmdlcnByaW50IGNoYW5naW5nLiBXZSBjYW4gc2NydWIgdGhlIGZpbmdlcnByaW50IGZyb20gb3VyIHN5c3RlbSB3aXRoIGEgY29tbWFuZCBsaWtlOlxuICpcbiAqIGBgYFxuICogc3NoLWtleWdlbiAtUiAxMi4zNC41Ni43ODlcbiAqIGBgYFxuICpcbiAqL1xuZXhwb3J0IGNsYXNzIEJhc3Rpb25Ib3N0IGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgaW5zdGFuY2U6IGVjMi5JbnN0YW5jZTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogQmFzdGlvbkhvc3RQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCB7IHN0YWNrTmFtZSB9ID0gU3RhY2sub2YodGhpcyk7XG5cbiAgICAvLyBCdWlsZCBlYzIgaW5zdGFuY2VcbiAgICB0aGlzLmluc3RhbmNlID0gbmV3IGVjMi5JbnN0YW5jZSh0aGlzLCBcImJhc3Rpb24taG9zdFwiLCB7XG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICAgIHZwY1N1Ym5ldHM6IHsgc3VibmV0VHlwZTogZWMyLlN1Ym5ldFR5cGUuUFVCTElDIH0sXG4gICAgICBpbnN0YW5jZU5hbWU6IGAke3N0YWNrTmFtZX0gYmFzdGlvbiBob3N0YCxcbiAgICAgIGluc3RhbmNlVHlwZTogZWMyLkluc3RhbmNlVHlwZS5vZihcbiAgICAgICAgZWMyLkluc3RhbmNlQ2xhc3MuQlVSU1RBQkxFNF9HUkFWSVRPTixcbiAgICAgICAgZWMyLkluc3RhbmNlU2l6ZS5OQU5PXG4gICAgICApLFxuICAgICAgbWFjaGluZUltYWdlOiBlYzIuTWFjaGluZUltYWdlLmxhdGVzdEFtYXpvbkxpbnV4KHtcbiAgICAgICAgZ2VuZXJhdGlvbjogZWMyLkFtYXpvbkxpbnV4R2VuZXJhdGlvbi5BTUFaT05fTElOVVhfMixcbiAgICAgICAgY3B1VHlwZTogZWMyLkFtYXpvbkxpbnV4Q3B1VHlwZS5BUk1fNjQsXG4gICAgICB9KSxcbiAgICAgIHVzZXJEYXRhOiBwcm9wcy51c2VyRGF0YSxcbiAgICAgIHVzZXJEYXRhQ2F1c2VzUmVwbGFjZW1lbnQ6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyBBc3NpZ24gZWxhc3RpYyBJUFxuICAgIGlmIChwcm9wcy5jcmVhdGVFbGFzdGljSXAgPz8gdHJ1ZSkge1xuICAgICAgbmV3IGVjMi5DZm5FSVAodGhpcywgXCJJUFwiLCB7XG4gICAgICAgIGluc3RhbmNlSWQ6IHRoaXMuaW5zdGFuY2UuaW5zdGFuY2VJZCxcbiAgICAgICAgdGFnczogW3sga2V5OiBcIk5hbWVcIiwgdmFsdWU6IHN0YWNrTmFtZSB9XSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEFsbG93IGJhc3Rpb24gaG9zdCB0byBjb25uZWN0IHRvIGRiXG4gICAgdGhpcy5pbnN0YW5jZS5jb25uZWN0aW9ucy5hbGxvd1RvKFxuICAgICAgcHJvcHMuZGIuY29ubmVjdGlvbnMuc2VjdXJpdHlHcm91cHNbMF0sXG4gICAgICBlYzIuUG9ydC50Y3AoNTQzMiksXG4gICAgICBcIkFsbG93IGNvbm5lY3Rpb24gZnJvbSBiYXN0aW9uIGhvc3RcIlxuICAgICk7XG5cbiAgICAvLyBBbGxvdyBJUCBhY2Nlc3MgdG8gYmFzdGlvbiBob3N0XG4gICAgZm9yIChjb25zdCBpcHY0IG9mIHByb3BzLmlwdjRBbGxvd2xpc3QpIHtcbiAgICAgIHRoaXMuaW5zdGFuY2UuY29ubmVjdGlvbnMuYWxsb3dGcm9tKFxuICAgICAgICBlYzIuUGVlci5pcHY0KGlwdjQpLFxuICAgICAgICBlYzIuUG9ydC50Y3AocHJvcHMuc3NoUG9ydCB8fCAyMiksXG4gICAgICAgIFwiU1NIIEFjY2Vzc1wiXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEludGVncmF0ZSB3aXRoIFNTTVxuICAgIHRoaXMuaW5zdGFuY2UuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgXCJzc21tZXNzYWdlczoqXCIsXG4gICAgICAgICAgXCJzc206VXBkYXRlSW5zdGFuY2VJbmZvcm1hdGlvblwiLFxuICAgICAgICAgIFwiZWMybWVzc2FnZXM6KlwiLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICB9KVxuICAgICk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwiaW5zdGFuY2UtaWQtb3V0cHV0XCIsIHtcbiAgICAgIHZhbHVlOiB0aGlzLmluc3RhbmNlLmluc3RhbmNlSWQsXG4gICAgICBleHBvcnROYW1lOiBgJHtzdGFja05hbWV9LWluc3RhbmNlLWlkYCxcbiAgICB9KTtcbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIFwiaW5zdGFuY2UtcHVibGljLWlwLW91dHB1dFwiLCB7XG4gICAgICB2YWx1ZTogdGhpcy5pbnN0YW5jZS5pbnN0YW5jZVB1YmxpY0lwLFxuICAgICAgZXhwb3J0TmFtZTogYCR7c3RhY2tOYW1lfS1pbnN0YW5jZS1wdWJsaWMtaXBgLFxuICAgIH0pO1xuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgXCJpbnN0YW5jZS1wdWJsaWMtZG5zLW5hbWUtb3V0cHV0XCIsIHtcbiAgICAgIHZhbHVlOiB0aGlzLmluc3RhbmNlLmluc3RhbmNlUHVibGljRG5zTmFtZSxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3N0YWNrTmFtZX0tcHVibGljLWRucy1uYW1lYCxcbiAgICB9KTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhc3Rpb25Ib3N0UHJvcHMge1xuICByZWFkb25seSB2cGM6IGVjMi5JVnBjO1xuICByZWFkb25seSBkYjogcmRzLklEYXRhYmFzZUluc3RhbmNlO1xuICByZWFkb25seSB1c2VyRGF0YTogZWMyLlVzZXJEYXRhO1xuICByZWFkb25seSBpcHY0QWxsb3dsaXN0OiBzdHJpbmdbXTtcbiAgcmVhZG9ubHkgc3NoUG9ydD86IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciBvciBub3QgYW4gZWxhc3RpYyBJUCBzaG91bGQgYmUgY3JlYXRlZCBmb3IgdGhlIGJhc3Rpb24gaG9zdC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGNyZWF0ZUVsYXN0aWNJcD86IGJvb2xlYW47XG59XG4iXX0=
@@ -17,6 +17,9 @@ from pypgstac.migrate import Migrate
17
17
  logger = logging.getLogger("eoapi-bootstrap")
18
18
 
19
19
 
20
+ DEFAULT_PG_CRON_SCHEDULE = "*/10 * * * *" # every 10 minutes
21
+
22
+
20
23
  def send(
21
24
  event,
22
25
  context,
@@ -143,30 +146,151 @@ def register_extensions(cursor) -> None:
143
146
  ###############################################################################
144
147
  # PgSTAC Customization
145
148
  ###############################################################################
146
- def customization(cursor, params) -> None:
149
+ def _is_enabled(params: dict, key: str) -> bool:
150
+ """Parse a string boolean CloudFormation custom resource property.
151
+
152
+ CloudFormation custom resource properties are always strings, so boolean
153
+ flags are passed as ``"TRUE"`` or ``"FALSE"``. Callers must check that the
154
+ key is present before calling this function; absent keys are a no-op and
155
+ should not reach this function.
156
+
157
+ Args:
158
+ params: ResourceProperties dict from the CloudFormation event.
159
+ key: Property name to look up.
160
+
161
+ Returns:
162
+ True if the property value is ``"TRUE"`` (case-insensitive).
147
163
  """
148
- CUSTOMIZED YOUR PGSTAC DATABASE
164
+ return str(params.get(key, "FALSE")).upper() == "TRUE"
165
+
166
+
167
+ def _apply_pgstac_setting(cursor, name: str, enabled: bool) -> None:
168
+ """Upsert or delete a row in the pgstac_settings table.
169
+
170
+ When ``enabled`` is True, upserts ``'on'``. When False, deletes the row so
171
+ pgstac reverts to its built-in default. When the setting is absent from
172
+ params entirely, this function should not be called — absent means no-op.
173
+
174
+ Args:
175
+ cursor: Database cursor with ``search_path`` including the pgstac schema.
176
+ name: Setting name (primary key in pgstac_settings).
177
+ enabled: Whether to enable or disable the setting.
178
+ """
179
+ if enabled:
180
+ cursor.execute(
181
+ sql.SQL(
182
+ "INSERT INTO pgstac_settings (name, value) VALUES ({name}, 'on') "
183
+ "ON CONFLICT ON CONSTRAINT pgstac_settings_pkey DO UPDATE SET value = excluded.value;"
184
+ ).format(name=sql.Literal(name))
185
+ )
186
+ else:
187
+ cursor.execute(
188
+ sql.SQL("DELETE FROM pgstac_settings WHERE name = {name};").format(
189
+ name=sql.Literal(name)
190
+ )
191
+ )
192
+
193
+
194
+ def customization(cursor, params) -> None:
195
+ """Apply pgSTAC database customizations based on the provided params.
196
+
197
+ Each setting follows honest boolean semantics:
198
+
199
+ - ``"TRUE"`` → enable (upsert ``'on'`` in pgstac_settings)
200
+ - ``"FALSE"`` → disable (delete from pgstac_settings, reverting to pgstac default)
201
+ - absent → no-op (the database is left exactly as-is)
202
+
203
+ This means the flags are safe to use as true booleans, and upgrading without
204
+ changing config never silently alters a manually-managed setting.
149
205
 
150
206
  ref: https://github.com/stac-utils/pgstac/blob/main/docs/src/pgstac.md
207
+ """
208
+ if "context" in params:
209
+ _apply_pgstac_setting(cursor, "context", _is_enabled(params, "context"))
210
+
211
+ if "mosaic_index" in params:
212
+ if _is_enabled(params, "mosaic_index"):
213
+ cursor.execute(
214
+ sql.SQL(
215
+ "CREATE INDEX IF NOT EXISTS searches_mosaic ON searches ((true)) "
216
+ "WHERE metadata->>'type'='mosaic';"
217
+ )
218
+ )
219
+ else:
220
+ cursor.execute(sql.SQL("DROP INDEX IF EXISTS searches_mosaic;"))
221
+
222
+ # Enable automatic spatial/temporal extent updates on item ingest.
223
+ # For large ingests, combine with use_queue=TRUE to reduce transaction overhead.
224
+ if "update_collection_extent" in params:
225
+ _apply_pgstac_setting(
226
+ cursor,
227
+ "update_collection_extent",
228
+ _is_enabled(params, "update_collection_extent"),
229
+ )
230
+
231
+ # Enable asynchronous queue processing for extent updates.
232
+ # Requires pg_cron to periodically invoke CALL pgstac.run_queued_queries().
233
+ if "use_queue" in params:
234
+ _apply_pgstac_setting(cursor, "use_queue", _is_enabled(params, "use_queue"))
235
+
236
+
237
+ def unregister_pg_cron(cursor) -> None:
238
+ """Remove the run_queued_queries pg_cron job if it exists.
239
+
240
+ Safe to call even if pg_cron is not installed or the job does not exist.
151
241
 
242
+ Args:
243
+ cursor: Database cursor connected to the ``postgres`` database as a superuser.
152
244
  """
153
- if str(params.get("context", "FALSE")).upper() == "TRUE":
154
- # Add CONTEXT=ON
155
- pgstac_settings = """
156
- INSERT INTO pgstac_settings (name, value)
157
- VALUES ('context', 'on')
158
- ON CONFLICT ON CONSTRAINT pgstac_settings_pkey DO UPDATE SET value = excluded.value;"""
159
- cursor.execute(sql.SQL(pgstac_settings))
160
-
161
- if str(params.get("mosaic_index", "TRUE")).upper() == "TRUE":
162
- # Create index of searches with `mosaic`` type
245
+ cursor.execute(sql.SQL("SELECT 1 FROM pg_extension WHERE extname = 'pg_cron';"))
246
+ if cursor.fetchone():
163
247
  cursor.execute(
164
248
  sql.SQL(
165
- "CREATE INDEX IF NOT EXISTS searches_mosaic ON searches ((true)) WHERE metadata->>'type'='mosaic';"
249
+ "SELECT cron.unschedule(jobid) FROM cron.job "
250
+ "WHERE jobname = 'pgstac-run-queued-queries';"
166
251
  )
167
252
  )
168
253
 
169
254
 
255
+ def register_pg_cron(cursor, db_name: str, schedule: str) -> None:
256
+ """Install the pg_cron extension and schedule run_queued_queries.
257
+
258
+ pg_cron can only be installed in the ``postgres`` database, so the cursor
259
+ must be connected there as a superuser. ``cron.schedule_in_database`` is
260
+ used to run the job against the pgSTAC database. The job is upserted by
261
+ name so repeated bootstrap runs are safe.
262
+
263
+ pg_cron must be listed in ``shared_preload_libraries`` in the RDS parameter
264
+ group before this will succeed.
265
+
266
+ Side effect: sets ``search_path = pgstac, public`` as the default for all
267
+ connections to ``db_name`` via ``ALTER DATABASE``. This is required because
268
+ pg_cron background worker sessions start with no ``search_path``, and
269
+ prepending ``SET search_path`` to the cron command would open a transaction
270
+ that prevents ``run_queued_queries()`` from issuing its own ``COMMIT``.
271
+
272
+ Args:
273
+ cursor: Database cursor connected to the ``postgres`` database as a superuser.
274
+ db_name: Name of the pgSTAC database where run_queued_queries will run.
275
+ schedule: Cron schedule expression (e.g. ``"*/5 * * * *"``).
276
+ """
277
+ cursor.execute(sql.SQL("CREATE EXTENSION IF NOT EXISTS pg_cron;"))
278
+ cursor.execute(
279
+ sql.SQL("ALTER DATABASE {db_name} SET search_path TO pgstac, public;").format(
280
+ db_name=sql.Identifier(db_name),
281
+ )
282
+ )
283
+ cursor.execute(
284
+ sql.SQL(
285
+ "SELECT cron.schedule_in_database({job_name}, {schedule}, 'CALL pgstac.run_queued_queries();', {db_name});"
286
+ ).format(
287
+ job_name=sql.Literal("pgstac-run-queued-queries"),
288
+ schedule=sql.Literal(schedule),
289
+ db_name=sql.Literal(db_name),
290
+ )
291
+ )
292
+
293
+
170
294
  def handler(event, context):
171
295
  """Lambda Handler."""
172
296
  print(f"Handling {event}")
@@ -213,6 +337,26 @@ def handler(event, context):
213
337
  password=eoapi_params["password"],
214
338
  )
215
339
 
340
+ if "use_queue" in params:
341
+ if _is_enabled(params, "use_queue"):
342
+ schedule = params.get(
343
+ "pg_cron_schedule", DEFAULT_PG_CRON_SCHEDULE
344
+ )
345
+ print(
346
+ f"Scheduling pg_cron job 'pgstac-run-queued-queries' "
347
+ f"with schedule '{schedule}'..."
348
+ )
349
+ register_pg_cron(
350
+ cursor=cur,
351
+ db_name=eoapi_params["dbname"],
352
+ schedule=schedule,
353
+ )
354
+ else:
355
+ print(
356
+ "Removing pg_cron job 'pgstac-run-queued-queries' if present..."
357
+ )
358
+ unregister_pg_cron(cursor=cur)
359
+
216
360
  # Install postgis and pgstac on the eoapi database with
217
361
  # superuser permissions
218
362
  print(f"Connecting to eoAPI '{eoapi_params['dbname']}' database...")
@@ -127,10 +127,42 @@ export interface PgStacDatabaseProps extends rds.DatabaseInstanceProps {
127
127
  */
128
128
  readonly maintenanceWindow?: ssm.CfnMaintenanceWindow;
129
129
  /**
130
- * Lambda function Custom Resource properties. A custom resource property is going to be created
131
- * to trigger the boostrapping lambda function. This parameter allows the user to specify additional properties
132
- * on top of the defaults ones.
133
- *
130
+ * Additional properties passed to the bootstrapper Lambda as CloudFormation
131
+ * Custom Resource properties. These are merged with the defaults and forwarded
132
+ * to the handler as `event["ResourceProperties"]`.
133
+ *
134
+ * ## Supported pgSTAC settings
135
+ *
136
+ * Each setting follows honest boolean semantics: `"TRUE"` enables, `"FALSE"`
137
+ * disables (reverts to pgSTAC's built-in default), and omitting the key
138
+ * entirely is a no-op — the database is left as-is. This means upgrading
139
+ * without changing config never silently alters a manually-managed setting.
140
+ *
141
+ * | Property | Default | Description |
142
+ * |----------------------------|----------|-------------|
143
+ * | `context` | (unset) | Enable `CONTEXT=ON` in pgSTAC (item count on search). |
144
+ * | `mosaic_index` | `"TRUE"` | Create a partial index on searches of type `mosaic`. Set `"FALSE"` to drop it. |
145
+ * | `update_collection_extent` | (unset) | Automatically update collection spatial/temporal extents on item ingest. Combine with `use_queue` to reduce per-transaction overhead. |
146
+ * | `use_queue` | (unset) | Process extent updates asynchronously via an internal queue. `"TRUE"` installs pg_cron and schedules the drain job; `"FALSE"` removes the job. Requires `pg_cron` (see below). |
147
+ * | `pg_cron_schedule` | `"*\/10 * * * *"` | Cron schedule for `CALL run_queued_queries()`. Only used when `use_queue` is `"TRUE"`. |
148
+ *
149
+ * ## pg_cron requirement
150
+ *
151
+ * When `use_queue` is `"TRUE"`, the bootstrapper installs the `pg_cron`
152
+ * extension and schedules a job to periodically drain the queue.
153
+ * `pg_cron` must be present in `shared_preload_libraries` **before**
154
+ * deployment or the bootstrap will fail. Add it via `props.parameters`:
155
+ *
156
+ * ```
157
+ * parameters: { shared_preload_libraries: "pg_cron" }
158
+ * ```
159
+ *
160
+ * @example
161
+ * customResourceProperties: {
162
+ * update_collection_extent: "TRUE",
163
+ * use_queue: "TRUE",
164
+ * pg_cron_schedule: "*\/10 * * * *",
165
+ * }
134
166
  */
135
167
  readonly customResourceProperties?: {
136
168
  [key: string]: any;