Compare commits

..

24 commits

Author SHA1 Message Date
dependabot[bot]
be7533da09
Bump react-native-haptic-feedback from 2.3.4 to 3.0.0 in /mobile
Bumps [react-native-haptic-feedback](https://github.com/mkuczera/react-native-haptic-feedback) from 2.3.4 to 3.0.0.
- [Release notes](https://github.com/mkuczera/react-native-haptic-feedback/releases)
- [Changelog](https://github.com/mkuczera/react-native-haptic-feedback/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkuczera/react-native-haptic-feedback/compare/v2.3.4...v3.0.0)

---
updated-dependencies:
- dependency-name: react-native-haptic-feedback
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 22:43:07 +00:00
Adam Moussa
68f77a6c0a Add missing RN CLI deps, exclude mobile from AWS deploy
react-native 0.79 requires @react-native-community/cli as an
explicit dev dependency for CocoaPods autolinking. Also adds
paths-ignore for mobile/ on the AWS deploy workflow so mobile-only
changes don't trigger unnecessary infrastructure deploys.
2026-05-18 18:42:36 -04:00
dependabot[bot]
ed6aed9aa7
Bump react-native from 0.79.7 to 0.85.3 in /mobile (#35)
Bumps [react-native](https://github.com/facebook/react-native/tree/HEAD/packages/react-native) from 0.79.7 to 0.85.3.
- [Release notes](https://github.com/facebook/react-native/releases)
- [Changelog](https://github.com/facebook/react-native/blob/main/CHANGELOG-0.7x.md)
- [Commits](https://github.com/facebook/react-native/commits/v0.85.3/packages/react-native)

---
updated-dependencies:
- dependency-name: react-native
  dependency-version: 0.85.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:40:56 +00:00
Adam Moussa
e64da7ecd7 Revert babel-preset to 0.79 to match React Native version
Dependabot bumped @react-native/babel-preset from 0.79 to 0.85,
which is incompatible with react-native 0.79. The 0.85 preset
expects CLI infrastructure that doesn't exist in 0.79, breaking
pod install during the mobile deploy.
2026-05-18 18:38:03 -04:00
Adam Moussa
e96c80c78a Add OIDC permissions to mobile deploy workflow
Startup failure — caller workflow needs id-token: write for the
reusable workflow's OIDC credential step to function.
2026-05-18 18:35:00 -04:00
Adam Moussa
28475d8529 Revert suggestions log group from foundation stack
The log group already exists — created by the compute stack's
logRetention setting on the suggestions Lambda. Adding it to the
foundation stack caused a duplicate resource error on deploy.
2026-05-18 18:32:04 -04:00
Adam Moussa
fdaaf5ed4a Fix compliance violations: Lambda defaults, CI node-version, dead code
oss-index-creator Lambda was missing functionName, arm64 architecture,
and explicit log retention — all required by the engineering handbook.
CI workflow was not passing node-version to reusable workflows, risking
drift. Removed unused _api_request helper from all four main Lambdas.
Added missing suggestions log group to foundation stack.
2026-05-18 18:28:31 -04:00
dependabot[bot]
69c989847f
Update requests-aws4auth requirement in /lambdas/oss-index-creator (#41)
Updates the requirements on [requests-aws4auth](https://github.com/tedder/requests-aws4auth) to permit the latest version.
- [Release notes](https://github.com/tedder/requests-aws4auth/releases)
- [Changelog](https://github.com/tedder/requests-aws4auth/blob/main/HISTORY.md)
- [Commits](https://github.com/tedder/requests-aws4auth/compare/v1.2.0...v1.3.2)

---
updated-dependencies:
- dependency-name: requests-aws4auth
  dependency-version: 1.3.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:14:39 +00:00
dependabot[bot]
d38049a6ca
Update httpx requirement in /lambdas/suggestions (#46)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:13:16 +00:00
dependabot[bot]
8c692c7477
Update boto3 requirement in /lambdas/pdf-extract (#44)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:28 +00:00
dependabot[bot]
4444eeb678
Update boto3 requirement in /lambdas/pdf-generate (#43)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:20 +00:00
dependabot[bot]
b7ab9ccc9d
Bump @tanstack/react-query from 5.100.10 to 5.100.11 in /web (#42)
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.10 to 5.100.11.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.11/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:14 +00:00
dependabot[bot]
c3a0868d2f
Update boto3 requirement in /lambdas/library-ingest (#45)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:12 +00:00
Adam Moussa
7dd66caf61 Add missing dependabot entry for lambdas/suggestions 2026-05-18 18:12:02 -04:00
dependabot[bot]
c14d7c2f55
Update requests requirement in /lambdas/oss-index-creator (#40)
Updates the requirements on [requests](https://github.com/psf/requests) to permit the latest version.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.31.0...v2.34.2)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.34.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:11:56 +00:00
dependabot[bot]
d40a58a943
Update opensearch-py requirement in /lambdas/oss-index-creator (#39)
Updates the requirements on [opensearch-py](https://github.com/opensearch-project/opensearch-py) to permit the latest version.
- [Release notes](https://github.com/opensearch-project/opensearch-py/releases)
- [Changelog](https://github.com/opensearch-project/opensearch-py/blob/main/CHANGELOG.md)
- [Commits](https://github.com/opensearch-project/opensearch-py/compare/v2.4.0...v3.2.0)

---
updated-dependencies:
- dependency-name: opensearch-py
  dependency-version: 3.2.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:11:54 +00:00
Adam Moussa
ef8a3b5f48 Clean up oss-index-creator: remove debug logging, update docs
- Remove verbose print statements from Lambda handler
- Add dependabot pip entry for oss-index-creator
- Update README with new Lambda and deployed stack state
2026-05-18 18:10:35 -04:00
Adam Moussa
7df81b4427 Fix AOSS dependency ordering: pre-create vector index via Custom Resource
Some checks are pending
Deploy / Deploy to AWS (push) Waiting to run
The Bedrock Knowledge Base creation was failing with 403/404 because
the OpenSearch Serverless data access policy hadn't propagated before
the KB tried to connect. Adds a CDK Custom Resource (using opensearch-py)
that creates the vector index with retry logic, ensuring the full
dependency chain: Collection → DataAccessPolicy → Index → KnowledgeBase.
2026-05-18 17:55:03 -04:00
dependabot[bot]
3250d4d927
Bump Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.11 to 8.0.27 (#37)
---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:37:30 +00:00
Adam Moussa
6263551b02 Fix deploy workflow: add permissions for OIDC token
Caller must declare id-token: write for the reusable workflow's
OIDC authentication to function.
2026-05-18 15:32:15 -04:00
dependabot[bot]
7b4a909751
Bump @react-native/babel-preset from 0.79.7 to 0.85.3 in /mobile (#33)
Bumps [@react-native/babel-preset](https://github.com/facebook/react-native) from 0.79.7 to 0.85.3.
- [Release notes](https://github.com/facebook/react-native/releases)
- [Changelog](https://github.com/facebook/react-native/blob/main/CHANGELOG-0.7x.md)
- [Commits](https://github.com/facebook/react-native/compare/v0.79.7...v0.85.3)

---
updated-dependencies:
- dependency-name: "@react-native/babel-preset"
  dependency-version: 0.85.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:32:13 +00:00
dependabot[bot]
cc7dfa3d07
Update httpx requirement in /lambdas/pdf-generate (#32)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:32:05 +00:00
dependabot[bot]
9994be3fed
Update httpx requirement in /lambdas/pdf-extract (#28)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:31:56 +00:00
dependabot[bot]
923b6a4712
Update httpx requirement in /lambdas/library-ingest (#25)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:31:41 +00:00
21 changed files with 2982 additions and 991 deletions

View file

@ -56,6 +56,20 @@ updates:
open-pull-requests-limit: 3
- package-ecosystem: pip
directory: /lambdas/suggestions
schedule:
interval: weekly
open-pull-requests-limit: 3
- package-ecosystem: pip
directory: /lambdas/oss-index-creator
schedule:
interval: weekly
open-pull-requests-limit: 3
- package-ecosystem: github-actions
directory: /
schedule:

View file

@ -21,6 +21,7 @@ jobs:
with:
working-directory: web
cache-dependency-path: web/package-lock.json
node-version: "24"
run-cdk-synth: false
run-conventions-check: false
@ -38,6 +39,7 @@ jobs:
with:
working-directory: mobile
cache-dependency-path: mobile/package-lock.json
node-version: "24"
run-cdk-synth: false
run-conventions-check: false
@ -47,6 +49,7 @@ jobs:
with:
working-directory: infra
cache-dependency-path: infra/package-lock.json
node-version: "24"
dotnet-version: "8.0.x"
dotnet-publish-project: api/src/ProposalSystem.Api/ProposalSystem.Api.csproj
run-typecheck: false

View file

@ -12,6 +12,10 @@ concurrency:
group: deploy-mobile
cancel-in-progress: false
permissions:
id-token: write
contents: read
jobs:
deploy-ios:
name: Build & Upload to TestFlight

View file

@ -3,11 +3,17 @@ name: Deploy
on:
push:
branches: [main]
paths-ignore:
- "mobile/**"
concurrency:
group: deploy-backend
cancel-in-progress: false
permissions:
id-token: write
contents: read
jobs:
deploy:
name: Deploy to AWS

View file

@ -9,7 +9,7 @@ Monorepo with five primary services:
- **.NET 8 API** -- Clean Architecture REST API hosted on Lambda behind API Gateway
- **React 19 Web** -- MUI v7 admin/dispatcher workspace served via CloudFront + S3
- **React Native Mobile** -- iOS-first field app for dispatchers (offline-capable)
- **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions
- **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions, AOSS index provisioning
- **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources
## Repository Structure
@ -41,12 +41,12 @@ proposal-system/
## AWS Resources
All resources are in **us-east-1** (account 328440206208). CDK stacks are defined but not yet deployed to AWS.
All resources are in **us-east-1** (account 328440206208).
| CDK Stack | Key Resources |
|---|---|
| `proposal-system-foundation` | RDS PostgreSQL 15 (t4g.small), S3 buckets, SQS queue + DLQ, Cognito user pool, Secrets Manager |
| `proposal-system-compute` | API Gateway HTTP API, .NET 8 API Lambda, Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions), Bedrock KB |
| `proposal-system-compute` | API Gateway HTTP API, .NET 8 API Lambda, Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions, oss-index-creator), OpenSearch Serverless collection, Bedrock KB |
| `proposal-system-frontend` | CloudFront distribution (S3 OAC) |
| Resource Type | Names |

View file

@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.27" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.27" />
</ItemGroup>
</Project>

View file

@ -12,6 +12,7 @@ import * as lambdaEventSources from 'aws-cdk-lib/aws-lambda-event-sources';
import * as bedrock from 'aws-cdk-lib/aws-bedrock';
import * as opensearchserverless from 'aws-cdk-lib/aws-opensearchserverless';
import * as logs from 'aws-cdk-lib/aws-logs';
import * as cr from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs';
export interface ComputeStackProps extends cdk.StackProps {
@ -90,8 +91,31 @@ export class ComputeStack extends cdk.Stack {
resources: [`arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0`],
}));
// OpenSearch Serverless data access policy
new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', {
// Lambda to pre-create the vector index (retries until AOSS access policy propagates)
const indexCreatorFn = new lambda.Function(this, 'OssIndexCreator', {
functionName: 'proposal-system-oss-index-creator',
runtime: lambda.Runtime.PYTHON_3_12,
architecture: lambda.Architecture.ARM_64,
handler: 'app.handler',
code: lambda.Code.fromAsset('../lambdas/oss-index-creator', {
bundling: {
image: lambda.Runtime.PYTHON_3_12.bundlingImage,
command: [
'bash', '-c',
'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output',
],
},
}),
timeout: cdk.Duration.minutes(6),
logRetention: logs.RetentionDays.TWO_MONTHS,
});
indexCreatorFn.addToRolePolicy(new iam.PolicyStatement({
actions: ['aoss:APIAccessAll'],
resources: [ossCollection.attrArn],
}));
const ossDataAccessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', {
name: 'proposal-system-kb-access',
type: 'data',
policy: JSON.stringify([{
@ -99,11 +123,27 @@ export class ComputeStack extends cdk.Stack {
{ ResourceType: 'collection', Resource: ['collection/proposal-system-kb'], Permission: ['aoss:*'] },
{ ResourceType: 'index', Resource: ['index/proposal-system-kb/*'], Permission: ['aoss:*'] },
],
Principal: [kbRole.roleArn, `arn:aws:iam::${this.account}:root`],
Principal: [kbRole.roleArn, indexCreatorFn.role!.roleArn],
}]),
});
ossDataAccessPolicy.addDependency(ossCollection);
const indexProvider = new cr.Provider(this, 'OssIndexProvider', {
onEventHandler: indexCreatorFn,
});
const ossIndex = new cdk.CustomResource(this, 'OssIndex', {
serviceToken: indexProvider.serviceToken,
properties: {
Endpoint: ossCollection.attrCollectionEndpoint,
IndexName: 'proposal-system-index',
VectorField: 'embedding',
TextField: 'text',
MetadataField: 'metadata',
},
});
ossIndex.node.addDependency(ossDataAccessPolicy);
// Bedrock Knowledge Base
const knowledgeBase = new bedrock.CfnKnowledgeBase(this, 'KnowledgeBase', {
name: 'proposal-system-kb',
roleArn: kbRole.roleArn,
@ -126,6 +166,7 @@ export class ComputeStack extends cdk.Stack {
},
},
});
knowledgeBase.node.addDependency(ossIndex);
// KB Data Source (S3 library bucket)
const dataSource = new bedrock.CfnDataSource(this, 'KbDataSource', {

View file

@ -8,7 +8,6 @@ then triggers a KB sync.
import json
import logging
import os
import time
from datetime import datetime
import boto3
@ -199,27 +198,3 @@ def _api_headers() -> dict:
if api_key:
headers["X-Internal-Api-Key"] = api_key
return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,2 +1,2 @@
boto3>=1.43.9,<2.0
httpx>=0.27.0,<1.0
boto3>=1.43.10,<2.0
httpx>=0.28.1,<1.0

View file

@ -0,0 +1,71 @@
import time
import boto3
from opensearchpy import OpenSearch, RequestsHttpConnection
from requests_aws4auth import AWS4Auth
def handler(event, context):
if event["RequestType"] == "Delete":
return {"PhysicalResourceId": event.get("PhysicalResourceId", "none")}
props = event["ResourceProperties"]
endpoint = props["Endpoint"].replace("https://", "")
index_name = props["IndexName"]
vector_field = props["VectorField"]
text_field = props["TextField"]
metadata_field = props["MetadataField"]
session = boto3.Session()
credentials = session.get_credentials().get_frozen_credentials()
region = session.region_name
awsauth = AWS4Auth(
credentials.access_key,
credentials.secret_key,
region,
"aoss",
session_token=credentials.token,
)
client = OpenSearch(
hosts=[{"host": endpoint, "port": 443}],
http_auth=awsauth,
use_ssl=True,
verify_certs=True,
connection_class=RequestsHttpConnection,
timeout=30,
)
index_body = {
"settings": {"index": {"knn": True, "knn.algo_param.ef_search": 512}},
"mappings": {
"properties": {
vector_field: {
"type": "knn_vector",
"dimension": 1024,
"method": {
"engine": "faiss",
"name": "hnsw",
"space_type": "l2",
},
},
text_field: {"type": "text"},
metadata_field: {"type": "text"},
}
},
}
for attempt in range(30):
try:
client.indices.create(index=index_name, body=index_body)
return {"PhysicalResourceId": index_name}
except Exception as e:
error_str = str(e)
if "resource_already_exists_exception" in error_str:
return {"PhysicalResourceId": index_name}
if "403" in error_str and attempt < 29:
time.sleep(10)
continue
raise
raise Exception("Timeout waiting for AOSS access policy propagation")

View file

@ -0,0 +1,3 @@
opensearch-py>=3.2.0
requests-aws4auth>=1.3.2
requests>=2.34.2

View file

@ -9,7 +9,6 @@ import json
import logging
import os
import tempfile
import time
import boto3
import httpx
@ -339,27 +338,3 @@ def _api_headers() -> dict:
if api_key:
headers["X-Internal-Api-Key"] = api_key
return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,3 +1,3 @@
pdfplumber>=0.11.9,<1.0
boto3>=1.43.9,<2.0
httpx>=0.27.0,<1.0
boto3>=1.43.10,<2.0
httpx>=0.28.1,<1.0

View file

@ -7,7 +7,6 @@ Triggered via SQS when an admin requests PDF generation.
import json
import logging
import os
import time
from datetime import datetime
from io import BytesIO
@ -543,27 +542,3 @@ def _api_headers() -> dict:
if api_key:
headers["X-Internal-Api-Key"] = api_key
return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,3 +1,3 @@
reportlab>=4.5.1,<5.0
boto3>=1.43.9,<2.0
httpx>=0.27.0,<1.0
boto3>=1.43.10,<2.0
httpx>=0.28.1,<1.0

View file

@ -7,7 +7,6 @@ to generate line item suggestions for new proposals.
import json
import logging
import os
import time
import boto3
import httpx
@ -320,27 +319,3 @@ def _api_headers() -> dict:
if api_key:
headers["X-Internal-Api-Key"] = api_key
return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,2 +1,2 @@
boto3>=1.35.0,<2.0
httpx>=0.27.0,<1.0
httpx>=0.28.1,<1.0

3624
mobile/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@
"@tanstack/react-query": "^5.100.10",
"axios": "^1.16.0",
"react": "^19.0.0",
"react-native": "^0.79.0",
"react-native": "^0.85.3",
"react-native-app-auth": "^8.0.0",
"react-native-document-picker": "^9.3.0",
"react-native-haptic-feedback": "^3.0.0",
@ -33,6 +33,8 @@
"react-redux": "^9.2.0"
},
"devDependencies": {
"@react-native-community/cli": "^20.1.3",
"@react-native-community/cli-platform-ios": "^20.1.3",
"@react-native/babel-preset": "^0.79.0",
"@react-native/metro-config": "^0.79.0",
"@types/react": "^19.0.0",

71
web/package-lock.json generated
View file

@ -13,7 +13,7 @@
"@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1",
"@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.100.10",
"@tanstack/react-query": "^5.100.11",
"axios": "^1.16.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
@ -1319,9 +1319,6 @@
"arm"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1336,9 +1333,6 @@
"arm"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1353,9 +1347,6 @@
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1370,9 +1361,6 @@
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1387,9 +1375,6 @@
"loong64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1404,9 +1389,6 @@
"loong64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1421,9 +1403,6 @@
"ppc64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1438,9 +1417,6 @@
"ppc64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1455,9 +1431,6 @@
"riscv64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1472,9 +1445,6 @@
"riscv64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1489,9 +1459,6 @@
"s390x"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1506,9 +1473,6 @@
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -1523,9 +1487,6 @@
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -1629,9 +1590,9 @@
"license": "MIT"
},
"node_modules/@tanstack/query-core": {
"version": "5.100.10",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.10.tgz",
"integrity": "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==",
"version": "5.100.11",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.11.tgz",
"integrity": "sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw==",
"license": "MIT",
"funding": {
"type": "github",
@ -1639,12 +1600,12 @@
}
},
"node_modules/@tanstack/react-query": {
"version": "5.100.10",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.10.tgz",
"integrity": "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==",
"version": "5.100.11",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.11.tgz",
"integrity": "sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg==",
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "5.100.10"
"@tanstack/query-core": "5.100.11"
},
"funding": {
"type": "github",
@ -3100,22 +3061,6 @@
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"license": "ISC"
},
"node_modules/yaml": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
"extraneous": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
}
}
}

View file

@ -14,7 +14,7 @@
"@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1",
"@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.100.10",
"@tanstack/react-query": "^5.100.11",
"axios": "^1.16.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",