From ebcc5baf5b351d12f2119c43d3bd3333676009dc Mon Sep 17 00:00:00 2001 From: Viserion77 Date: Thu, 30 Jul 2026 22:36:12 +0000 Subject: [PATCH 01/16] feat: Refactor engine handling and improve UI messaging - Introduced a new engine service to manage engine kind and labels. - Updated health check to apply engine kind based on server response. - Replaced deprecated localstack references with dynamic engine labels across UI components. - Enhanced descriptions in various views to reflect the active engine type. - Implemented pagination handling for DynamoDB and SQS resources to ensure complete data retrieval. - Added tests for new engine functionality and pagination logic. - Improved memory store tests to ensure isolation and reproducibility. --- README.md | 4 +- REVISAO-2026-07-29.md | 492 ++++++++++++++++++ bin/cli.js | 50 +- docs/CONFIGURATION.md | 61 ++- docs/FEATURES.md | 21 +- docs/SELF_ENGINE.md | 27 +- src/client/http.ts | 12 +- src/client/namespaces/queues.ts | 10 + src/server/dev/dynamo-proxy.ts | 9 + src/server/engine/backends/self-backend.ts | 4 + src/server/engine/store/engine-store.ts | 7 +- src/server/engine/store/memory-store.ts | 199 +++++++ src/server/engine/store/wal.ts | 36 +- src/server/index.ts | 52 +- src/server/routes/config.ts | 12 + src/server/routes/lambdas.ts | 4 + src/server/routes/services.ts | 3 + src/server/services/cache-manager.ts | 20 +- src/server/services/config-manager.ts | 78 ++- src/server/services/dynamo-explorer.ts | 30 +- src/server/services/explorer-region.ts | 23 + src/server/services/lambda-runtime-manager.ts | 134 ++++- src/server/services/opensearch-explorer.ts | 8 +- src/server/services/project-scope.ts | 24 + src/server/services/queue-inspector.ts | 13 +- src/server/services/resource-provisioner.ts | 24 +- src/server/services/secrets-explorer.ts | 8 +- src/server/services/seed-manager.ts | 13 +- src/server/services/source-watcher.ts | 39 +- src/ui/src/App.vue | 15 +- src/ui/src/components/QueuesView.vue | 3 +- src/ui/src/components/ServicesList.vue | 3 +- src/ui/src/components/buckets/BucketsView.vue | 3 +- src/ui/src/pages/OverviewPage.vue | 50 +- src/ui/src/pages/ServiceDetailPage.vue | 3 +- src/ui/src/services/api.ts | 15 + src/ui/src/services/engine.ts | 20 + tests/unit/cli/cli.test.ts | 31 ++ tests/unit/dev/dynamo-proxy.test.ts | 28 +- tests/unit/engine/dispatch/helpers.ts | 16 +- tests/unit/engine/store/item-table.test.ts | 33 ++ tests/unit/engine/store/memory-store.test.ts | 143 +++++ tests/unit/routes/lambdas.test.ts | 3 + tests/unit/services/config-manager.test.ts | 81 ++- tests/unit/services/dynamo-explorer.test.ts | 16 + tests/unit/services/explorer-region.test.ts | 38 ++ tests/unit/services/queue-inspector.test.ts | 17 + .../services/resource-provisioner.test.ts | 22 + tests/unit/services/seed-manager.test.ts | 11 + 49 files changed, 1838 insertions(+), 130 deletions(-) create mode 100644 REVISAO-2026-07-29.md create mode 100644 src/server/engine/store/memory-store.ts create mode 100644 src/server/services/explorer-region.ts create mode 100644 src/server/services/project-scope.ts create mode 100644 src/ui/src/services/engine.ts create mode 100644 tests/unit/engine/store/memory-store.test.ts create mode 100644 tests/unit/services/explorer-region.test.ts diff --git a/README.md b/README.md index 0384280..43f71a1 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,13 @@ LSS features come in two layers: - CloudFormation parsing from `sls package` → auto-provisions tables, queues (incl. `RedrivePolicy`), topics, buckets (incl. `CorsConfiguration`), secrets, EventBridge buses/rules, raw ApiGatewayV2 routes and OpenSearch collections - `autoPackage` — runs `sls package` on demand when the template is missing - Automatic event source mappings: SQS / DynamoDB streams / S3 notifications / EventBridge rules → Lambda — with AWS-faithful failure semantics (`FilterCriteria` enforced, `ReportBatchItemFailures` partial batches, `maximumRetryAttempts` incl. the `-1` "until the record ages out" default) - - Per-instance isolation — `stateDir` + port-scoped PID/log paths let many LSS instances coexist (one per project) + - Per-instance isolation — `stateDir` + port-scoped PID/log paths let many LSS instances coexist (one per project); with no `stateDir` the engine/aoss/artifact directories fall back to a **per-project** path under `~/.lss/projects/`, so two checkouts never share state + - Explorers honour the configured `region` when a caller omits `?region=`, and page through `ListTables`/`ListQueues` (400 tables list as 400, not the first 100) - Config: `lss.config.json` / `.lssrc` + env overrides (`LSS_*`); public-safe `GET /api/config` snapshot (never leaks the auth token); editable from the dashboard via `PUT /api/config` (writes the file for you to commit) + `POST /api/config/reload`; `GET /api/config/ports` lists every exposed port - **Lambda runtime & API Gateway emulation** (serverless-offline replacement — same `30xx`/`130xx` ports) - Function + route registry: REST (`http`, payload v1), HTTP API (`httpApi`, payload v2) and authorizers — persisted and rehydrated on restart - Per-service worker processes: lazy/warm handler loading, function env/timeout/context, per-invocation log capture, crash restart + - **Bounded memory by default**: `lambdaRuntime.lazy` forks a worker on the first invocation instead of at registration, `idleTimeoutMs` (60 s) unloads it once it goes quiet, and `maxWarmWorkers` (one per GB of RAM) caps how many may be resident at once — so host memory tracks the services *in flight*, not the services *registered*. Measured on 40 services / 400 lambdas / 400 tables: **2.0 GB → 128 MB** at rest, ~20 ms cold start per service used - Execution modes: `artifact` (extracted zip) · `source` (direct require/import; TS via native type-stripping → esbuild/tsx/ts-node) · `auto` - Lambda Invoke API on `130xx` (`X-Amz-Invocation-Type` RequestResponse/Event/DryRun, `X-Amz-Function-Error`) - API Gateway proxy on `30xx`: route precedence (literal > `{param}` > `{proxy+}` > `$default`, method > ANY), payload v1/v2, CORS preflight, `port-conflict` status diff --git a/REVISAO-2026-07-29.md b/REVISAO-2026-07-29.md new file mode 100644 index 0000000..217a09c --- /dev/null +++ b/REVISAO-2026-07-29.md @@ -0,0 +1,492 @@ +# Revisão do LSS — 2026-07-29 + +Documento de handoff. **Nada foi commitado**: tudo está na working tree para você revisar. +As duas primeiras seções são o que interessa se você tiver 5 minutos. + +--- + +## 1. Resumo executivo + +Subi o stack de verdade (exemplo `self-hosted`, engine self, sem Docker), dirigi o pipeline +ponta a ponta, rodei duas instâncias em paralelo e montei um projeto sintético de **40 serviços +× 400 lambdas × 400 tabelas** para medir o cenário que motiva o projeto. + +**O produto funciona.** O pipeline `POST /orders → DynamoDB → SQS → Lambda → S3 + EventBridge → +regra → Lambda → DynamoDB` roda inteiro em ~120 ms, o redrive para DLQ respeita +`maxReceiveCount`, OpenSearch responde busca e agregação, persistência sobrevive a restart e +duas instâncias paralelas ficam completamente isoladas. Boot em 2 s, registro de 40 serviços +em 0,9 s (22 ms cada), latência de API abaixo de 200 ms com 400 tabelas. + +**Mas havia quatro problemas que batem exatamente no seu caso de uso**, todos corrigidos: + +| # | Problema | Efeito no seu monolito de 40 OSLs | +|---|---|---| +| 1 | Um worker Node forkado **ansiosamente** por serviço registrado | **2,0 GB de RAM parada** antes de qualquer handler rodar | +| 2 | `ListTables` sem paginação (AWS corta em 100) | Das suas **400 tabelas, só 100 apareciam** no dashboard e na API | +| 3 | Explorers com região default `us-east-1` fixa | Projeto fora de us-east-1 → **API devolvia listas vazias** (o dashboard escapava; CLI/`LssClient`/curl não) | +| 4 | `persistence: false` era **no-op** no self engine | Sem clean slate para teste automatizado; deixava `.lss/engine/` para trás | + +Medição do antes/depois com 40 serviços registrados, ociosos: + +| | antes | depois | +|---|---|---| +| RSS total da instância | **2.020 MB** | **128 MB** (−94%) | +| processos worker | 40 | 0 parado; teto de `maxWarmWorkers` em uso | +| CPU ociosa | 4,1% | 0,3% | +| tabelas listadas (de 400) | 100 | 400 | +| cold start da 1ª invocação | — | **~23 ms** (morno: ~1 ms) | +| watches inotify por serviço | 1.756 | 4 | + +O gate `validate: pre-prod` passa inteiro: lint 0 erros, `tsc` nos 4 projetos, **2.405 testes +verdes com cobertura 100%**, build completo. + +--- + +## 2. Como reproduzir as medições + +```bash +# gerador do projeto sintético e runner (ficaram no scratchpad da sessão) +node gen-scale.js 40 10 10 3250 14766 # 40 svc × 10 lambdas × 10 tabelas +bash run-scale.sh 3250 40 # sobe, registra, mede RSS/CPU/latência +``` + +Os dois scripts estão em +`/tmp/claude-1000/-workspaces-local-serverless-stack/79e9e892-7e35-4e30-a18d-4130e4d5e996/scratchpad/`. +Se quiser mantê-los, o lugar natural é `tests/perf/` ou `scripts/` — hoje o repo não tem nenhum +harness de performance, e este é o tipo de número que precisa virar regressão vigiada +(ver §5, item "Sem harness de performance"). + +--- + +## 3. Alterações aplicadas + +Agrupadas por tema. Todas com teste e comentário explicando o *porquê*, no estilo da base. + +### 3.1 Escala — worker sob demanda (a mudança de maior impacto) + +**`src/server/services/lambda-runtime-manager.ts`, `config-manager.ts`, `routes/{lambdas,services}.ts`** + +`syncService()` forkava o worker no registro. Agora resolve onde os handlers moram (então um +artefato quebrado **continua falhando no registro**, não na primeira chamada) e deixa o fork +para o primeiro `invoke`. + +- `lambdaRuntime.lazy` — **default `true`**. `false` restaura o comportamento antigo. +- `lambdaRuntime.idleTimeoutMs` — **default `60000`** (1 min). Descarrega um worker que ficou + quieto; nunca interrompe invocação em voo. `0` mantém vivo para sempre. +- `lambdaRuntime.maxWarmWorkers` — **default: 1 por GB de RAM, limitado a 2..12**. Teto rígido + de workers residentes; ao estourar, descarrega o menos recentemente invocado. É o que garante + que a memória do host depende dos serviços **em uso**, não dos serviços **registrados** — uma + rajada que toca os 40 dentro da janela de ociosidade ainda estabiliza no teto. + +Medido no stack sintético de 40 serviços, com `maxWarmWorkers: 4` e `idleTimeoutMs: 8000`: + +| momento | workers | RSS | +|---|---|---| +| 40 registrados, nada invocado | 0 | **128 MB** | +| logo após invocar **todos os 40** em rajada | **4** (teto) | 329 MB | +| 11 s depois, ocioso | **0** | **132 MB** | +| requisição seguinte | re-fork | 200 em **23 ms** | + +- Status interno novo `idle`, mas `getRuntimeInfo()` reporta `online` + `warm: false` — nenhum + consumidor (UI, rotas, dispatch) precisou mudar, porque para todos eles "idle" significa + "vai atender". `GET /api/lambdas` expõe `warm`, `GET /api/services` expõe `runtimeWarm`. + +### 3.2 Escala — WAL, watchers e paginação + +- **`src/server/engine/store/wal.ts`** — compactação só acontecia via `dehydrate()`, que é + disparado pelo sweep de ociosidade e pelo LRU. Uma tabela escrita continuamente nunca fica + ociosa: o WAL crescia a sessão inteira e era relido por completo no boot seguinte. Agora a + tabela compacta sozinha quando o WAL passa de 4 MB **e** do dobro do tamanho residente. +- **`src/server/services/source-watcher.ts`** — `fs.watch(root, {recursive:true})` registra um + watch inotify por diretório da árvore. Medido no exemplo: **1.756 diretórios, dos quais 4 têm + código**. Com 40 serviços seriam ~70 mil watches (`max_user_watches` costuma ser 8.192 em + máquina de dev). `IGNORED_SEGMENTS` só filtrava os eventos, nunca os watches. Agora: watch + não-recursivo na raiz + um recursivo por subdiretório não ignorado. +- **Paginação** em `dynamo-explorer.ts`, `seed-manager.ts`, `resource-provisioner.ts` + (`ListTables`, corte em 100) e `queue-inspector.ts` + `resource-provisioner.ts` + (`ListQueues`, corte em 1000). O engine implementa o corte fielmente à AWS — o bug era do + consumidor. + +### 3.3 Correção de região nos explorers + +**`src/server/services/explorer-region.ts` (novo)** + construtores de `dynamo-explorer`, +`secrets-explorer`, `opensearch-explorer`. + +`DynamoExplorer`, `SecretsExplorer` e `OpenSearchExplorer` tinham `defaultRegion = 'us-east-1'` +fixo e `setDefaultRegion()` nunca era chamado no boot (só `SeedManager` chamava). +`S3Explorer`/`QueueInspector` já liam a região do engine no construtor — a inconsistência +escondia o bug. O dashboard sempre manda `?region=` (lido de `/api/config`), então só quebrava +para **CLI, `LssClient` e curl**. Agora: construtor lê a região configurada, `index.ts` fixa +explicitamente no boot, e `PUT /api/config` / `POST /api/config/reload` re-aplicam. + +Sintoma antes da correção, no exemplo shipado (região `us-west-2`): + +``` +$ curl .../api/dynamo/tables → {"tables":[]} +$ curl .../api/dynamo/tables?region=us-west-2 → 2 tabelas +``` + +### 3.4 `persistence: false` passou a significar o que promete + +**`src/server/engine/store/memory-store.ts` (novo)**, `engine-store.ts`, `self-backend.ts`. + +`config.persistence` só era consultado para o snapshot de mensagens SQS. Catálogos e WAL eram +escritos sempre — tabelas e filas sobreviviam ao restart e o run deixava `.lss/engine/` para +trás. Agora `persistence: false` troca o store por um in-memory: nada é criado em disco, +nenhum boot herda estado. + +Verificado: com `persistence:false`, `.lss/` contém só `orchestrator.{log,pid}`, e +`/api/resources` volta vazio depois de um restart. + +### 3.5 Isolamento entre projetos e instâncias + +- **`src/server/services/project-scope.ts` (novo)** — `projectCacheSegment()` saiu de + `cache-manager.ts` (re-exportado de lá, sem quebrar importadores) para poder ser usado sem + ciclo de import. +- **`config-manager.ts`** — novo env var **`LSS_ENGINE_DATA_DIR`**: com ele, mais + `LSS_DASHBOARD_PORT` e `LSS_ENGINE_PORT`, uma segunda instância sobe sem escrever nenhum + arquivo de config e sem compartilhar nada com o stack de dev: + ```bash + LSS_DASHBOARD_PORT=3250 LSS_ENGINE_PORT=14766 \ + LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start --self-engine + ``` + Validado: o estado do engine foi inteiro para o diretório do env e `.lss/` ficou só com + `orchestrator.{log,pid}`. +- **`config-manager.ts`** — sem `stateDir`, `dataDir` do engine e do sidecar aoss caíam em + `~/.lss/engine` e `~/.lss/aoss`, **globais**: todo projeto da máquina compartilhava o mesmo + conjunto de tabelas. Agora: `~/.lss/projects/-/{engine,aoss}`. +- **`lambda-runtime-manager.ts`** — o diretório de extração de artefato era + `~/.lss/orchestrator/runtime//`, sem escopo de projeto, e um registro novo + faz `rm -rf` do diretório base. Dois checkouts com um serviço chamado `api` → o segundo + apagava o código do qual o worker do primeiro estava rodando. Agora escopado por projeto. +- **`bin/cli.js`** — `lss start` com `engine: "self"` não exporta mais nenhuma + `LSS_LOCALSTACK_*` nem `LOCALSTACK_AUTH_TOKEN`. Além do vazamento (o env é herdado por todo + worker forkado), cada chave exportada era reportada por `GET /api/config` como + `envOverridden` — o que **acinzentava 7 campos na aba Settings** para valores que você nunca + setou. + +### 3.6 Erros que derrubavam o processo + +- **`src/server/index.ts`** — `app.listen()` sem handler de `error`: um `EADDRINUSE` na porta + do dashboard virava exceção não tratada **depois** de o engine já ter feito bind da porta + dele e armado os loops de entrega, deixando um processo meio vivo. Agora: mensagem nomeada + + shutdown limpo com exit code 1. +- **`src/server/dev/dynamo-proxy.ts`** — mesmo problema; como o proxy é opcional, degrada para + warning e o orquestrador continua de pé. + +### 3.7 Testabilidade + +- **`src/client/{http,namespaces/queues}.ts`** — o default de `awaitIdle` no servidor (15.000 ms) + era **igual** ao timeout HTTP default do `LssClient` (15.000 ms): a principal primitiva de + espera do produto resolvia ou lançava dependendo de escalonamento. Agora o request de + `awaitIdle` tem orçamento próprio (`timeoutMs` do servidor + 5 s de folga). +- **`src/server/index.ts`** — qualquer `/api/*` que nenhum router reivindicou agora responde + **404 JSON**, não o `200 text/html` do SPA. Antes, um path errado passava por sucesso para + curl, para o `LssClient` e para qualquer teste assertando na resposta. +- **`tests/unit/engine/dispatch/helpers.ts`** — causa raiz do flake `ENOTEMPTY` documentado no + AGENTS.md: `cleanup()` fazia `rm -rf` sem `flushAll()`, correndo com as escritas debounced + (20 ms) do catálogo. Agora drena antes e tem retry curto. Confirmei que o flake é de + **contenção de CPU**: ele reapareceu enquanto a instância de 40 workers rodava e sumiu depois + — 5 execuções limpas seguidas. + +### 3.8 Dashboard sem "LocalStack" no modo self + +**`src/ui/src/services/engine.ts` (novo)** + `App.vue`, `OverviewPage.vue`, `QueuesView.vue`, +`BucketsView.vue`, `ServicesList.vue`, `ServiceDetailPage.vue`, `api.ts`. + +O badge do header dizia "LocalStack: Running" sempre; a Overview dizia "One LocalStack. Every +microservice." e mostrava `endpoint: :4566` / `image: localstack/localstack:latest` / `mode: +managed` **mesmo com o engine self em :14666** — o campo que o dev copia para o SDK apontava +para uma porta morta. Empty states e confirmações de exclusão diziam "in LocalStack". + +Agora tudo lê `engineLabel`/`isSelfEngine`, alimentados por `/api/health` (`engine.kind`) e +`/api/config`. No servidor, `GET /api/health` ganhou `engineRunning`; `localstack` continua como +alias deprecado. + +### 3.9 Documentação + +`README.md`, `docs/FEATURES.md`, `docs/SELF_ENGINE.md`, `docs/CONFIGURATION.md` atualizados +para tudo acima (exigência do AGENTS.md §4). + +--- + +## 4. Decisões que tomei — e as alternativas + +Você pediu para eu escolher e listar as alternativas. + +### 4.1 `lambdaRuntime.lazy` default **true** + +- **Escolhi:** ligado por default. É a diferença entre 2,0 GB e 128 MB no seu cenário, e o custo + medido é 23 ms na primeira chamada de cada serviço. +- **Alternativas:** (a) default `false` e opt-in — mais conservador, mas ninguém liga o que não + sabe que existe, e o cenário-alvo do produto é justamente o que sofre; (b) worker + multi-tenant (N serviços por processo) — economiza mais, mas quebra o isolamento de `env` e + de crash entre serviços; (c) `worker_threads` em vez de `fork` (~10 MB em vez de 48 MB) — + ganho grande, mas exige revisar isolamento de `process.env` e de `process.exit` dos handlers. + **(c) é o próximo passo natural se 128 MB + N×48 MB ainda incomodar.** + +### 4.2 `idleTimeoutMs` default **60 s** e `maxWarmWorkers` default **1 por GB de RAM** + +- **Escolhi:** agressivo, conforme você definiu — o lambda sobe quando é usado e cai depois. + Um cold start custa 23 ms; lentidão não é problema, travar o host é. +- **Por que os dois, e não só o timeout:** o timeout sozinho não protege de uma rajada. Uma + suíte de testes ou um script de boot que toca os 40 serviços dentro da janela de ociosidade + teria os 40 workers vivos ao mesmo tempo. O teto é o que transforma "memória proporcional aos + serviços registrados" em "memória proporcional aos serviços em uso". +- **Alternativas para o teto:** (a) valor fixo (ex.: 8) — previsível, mas ou desperdiça numa + máquina grande ou sufoca numa pequena; (b) orçamento em MB em vez de contagem de processos — + mais preciso, mas exige amostrar RSS dos filhos periodicamente; (c) sem teto (`0`), confiando + só no timeout. Escolhi 1/GB limitado a 2..12 porque responde diretamente ao "não pode travar + o computador hospedeiro" sem precisar de configuração por máquina. + +### 4.3 Status `idle` reportado como `online` + `warm: false` + +- **Escolhi:** manter `status` estável e adicionar `warm`. Zero mudança para consumidores + existentes, e a informação nova está lá para a UI usar. +- **Alternativa:** expor `idle` diretamente em `runtimeStatus` — mais honesto, mas quebraria a + UI (badge de status), o client tipado e testes de rota. + +### 4.4 `persistence:false` → store in-memory (e não diretório temporário) + +- **Escolhi:** implementação in-memory dedicada. É o que a documentação promete e dá clean + slate real. +- **Alternativas:** (a) apontar `dataDir` para um temp dir apagado no shutdown — menos código, + mas continua fazendo I/O e vaza o diretório num SIGKILL; (b) tornar as escritas no-op dentro + do `JsonlItemTable` — mexeria no caminho crítico de WAL testado. +- **Trade-off assumido e documentado:** em modo in-memory os corpos de S3 ficam no heap + (o store em disco os mantém fora dele) e `idleUnloadMs`/`memoryBudgetMb` ficam inertes — + descartar uma tabela sem snapshot seria perda de dados, não evicção. + +### 4.5 CLI: só as variáveis de LocalStack foram removidas no modo self + +- **Escolhi:** remover apenas as `LSS_LOCALSTACK_*`/token quando `engine === 'self'`. +- **Não fiz:** parar de exportar `PORT` e `LSS_DYNAMO_PROXY_PORT`. Isso deixaria `serverPort` + e `dynamoProxyPort` editáveis na aba Settings, mas mudaria o contrato documentado do + `LSS_CONFIG_PATH` passthrough e mexe no arquivo mais coberto por teste do repo. +- **Alternativa recomendada para um próximo passo:** sempre exportar `LSS_CONFIG_PATH` com o + arquivo de config resolvido (inclusive quando encontrado pela busca em cwd/home) e deixar de + traduzir config → env, mantendo env **só** para o que veio de flag de CLI + (`--external`, `--pro`, `--localstack-token`, `--self-engine`, `--enable-dynamo-proxy`). + Aí `envOverrides` volta a significar "o usuário setou um env var". + +--- + +## 5. Backlog priorizado — o que **não** corrigi + +Saiu de uma auditoria multi-agente (7 dimensões × verificação adversarial): 89 achados +confirmados. Abaixo os que sobraram, em ordem de impacto no seu cenário. Cada item tem a +recomendação e, quando existe, o caminho alternativo. + +### P0 — mexem direto no monolito de 40 serviços + +**1. Sem lock no `dataDir` do engine** (`engine/store/engine-store.ts`) +Dois engines apontando para o mesmo diretório se corrompem em **silêncio** (não dá erro). +Acontece com cópia de projeto, worktree com `.lss` symlinkado, ou dois `lss start` na mesma +pasta com portas diferentes. +→ *Recomendado:* lock exclusivo `/engine.lock` via `fs.openSync(p,'wx')` com +`{pid, serverPort, enginePort}`; se o pid estiver vivo, abortar com a mesma qualidade de +mensagem do `EADDRINUSE`; se morto, tomar o lock e logar recuperação. E tornar o `tmpPath` de +`atomic.ts` único por processo. +→ *Alternativa:* só o `tmpPath` único + aviso — mas a truncagem de WAL pelo `compact()` +continua acontecendo. + +**2. `GET /api/config` fabrica um bloco `localstack` no modo self** +(`routes/config.ts:42`) — corrigi a UI, mas o payload ainda traz `endpoint: :4566`, +`image: localstack/localstack:latest`, `mode: managed`. Qualquer outro consumidor da API +continua sendo enganado. +→ *Recomendado:* `localstack: null` no modo self (mais fácil para consumidor tipado que omitir +a chave) e ajustar `LssConfigSnapshot` no client e na UI. + +**3. Query/Scan do DynamoDB materializa a tabela inteira e ordena a cada chamada; GSI/LSI nunca +são materializados** (`engine/emulators/dynamodb/query.ts:243`) +Com 400 tabelas e volume real de dados, é o gargalo de CPU mais provável. +→ *Recomendado:* manter um índice ordenado por partition key na hidratação e materializar GSI +como estruturas secundárias mantidas no `put`/`delete`. +→ *Alternativa barata:* cachear a ordenação por tabela, invalidada na escrita — resolve o +Scan repetido sem tocar na estrutura. + +**4. `memoryBudgetMb` conta comprimento de JSON, não heap** (`engine/store/wal.ts:53`) +O default de 128 MB vale ~390 MB de heap / ~540 MB de RSS reais. Numa máquina fraca, o +orçamento não protege do que promete. +→ *Recomendado:* calibrar o fator (medir `process.memoryUsage()` contra `approxBytes` numa +tabela sintética) e documentar a unidade real, ou trocar por amostragem de heap. + +**5. `lambdaRuntime.enabled: false` continua provisionando ESMs e proxies** +(`services/service-registrar.ts:187`) — o engine tenta entregar para sempre e arma um timer de +1 s por ESM. Confirmei que worker e listeners ficam em 0, mas os loops de entrega não. +→ *Recomendado:* pular o provisionamento de event-source-mapping quando o runtime está +desligado para aquele serviço. + +**6b. `idleTimeoutMs` não cobre worker que morre por crash-restart em loop** — o contador +`MAX_RESTARTS` (3 em 30 s) já limita, mas um serviço que quebra no import fica reiniciando 3× +antes de parar. Com 40 serviços num boot ruim, são até 120 forks. +→ *Recomendado:* não re-forkar automaticamente quando o worker nunca chegou a reportar `ready` +(falha de import) — só quando ele já esteve online. + +**6. `QueueInspector.startPolling()` roda sempre** (`index.ts:124`) — 1+N requisições AWS a cada +5 s independentemente de haver fila, dashboard aberto ou `sqs` nos `services`. +→ *Recomendado:* só ligar quando houver fila registrada, e desligar após N ciclos sem +consumidor de `/api/queues`. + +### P1 — testes automatizados (seu terceiro objetivo) + +**7. Não existe porta efêmera para o orquestrador** (`config-manager.ts:437`) +`serverPort: 0` é rejeitado e a porta real nunca é publicada. Isso inviabiliza +`jest --maxWorkers=N` com um stack por worker: seriam ~80 portas por stack para alocar à mão. +→ *Recomendado:* aceitar `0`, e ao subir gravar `/orchestrator.json` com as portas +resolvidas (orquestrador, engine, e `apiPort`/`invokePort` por serviço); `resolveConfig()` do +client passa a ler esse arquivo. +→ *Alternativa mais barata:* `LssClient.ephemeral()` que reserva portas livres no processo de +teste e escreve um config temporário (sujeito a TOCTOU, resolve 95%). + +**8. `waitUntilReady()` retorna antes dos seeds e do `rehydrateAll()`** (`index.ts`) +O *arrange* do teste corre contra o boot. +→ *Recomendado:* só marcar `status: 'ok'` no `/api/health` depois de seeds + rehydrate, ou +adicionar um campo `ready` separado do `status`. + +**9. `lifecycle.start()` do client não sabe subir o self engine** (`client/lifecycle.ts:10`) +Só expõe flags de LocalStack e paga um `setTimeout(2000)` fixo por boot. +→ *Recomendado:* adicionar `engine: 'self'` às `StartOptions` e trocar o sleep fixo por poll no +`/api/health`. + +**10. Só existe primitiva de espera para SQS** (`routes/queues.ts:64`) +Não há como aguardar EventBridge, DynamoDB Streams, notificação S3 ou o fim de uma invocação. +→ *Recomendado:* `POST /api/lambdas/:name/await-invocations { count, timeoutMs }` — espera pelo +**efeito** (a lambda rodou N vezes), que é determinístico, em vez da causa. +→ Isso também resolve o item 11. + +**11. `sinceProcessed` é derivado de heurística de amostragem** (`queue-inspector.ts:612`) +Quanto **mais rápido** o consumidor, mais provável o `awaitIdle({sinceProcessed:1})` nunca +satisfazer a condição e girar até o deadline. +→ *Recomendado:* contador monotônico exato de deleções por fila no `SqsEmulator`, exposto via +atributo/endpoint; manter a heurística só no caminho LocalStack. + +**12. Não há reset de estado entre testes** (`services/seed-manager.ts:291`) +`seeds.clear` só apaga tabelas que têm arquivo de seed, e faz Scan + BatchDelete item a item. +→ *Recomendado:* `POST /api/engine/reset` que recria o store (trivial agora que existe o store +in-memory). Com `persistence:false` o reset já é "reinicie o processo". + +**13. `SelfEngineBackend` não é exportado pelo pacote publicado** (`package.json:12`) +É o padrão dos testes `wire-*` do próprio repo, mas usuários não têm acesso ao modo in-process. +→ *Recomendado:* exportar em `exports` como `./engine` e documentar o padrão. + +**14. Zero cobertura e2e do self engine** (`tests/integration/`) +A única suíte de integração é gated em Docker + `LOCALSTACK_AUTH_TOKEN`. +→ *Recomendado:* uma suíte de integração com `engine: 'self'` — não precisa de Docker nem +token, então roda em qualquer CI. + +### P2 — qualidade, docs e UI + +**15. O gate "100% de cobertura global" exclui `src/server/engine/**` e `src/server/runtime/**`** +(`jest.config.js:9`) — 47 arquivos / ~13 mil linhas, incluindo todo o diferencial do produto. +Os testes existem (45 dos 92 arquivos de teste são do engine), o que falta é a **medição**: +`npm run test:coverage` passa em 100% mesmo com um branch novo de WAL/LRU/FilterCriteria sem +teste. As outras 6 exclusões do arquivo têm comentário explicando o porquê; essas duas são por +omissão. +→ *Recomendado:* adicionar ao `collectCoverageFrom` com exclusões explícitas e comentadas, e um +`coverageThreshold` por path começando no valor medido e subindo. +→ *Alternativa mínima:* corrigir o texto do AGENTS.md §3 para listar o que está fora. + +**16. `DELETE /api/services/:name` apaga recursos AWS reais** (`routes/services.ts:181`) +Com 10 tabelas por serviço, remover um serviço pelo dashboard destrói 10 tabelas e os dados +semeados, sem confirmação e sem nenhum dos 4 documentos avisar. O `lss seed:clear`, muito menos +destrutivo, tem confirmação interativa. +→ *Recomendado:* documentar + exigir `?deleteResources=true` + confirmação na UI. +→ *Alternativa:* separar em `DELETE /:name` (só desregistra) e `DELETE /:name/resources`. + +**17. Default de `engine` é `'localstack'` em três lugares**, e o `lss.config.json` versionado +na raiz do repo boota Docker. O diferencial do produto é opt-in por flag. +→ *Recomendado (imediato, sem breaking change):* trocar o `lss.config.json` da raiz para +`engine: "self"`. O repo passa a se desenvolver no próprio diferencial. +→ *Recomendado (major):* inverter o default e adicionar a flag simétrica `lss start --localstack`. + +**18. Nenhuma lista da UI tem paginação ou virtualização** e 5 de 8 não têm filtro +(`ui/src/components/lambdas/LambdasList.vue:123`). Com 2.400 lambdas a aba trava numa máquina +fraca — exatamente o público-alvo. +→ *Recomendado:* como paginação de tabela pertence à TreeUI, abrir item em +`src/ui/treeUxPatterns.md` pedindo `TTable` com `page-size`/`virtualized`. +→ *Paliativo sem CSS local:* cortar em `computed` nas primeiras 100 linhas + contador +"mostrando 100 de 2400, refine o filtro". + +**19. Polling de intervalo fixo na UI, sem pausar em aba oculta** +(`ui/src/components/QueuesView.vue:82`) — com 40 serviços, a aba Queues força ~40 leituras e +parses de template CloudFormation **a cada 4 s**, mesmo minimizada. +→ *Recomendado:* composable `usePolling(fn, ms)` que respeita `document.hidden`; buscar +`listResourceOwners()` uma vez por montagem; memoizar o parse por `templateHash` no servidor. + +**20. `POST /register` sobrescreve o serviço por nome sem aviso** +(`services/function-registry.ts:59`) — dois checkouts do mesmo repo registram no mesmo +orquestrador (o `orchestratorUrl` é fixo no `serverless.yml`); o segundo reaponta o `root` do +serviço para a outra árvore. +→ *Recomendado:* warning explícito quando o root muda, e 409 por default quando o root novo +está fora do `projectRoot`. + +**21. `dist/server/index.js` é ESM sem `"type": "module"`** (`package.json`) +Cada boot imprime `MODULE_TYPELESS_PACKAGE_JSON` e paga reparse por detecção de sintaxe — do +orquestrador **e de cada worker**. Aparece em todo log do produto. +→ *Recomendado:* resolver o `"type"` do pacote publicado (ou emitir `.mjs`). + +**22. Sem harness de performance no repo.** Os números da §1 não têm nada que os vigie. +→ *Recomendado:* mover `gen-scale.js`/`run-scale.sh` para `tests/perf/` com um limite mínimo +(ex.: falha se o RSS de 40 serviços ociosos passar de 300 MB). + +**Menores** (todos com arquivo:linha no relatório da auditoria): `lss status` e `lss seed:clear` +imprimem "LocalStack: http://localhost:4566" incondicionalmente; `lss help` só documenta +configuração de LocalStack; `HealthStatus`/`StartOptions` do client não expõem engine; +`lambdas.invoke(…, {invocationType:'Event'})` devolve forma diferente do tipo declarado; +o switch do sidecar aoss na SettingsPage é no-op silencioso no modo self; `BucketDetail` trunca +em 200 objetos sem avisar; `debug` é toggle morto no self engine mas a UI o apresenta como +"Verbose engine logging"; `selfEngine.account` é honrado pelo engine mas hardcoded +`000000000000` no provisionador; chave `secrets` ausente do `CONFIGURATION.md`; `/_lss/health` +não documentado; 76 `style=` inline violando o contrato TreeUI sem registro no +`treeUxPatterns.md`. + +--- + +## 6. Respostas diretas às suas perguntas + +**"Todas as features estão documentadas?"** Quase. A enumeração está boa — os 47 endpoints, +os 9 emuladores, os 19 tipos CloudFormation e os comandos de CLI estão todos em +`FEATURES.md`/`README.md`, e os testes citados na coluna "Asserted by" existem de fato. As +falhas são de *garantia*, não de inventário: o gate de cobertura não mede o engine (item 15) e +`DELETE /api/services/:name` destrói recursos sem que nenhum doc avise (item 16). + +**"Todas as features estão funcionando?"** As que exercitei, sim — pipeline completo, DLQ, +OpenSearch, secrets, presigned POST, persistência, rehydrate. Os bugs reais que achei estavam +em superfícies **de leitura** (explorers) e em **escala**, não no caminho de dados. + +**"Quando desligo algo, gera lixo?"** `lambdaRuntime.enabled:false` estava limpo (0 workers, +0 listeners) exceto pelos ESMs (item 5). `persistence:false` gerava lixo e foi corrigido. +`aossSidecar` já era corretamente desligado no modo self. `enableDynamoProxy:false` não abre +nada. O lixo que restava era acumulativo em `~/.lss` — corrigido para escopo por projeto; +sobra apenas o cache legado flat (`~/.lss/orchestrator/cache/`) de versões antigas, +que nunca é limpo e é invisível para o código atual. + +**"Boa isolação entre ambientes?"** Sim, desde que você use `stateDir` (o que os exemplos +fazem). Sem `stateDir` era compartilhado globalmente — corrigido. O buraco que resta é a +ausência de lock (item 1). + +**"Dois processos em paralelo sem bugar?"** Comprovado: duas instâncias completas, quatro +serviços cada, dados totalmente isolados, `stop` de uma não toca na outra. As condições são +portas distintas em tudo (orquestrador, engine, `apiPort`, `invokePort`) e `stateDir` próprio. +O que ainda quebra: modo `artifact` compartilhando diretório de extração (corrigido) e o mesmo +`orchestratorUrl` fixo no `serverless.yml` fazendo dois checkouts registrarem no mesmo +orquestrador (item 20). + +**"Dá para usar em testes automatizados?"** Hoje, para uma suíte **serial** contra um stack +fixo, sim — e o `awaitIdle` agora funciona de forma determinística. Para o padrão que você vai +querer (N stacks em paralelo, um por worker do Jest, clean slate por run), faltam os itens 7, +8, 10 e 12. Com `persistence:false` corrigido, o clean slate já é possível hoje reiniciando o +processo. + +**"O self host tem sujeira do LocalStack?"** Tinha, bastante — env vars, textos de UI em todas +as telas, endpoint `:4566` exibido como se fosse o endpoint real, campo `localstack` no health. +A maior parte foi corrigida. Sobra o bloco `localstack` fabricado em `/api/config` (item 2), os +textos do CLI e o default `engine: 'localstack'` (item 17). O import estático de +`LocalStackBackend` no `engine-manager` existe, mas o módulo só faz `import` de +`child_process` — custo desprezível; o comentário do arquivo é que exagera a assimetria. + +**"É pesado?"** Depois das correções: **128 MB parado com 40 serviços registrados**, +48 MB por +serviço efetivamente invocado, 0,3% de CPU ociosa, boot em 2 s, registro a 22 ms por serviço. +Com `idleTimeoutMs` ligado, o teto fica no número de serviços que você usa ao mesmo tempo, não +no número que você tem. diff --git a/bin/cli.js b/bin/cli.js index 6ec7b7b..d631ce6 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -207,10 +207,6 @@ function startOrchestrator() { if (cfg.serverPort) { env.PORT = cfg.serverPort; } - /* istanbul ignore else: getConfig() always defaults localstackPort to 4566, so the else is unreachable */ - if (cfg.localstackPort) { - env.LSS_LOCALSTACK_PORT = cfg.localstackPort; - } if (enableDynamoProxy) { env.LSS_ENABLE_DYNAMO_PROXY = 'true'; } @@ -218,26 +214,36 @@ function startOrchestrator() { if (cfg.dynamoProxyPort) { env.LSS_DYNAMO_PROXY_PORT = cfg.dynamoProxyPort; } - /* istanbul ignore else: mode resolves to cfg.mode which getConfig() defaults to 'managed', so the else is unreachable */ - if (mode) { - env.LSS_LOCALSTACK_MODE = mode; - } - /* istanbul ignore else: edition resolves to localstackEdition which getConfig() defaults to 'community', so the else is unreachable */ - if (edition) { - env.LSS_LOCALSTACK_EDITION = edition; - } - /* istanbul ignore else: getConfig() always defaults localstackVersion to 'latest', so the else is unreachable */ - if (cfg.localstackVersion) { - env.LSS_LOCALSTACK_VERSION = cfg.localstackVersion; - } - if (cfg.localstackImage) { - env.LSS_LOCALSTACK_IMAGE = cfg.localstackImage; - } - if (authToken) { - env.LOCALSTACK_AUTH_TOKEN = authToken; - } if (engine === 'self') { + // Self engine: not one LocalStack variable is exported. They would be dead + // weight in the child's environment, they leak "there is a LocalStack here" + // into a mode whose whole point is that there isn't, and every key exported + // this way is reported by GET /api/config as env-overridden — which greys + // it out in the dashboard's Settings tab for a value the user never set. env.LSS_ENGINE = 'self'; + } else { + /* istanbul ignore else: getConfig() always defaults localstackPort to 4566, so the else is unreachable */ + if (cfg.localstackPort) { + env.LSS_LOCALSTACK_PORT = cfg.localstackPort; + } + /* istanbul ignore else: mode resolves to cfg.mode which getConfig() defaults to 'managed', so the else is unreachable */ + if (mode) { + env.LSS_LOCALSTACK_MODE = mode; + } + /* istanbul ignore else: edition resolves to localstackEdition which getConfig() defaults to 'community', so the else is unreachable */ + if (edition) { + env.LSS_LOCALSTACK_EDITION = edition; + } + /* istanbul ignore else: getConfig() always defaults localstackVersion to 'latest', so the else is unreachable */ + if (cfg.localstackVersion) { + env.LSS_LOCALSTACK_VERSION = cfg.localstackVersion; + } + if (cfg.localstackImage) { + env.LSS_LOCALSTACK_IMAGE = cfg.localstackImage; + } + if (authToken) { + env.LOCALSTACK_AUTH_TOKEN = authToken; + } } // Hand the same config file to the server so its ConfigManager reads the // identical serverPort/localstackPort/seedsDir/region/mode (not just the diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index cdeeb16..9607938 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -69,7 +69,9 @@ Both files should contain valid JSON with the following optional properties: - **selfEngine** (object, optional — only used when `engine` is `"self"`) - `port` (default 14566, env `LSS_ENGINE_PORT`), `dataDir` (default - `~/.lss/engine`, or `/engine` when `stateDir` is set), `account`, + `~/.lss/projects/-/engine`, or `/engine` when + `stateDir` is set — the home fallback is scoped per project so two checkouts + never share one set of tables), `account`, `idleUnloadMs`, `memoryBudgetMb`, `fsync`, `fallbackEndpoint` (forward unimplemented AWS calls to a LocalStack instance during migration). - Full reference: [SELF_ENGINE.md](SELF_ENGINE.md). @@ -85,7 +87,7 @@ Both files should contain valid JSON with the following optional properties: opt out — aoss provisioning then fails with a hint pointing back here. - `port` (number, default `14567` — one above the self engine's 14566): the sidecar's endpoint is `http://localhost:`. - - Data persists under `~/.lss/aoss` (or `/aoss` when `stateDir` is + - Data persists under `~/.lss/projects/-/aoss` (or `/aoss` when `stateDir` is set), independent of the LocalStack container's lifecycle. - Example — move the sidecar off a busy port: ```jsonc @@ -144,7 +146,14 @@ Both files should contain valid JSON with the following optional properties: - Example: `["dynamodb", "sqs", "sns", "lambda", "s3", "secretsmanager"]` - **persistence** (boolean, default: true) - - Whether to persist LocalStack data between restarts + - Whether engine data survives a restart. + - LocalStack engine: sets `PERSISTENCE` on the container. + - Self engine: `false` swaps the file-backed store for an **in-memory** one — no + `dataDir` is created, no catalog, WAL or blob is written, and every boot starts + from an empty engine. That is the mode to use for an automated test run that + needs a guaranteed clean slate and no leftover files. (The residency knobs — + `selfEngine.idleUnloadMs` / `memoryBudgetMb` — are inert there: with no + snapshot on disk, evicting a table would be data loss rather than eviction.) - Example: `true` - **debug** (boolean, default: false) @@ -162,11 +171,27 @@ Both files should contain valid JSON with the following optional properties: `lss seed [table]` / `lss seed:clear [table]` or the seed panel in the dashboard's DynamoDB tab (open a table → Seed). +- **LSS_ENGINE_DATA_DIR** (env var, no config-file equivalent beyond `selfEngine.dataDir`) + - Overrides where the self engine keeps its state, without touching a config file. + Together with `LSS_ENGINE_PORT` and `LSS_DASHBOARD_PORT` it is everything a second + instance needs: + ```bash + LSS_DASHBOARD_PORT=3250 LSS_ENGINE_PORT=14766 \ + LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start --self-engine + ``` + - Reported as an env override by `GET /api/config`, like every other `LSS_*` var. + - **stateDir** (string, optional) - Directory where this instance keeps its state (PID/lock/log files), resolved relative to the working directory. Setting it isolates an instance so `lss stop --config ` targets it and not your dev instance — useful for e2e stacks running next to a normal one. + - It is also where the engine's `dataDir` and the aoss sidecar's data dir land. + Without it they fall back to a **per-project** directory under + `~/.lss/projects/-/`, derived from the absolute project + root — so two checkouts of the same repo, or two examples, never share state. + Setting `stateDir` (the examples use `.lss`) keeps everything inside the + project and is still the recommended default. - **autoPackage** (boolean, default: false) - When registering a service, if `.serverless/cloudformation-template-update-stack.json` is missing, run the configured `packageCommand` in the service directory and retry. @@ -240,9 +265,39 @@ Both files should contain valid JSON with the following optional properties: Docker Desktop instead of the devcontainer; set this to the Docker network gateway reachable from the LocalStack container (for example `"172.19.0.1"`). Only relevant on the LocalStack engine. + - `lazy` (boolean, default `true`): fork a service's runtime worker on its **first + invocation** instead of at registration. A worker is a Node process costing ~48 MB + resident, so a 40-service monorepo paid ~1.9 GB before a single handler ran; + deferring the fork brings a 40-service stack from ~2.0 GB to ~130 MB at rest and + costs one cold start (~20 ms, measured) per service actually exercised. Handler + resolution (and artifact extraction) still happens at registration, so a broken + packaging is still reported there. Set `false` to restore the eager behaviour. + - `idleTimeoutMs` (number, default `60000` — one minute): stop a worker that has + served nothing for this long, returning the service to the lazy state; the next + invocation re-forks it (~20 ms). LSS is a development stack, not a production + workload — a handler only needs to be resident while it is being used, and a + session that touches every service would otherwise end up as expensive as eager + mode. An in-flight invocation is never interrupted. Set `0` to keep workers + alive forever. + - `maxWarmWorkers` (number, default: one per GB of system RAM, clamped to + `2..12`): hard ceiling on resident workers. When a fork pushes past it, the + least-recently-invoked idle worker is unloaded. This is what makes host memory a + function of the services **in flight** rather than the services **registered**: + a burst that touches all 40 services of a monorepo inside the idle window still + settles at `maxWarmWorkers × ~48 MB`. Set `0` to remove the ceiling. + + > **Measured** on a synthetic 40-service / 400-lambda / 400-table stack: 128 MB + > resident with everything registered and nothing invoked; 329 MB right after + > invoking all 40 with `maxWarmWorkers: 4`; back to 132 MB once the idle timeout + > elapsed — and the next request still answered in 23 ms. - Env overrides: `LSS_LAMBDA_RUNTIME`, `LSS_LAMBDA_EXECUTION`, `LSS_LAMBDA_WATCH`, `LSS_INVOKE_HOST`. + > **Reading the runtime state.** `GET /api/services` reports `runtimeStatus` plus + > `runtimeWarm`, and `GET /api/lambdas` reports `status` plus `warm`. `status` + > stays `online` for a lazily-registered service — it *will* serve an invoke; + > `warm: false` is what tells you no worker process is alive yet. + Docker-in-Docker/devcontainer example: ```jsonc { diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 3f6d07e..d4aaaaf 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -34,7 +34,10 @@ by the live integration suite (`npm run test:integration`). |---|---|---| | `lss.config.json` / `.lssrc` | File config for ports, mode, edition, services, seeds, etc.; env vars override. | unit (`config-manager`, `cli`) | | `stateDir` | Per-instance PID/log directory so an isolated test instance never collides with the dev instance. | unit (`cli`, `config-manager`) + integration | +| `LSS_ENGINE_DATA_DIR` | Points the self engine's state at an explicit directory from the environment. With `LSS_DASHBOARD_PORT` and `LSS_ENGINE_PORT` it is everything a second instance needs — no config file to write, nothing shared with the dev stack. | unit (`config-manager`) | | `LSS_CONFIG_PATH` passthrough | The CLI hands the chosen config to the spawned server so both loaders agree on ports/seedsDir/region/mode. | unit (`config-manager`) + integration | +| Per-project state, no `stateDir` | With no `stateDir`, the engine `dataDir`, the aoss sidecar data dir and the artifact-extraction dir all fall back to `~/.lss/projects/-/…` instead of one shared path — two checkouts (or two examples) never read each other's tables, and re-registering in one no longer `rm -rf`s the code another instance's worker is running from. | unit (`config-manager`, `cache-manager`) | +| No LocalStack env in self mode | `lss start` with `engine: "self"` exports **no** `LSS_LOCALSTACK_*` / `LOCALSTACK_AUTH_TOKEN` to the orchestrator (and therefore to every forked worker). Besides the leak, each exported key was reported by `GET /api/config` as env-overridden, greying it out in the Settings tab for a value the user never set. | unit (`cli`) | | Managed vs external mode | `mode: managed` runs a LocalStack container; `external` connects to a running one. | unit (`config-manager`) | | Edition / version / image / services / persistence / region | All configurable; sensible defaults (community/latest, us-east-1, dynamodb+sqs+sns+s3+lambda+events). | unit (`config-manager`) | | `GET /api/config` | Public-safe full config snapshot for the UI: engine kind/endpoint, self-engine + aoss sidecar + lambda-runtime blocks, packaging, `envOverrides` (keys masked by env vars). Secret values never appear — auth token → `hasAuthToken`, `packageEnv` → key names, `secrets` → count. | unit (`routes/config`) + integration | @@ -84,6 +87,14 @@ LocalStack. `autoPackage` can run the packaging command on demand when the templ `POST /tables/:name/items{,/get,/delete}` — list/describe (key schema, GSI/LSI, stream, TTL), scan/query with filters, and item CRUD. Asserted by: unit (`dynamo-explorer`, `routes/dynamo`) + integration. +**Region default and paging.** Every explorer (`dynamo`, `buckets`, `secrets`, `opensearch`, `queues`) accepts +`?region=`; when it is omitted the configured `region` is used, not a hardcoded `us-east-1`. The dashboard +always sends the region it read from `/api/config`, so a wrong default only ever hit the callers that omit it — +the CLI, the `LssClient` and plain curl — which silently saw an empty stack on any project outside us-east-1. +Table and queue listings follow their pagination tokens (`ListTables` caps a page at 100 names, `ListQueues` at +1000), so a monorepo with 40 services × 10 tables lists all 400 instead of the first 100. Asserted by: unit +(`explorer-region`, `dynamo-explorer`, `seed-manager`, `queue-inspector`, `resource-provisioner`). + ## 7. S3 explorer (`/api/buckets`) `GET /`, `GET /:name`, `GET /:name/objects`, `GET /:name/objects/content`, `POST /:name/objects`, @@ -116,8 +127,13 @@ port. Asserted by: unit (`dev/dynamo-proxy`). ## 10. Health & dashboard -`GET /api/health` reports orchestrator + engine + dynamo-proxy status (the `localstack` field reports the -active engine's health — LocalStack or self — kept under that name for compatibility). The Vue dashboard +`GET /api/health` reports orchestrator + engine + dynamo-proxy status. Liveness of the **active** engine +(LocalStack or self) is `engineRunning`; the older `localstack` field is a deprecated alias for it, kept for +existing clients — it says "localstack" even when the self engine is what is running. `engine.kind` tells the +two apart, and the dashboard reads it so no screen says "LocalStack" on a self-engine stack. + +Any `/api/*` path no router claims answers **404 with a JSON body**, not the SPA's `200 text/html` — a mistyped +API path used to read as success to curl, to the `LssClient` and to any test asserting on the response. The Vue dashboard (served as a SPA) surfaces ten tabs — Overview / Services / Lambdas / APIs / Queues / S3 / DynamoDB / OpenSearch / Secrets / **Settings** — with a region selector and theme toggle; the Services list and service detail pages include the per-service resource breakdown with EventBridge buses & rules and OpenSearch @@ -169,6 +185,7 @@ serverless-offline process running. See `docs/PRD_API_LAMBDA_EMULATION.md` for t |---|---|---| | Function & route registry | `sls package` registers functions, REST (`http`, payload v1) and HTTP API (`httpApi`, payload v2) routes and authorizers; persisted in the service cache and rehydrated on restart. | unit (`serverless-state-parser`, `function-registry`, `cache-manager`) | | Lambda runtime workers | One worker per service loads handlers lazily (warm starts), applies function env/timeout/context, captures per-invocation logs, restarts on crash. | unit (`api-gateway-events` helpers) + integration | +| Lazy workers, idle unload and a warm ceiling | A worker is a Node process costing ~48 MB resident, and LSS is a development stack — a handler only needs to be resident while it is being used. `lambdaRuntime.lazy` (default **true**) forks on the first invocation instead of at registration; `idleTimeoutMs` (default **60000**) unloads a worker that has served nothing for a minute; `maxWarmWorkers` (default: one per GB of RAM, clamped 2..12) caps how many may be resident at once, evicting the least-recently-invoked. Together they make host memory a function of the services *in flight*, not the services *registered*. Handler resolution (and artifact extraction) still runs at registration, so broken packaging still fails there, and an in-flight invocation is never interrupted. Measured on 40 services / 400 lambdas / 400 tables: **2.0 GB → 128 MB** at rest, 329 MB right after invoking all 40 with a ceiling of 4, back to 132 MB once idle — next request still 23 ms. `GET /api/services` reports `runtimeWarm`, `GET /api/lambdas` reports `warm`; `status` stays `online` either way, because the service serves an invoke regardless. | unit (`config-manager`, `routes/lambdas`, `routes/services`) | | Execution modes | `artifact` (extracted `sls package` zip — TS/JS uniform), `source` (direct require/import; TS uses Node native type stripping when available, then `esbuild-register`/`tsx`/`ts-node`), `auto` picks artifact when present. | unit (`config-manager`) + integration | | Invoke API (130xx) | `POST /2015-03-31/functions/{name}/invocations` with `X-Amz-Invocation-Type` (RequestResponse 200 / Event 202 / DryRun 204) and `X-Amz-Function-Error` — same contract the LocalStack event proxies already call. | integration | | Gateway proxy (30xx) | Multi-port routing (literal > `{param}` > `{proxy+}` > `$default`; exact method > ANY), API Gateway payload v1/v2 events, v1 malformed → 502, v2 inferred responses, CORS preflight, `port-conflict` status instead of failing registration. | unit (`api-gateway-events`) + integration | diff --git a/docs/SELF_ENGINE.md b/docs/SELF_ENGINE.md index 5acf79d..db02ed3 100644 --- a/docs/SELF_ENGINE.md +++ b/docs/SELF_ENGINE.md @@ -143,12 +143,27 @@ and non-fatal (a failure warns and boot continues). ## Storage & footprint -Data lives under `dataDir` (default `~/.lss/engine`): JSON catalogs for -metadata, JSONL snapshot + WAL per DynamoDB table / S3 object index / OpenSearch -index, S3 bodies as content-addressed blobs. Registration writes metadata only; -item data hydrates on first access (streamed line-by-line) and dehydrates after -`idleUnloadMs` or under `memoryBudgetMb` LRU pressure. SQS messages are -memory-only (snapshotted on graceful shutdown when `persistence` is on). +Data lives under `dataDir` (default `/engine`, or +`~/.lss/projects/-/engine` when no `stateDir` is set — the +home fallback is scoped per project so two checkouts never share one set of +tables): JSON catalogs for metadata, JSONL snapshot + WAL per DynamoDB table / +S3 object index / OpenSearch index, S3 bodies as content-addressed blobs. +Registration writes metadata only; item data hydrates on first access (streamed +line-by-line) and dehydrates after `idleUnloadMs` or under `memoryBudgetMb` LRU +pressure. SQS messages are memory-only (snapshotted on graceful shutdown when +`persistence` is on). + +A table's WAL folds back into its snapshot on dehydrate **and** on its own once +it outgrows both 4 MB and twice the table's resident size — a table written to +continuously never goes idle, and without that its WAL would grow for the whole +session and be replayed in full on the next boot. + +**`persistence: false` means in-memory.** The engine swaps the file-backed store +for a heap-only one: `dataDir` is never created, no catalog/WAL/blob is written, +and every boot starts empty. That is the mode for an automated test run that +needs a guaranteed clean slate and no leftover files; `idleUnloadMs` / +`memoryBudgetMb` are inert there, since with no snapshot on disk an eviction +would be data loss. Crash-safety bar (a dev tool, stated honestly): a hard crash may lose the last ~20 ms of writes. Ground truth is regenerable — re-register the services and diff --git a/src/client/http.ts b/src/client/http.ts index f043c46..3a4c0e8 100644 --- a/src/client/http.ts +++ b/src/client/http.ts @@ -26,6 +26,13 @@ export interface RequestOptions { query?: Record; /** Status codes treated as success in addition to 2xx (e.g. await-idle's 408). */ okStatuses?: number[]; + /** + * Per-request client timeout, overriding the client default. Required by any + * endpoint that BLOCKS server-side for a caller-chosen duration: with the + * shared 15 s default, await-idle's own 15 s default made the client abort at + * exactly the moment the server would have answered 408. + */ + timeoutMs?: number; } export interface RequestContext { @@ -82,7 +89,8 @@ async function doFetch( ): Promise { const url = ctx.baseUrl + path + buildQuery(opts.query); const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), ctx.timeoutMs); + const timeoutMs = opts.timeoutMs ?? ctx.timeoutMs; + const timer = setTimeout(() => controller.abort(), timeoutMs); const hasBody = opts.body !== undefined; try { return await fetch(url, { @@ -96,7 +104,7 @@ async function doFetch( // an Error subclass across Node versions), so match on the name directly. const name = (err as { name?: string }).name; if (name === 'AbortError') { - throw new LssHttpError(`request to ${path} timed out after ${ctx.timeoutMs}ms`, { + throw new LssHttpError(`request to ${path} timed out after ${timeoutMs}ms`, { status: 0, statusText: 'timeout', path, diff --git a/src/client/namespaces/queues.ts b/src/client/namespaces/queues.ts index cd55479..5a74370 100644 --- a/src/client/namespaces/queues.ts +++ b/src/client/namespaces/queues.ts @@ -25,6 +25,10 @@ export interface QueuesApi { purge(name: string, region?: string): Promise<{ success: true }>; } +// Headroom on top of the server-side await-idle budget, so the 408 always wins +// the race against the client abort. +const AWAIT_IDLE_GRACE_MS = 5000; + export function createQueuesApi(http: Http, defaultRegion?: string): QueuesApi { const reg = (r?: string) => r ?? defaultRegion; const base = (name: string) => `/api/queues/${encodeURIComponent(name)}`; @@ -38,6 +42,12 @@ export function createQueuesApi(http: Http, defaultRegion?: string): QueuesApi { body: input ?? {}, query: { region: reg(r) }, okStatuses: [408], // additive to 2xx: 200 = drained, 408 = timed out (inspect `drained`) + // The server blocks for up to `timeoutMs` (its own default is 15 s, + // clamped to 120 s) and only then answers 408. The client's shared + // default is also 15 s, so without a longer per-request budget the + // abort and the 408 raced — the main waiting primitive of the whole + // test story resolved or threw depending on scheduling. + timeoutMs: Math.min(Math.max(input?.timeoutMs ?? 15000, 100), 120000) + AWAIT_IDLE_GRACE_MS, }), hold: (name, r) => http.json('POST', `${base(name)}/hold`, { query: { region: reg(r) } }), captured: (name, r) => http.json('GET', `${base(name)}/captured`, { query: { region: reg(r) } }), diff --git a/src/server/dev/dynamo-proxy.ts b/src/server/dev/dynamo-proxy.ts index 41f9276..ec16e1e 100644 --- a/src/server/dev/dynamo-proxy.ts +++ b/src/server/dev/dynamo-proxy.ts @@ -45,5 +45,14 @@ export function startDynamoProxy(targetEndpoint: string, port = 8000) { console.log(`✅ DynamoDB proxy listening on http://localhost:${port} -> ${targetBase}`); }); + // The proxy is an optional convenience: a busy port must degrade to a warning, + // never take the orchestrator down with an unhandled 'error' event. + server.on('error', (error: NodeJS.ErrnoException) => { + const detail = error.code === 'EADDRINUSE' + ? `port ${port} is already in use — set dynamoProxyPort to a free port or disable enableDynamoProxy` + : error.message; + console.warn(`⚠️ DynamoDB proxy disabled: ${detail}`); + }); + return server; } diff --git a/src/server/engine/backends/self-backend.ts b/src/server/engine/backends/self-backend.ts index 8179f2b..73abbe2 100644 --- a/src/server/engine/backends/self-backend.ts +++ b/src/server/engine/backends/self-backend.ts @@ -62,6 +62,10 @@ export class SelfEngineBackend implements EngineBackend { idleUnloadMs: config.idleUnloadMs, memoryBudgetMb: config.memoryBudgetMb, fsync: config.fsync, + // `persistence: false` must mean it: no dataDir, no catalogs, no WAL — + // otherwise tables and queues survive a restart and the run leaves a + // `.lss/engine/` tree behind. + persistence: config.persistence, }); this.store = store; const bus = new EngineBus(); diff --git a/src/server/engine/store/engine-store.ts b/src/server/engine/store/engine-store.ts index 2307e66..d7763f9 100644 --- a/src/server/engine/store/engine-store.ts +++ b/src/server/engine/store/engine-store.ts @@ -16,6 +16,7 @@ import path from 'path'; import type { CatalogStore, EngineStore, ItemTable } from './store-types.js'; import { atomicWriteFile } from './atomic.js'; import { JsonlItemTable } from './wal.js'; +import { MemoryEngineStore } from './memory-store.js'; const CATALOG_FLUSH_DEBOUNCE_MS = 20; const SWEEP_INTERVAL_MS = 60_000; @@ -25,10 +26,14 @@ export interface EngineStoreOptions { idleUnloadMs: number; memoryBudgetMb: number; fsync: boolean; + // `false` swaps in the in-memory store: nothing is read from or written to + // dataDir, so the run starts clean and leaves nothing behind. Defaults to + // true — every existing caller keeps the file-backed behaviour. + persistence?: boolean; } export function createEngineStore(options: EngineStoreOptions): EngineStore { - return new FileEngineStore(options); + return options.persistence === false ? new MemoryEngineStore() : new FileEngineStore(options); } class JsonCatalog implements CatalogStore { diff --git a/src/server/engine/store/memory-store.ts b/src/server/engine/store/memory-store.ts new file mode 100644 index 0000000..802cf69 --- /dev/null +++ b/src/server/engine/store/memory-store.ts @@ -0,0 +1,199 @@ +// In-memory EngineStore — what `persistence: false` actually means. +// +// The file-backed store always wrote: catalogs, WALs and blobs landed under +// dataDir even with persistence off, so tables and queues survived a restart +// and the run left a `.lss/engine/` tree behind. That breaks the two things +// the flag exists for: a guaranteed clean slate for an automated test run, and +// "turning it off leaves nothing behind". +// +// Everything here lives in the heap for the lifetime of the process. There is +// no residency governance: dehydrating would mean dropping data with nowhere +// to reload it from, so the LRU/idle machinery is deliberately inert (the +// memory budget only ever protected against unbounded file-backed hydration). +// A run that needs the budget enforced wants persistence on. + +import crypto from 'crypto'; +import path from 'path'; +import type { CatalogStore, EngineStore, ItemTable } from './store-types.js'; + +class MemoryCatalog implements CatalogStore { + private map = new Map(); + + load(): Promise { + return Promise.resolve(); + } + + get(key: string): T | undefined { + return this.map.get(key); + } + + set(key: string, value: T): void { + this.map.set(key, value); + } + + delete(key: string): boolean { + return this.map.delete(key); + } + + keys(): string[] { + return [...this.map.keys()]; + } + + values(): T[] { + return [...this.map.values()]; + } + + flush(): Promise { + return Promise.resolve(); + } +} + +// Same rough accounting the JSONL table uses, so approxBytes() stays +// comparable across the two implementations. +function approxSizeOf(key: string, value: unknown): number { + return key.length + JSON.stringify(value ?? null).length + 2; +} + +class MemoryItemTable implements ItemTable { + private map = new Map(); + private bytes = 0; + private touchedAt = Date.now(); + + private touch(): void { + this.touchedAt = Date.now(); + } + + hydrate(): Promise { + this.touch(); + return Promise.resolve(); + } + + // Always resident: there is no backing file to rehydrate from. + isHydrated(): boolean { + return true; + } + + get(key: string): unknown { + this.touch(); + return this.map.get(key); + } + + put(key: string, value: unknown): void { + const previous = this.map.get(key); + if (previous !== undefined) this.bytes -= approxSizeOf(key, previous); + this.map.set(key, value); + this.bytes += approxSizeOf(key, value); + this.touch(); + } + + delete(key: string): boolean { + const previous = this.map.get(key); + const existed = this.map.delete(key); + if (existed) this.bytes -= approxSizeOf(key, previous); + this.touch(); + return existed; + } + + has(key: string): boolean { + return this.map.has(key); + } + + entries(): IterableIterator<[string, unknown]> { + this.touch(); + return this.map.entries(); + } + + size(): number { + return this.map.size; + } + + approxBytes(): number { + return this.bytes; + } + + lastTouchedAt(): number { + return this.touchedAt; + } + + flush(): Promise { + return Promise.resolve(); + } + + compact(): Promise { + return Promise.resolve(); + } + + // Deliberately keeps the rows: with no snapshot on disk, dropping them here + // would be data loss rather than eviction. + dehydrate(): Promise { + return Promise.resolve(); + } + + destroy(): Promise { + this.map.clear(); + this.bytes = 0; + return Promise.resolve(); + } +} + +export class MemoryEngineStore implements EngineStore { + private catalogs = new Map>(); + private tables = new Map(); + private blobs = new Map(); + + // A virtual path: nothing is created on disk. The only caller (the graceful + // SQS snapshot in self-backend) is already gated on persistence being on. + dir(...segments: string[]): string { + return path.posix.join('/lss-memory', ...segments); + } + + catalog(relPath: string): CatalogStore { + let catalog = this.catalogs.get(relPath); + if (!catalog) { + catalog = new MemoryCatalog(); + this.catalogs.set(relPath, catalog); + } + return catalog as CatalogStore; + } + + table(relPath: string): ItemTable { + let table = this.tables.get(relPath); + if (!table) { + table = new MemoryItemTable(); + this.tables.set(relPath, table); + } + return table; + } + + // Content-addressed like the file store, so the S3 emulator's + // "same bytes → same handle" de-duplication behaves identically. + writeBlob(relDir: string, data: Buffer): Promise { + const hash = crypto.createHash('sha256').update(data).digest('hex'); + const handle = `${this.dir(relDir)}/${hash.slice(0, 2)}/${hash}`; + if (!this.blobs.has(handle)) this.blobs.set(handle, data); + return Promise.resolve(handle); + } + + readBlob(blobPath: string): Promise { + const data = this.blobs.get(blobPath); + if (!data) { + const error = new Error(`ENOENT: no such blob, open '${blobPath}'`) as NodeJS.ErrnoException; + error.code = 'ENOENT'; + return Promise.reject(error); + } + return Promise.resolve(data); + } + + deleteBlob(blobPath: string): Promise { + this.blobs.delete(blobPath); + return Promise.resolve(); + } + + // No files to sweep or flush — the residency machinery has nothing to do. + startSweeper(): void {} + stopSweeper(): void {} + + flushAll(): Promise { + return Promise.resolve(); + } +} diff --git a/src/server/engine/store/wal.ts b/src/server/engine/store/wal.ts index 24ceb61..3c62ed3 100644 --- a/src/server/engine/store/wal.ts +++ b/src/server/engine/store/wal.ts @@ -20,6 +20,13 @@ import type { ItemTable } from './store-types.js'; const WAL_FLUSH_DEBOUNCE_MS = 20; const WAL_FLUSH_BYTES = 256 * 1024; const SNAPSHOT_WRITE_CHUNK = 256 * 1024; +// Self-compaction thresholds. Compaction used to happen only on dehydrate — +// which is driven by the idle sweep and the LRU budget — so a table that is +// written to continuously never compacted: its WAL grew for the whole session +// and the next boot replayed every record. Compact once the WAL has outgrown +// both an absolute floor and the table's own resident size. +const WAL_COMPACT_MIN_BYTES = 4 * 1024 * 1024; +const WAL_COMPACT_RATIO = 2; interface WalRecord { seq: number; @@ -83,6 +90,10 @@ export class JsonlItemTable implements ItemTable { private walBuffer: string[] = []; private walBufferBytes = 0; + // Bytes appended to the WAL file since the last compaction, and the guard + // that keeps a background compaction from being scheduled twice. + private walBytesSinceCompact = 0; + private compacting = false; private walTimer: NodeJS.Timeout | null = null; // Serializes WAL appends; kept always-resolved (failures are logged) so a // bad write never wedges later flushes. @@ -178,7 +189,7 @@ export class JsonlItemTable implements ItemTable { await this.writeSnapshot(tmpPath, map); await fsp.rename(tmpPath, this.snapshotPath); await fsp.writeFile(this.walPath, ''); - + this.walBytesSinceCompact = 0; } async dehydrate(): Promise { @@ -332,13 +343,34 @@ export class JsonlItemTable implements ItemTable { const data = this.walBuffer.join(''); this.walBuffer = []; this.walBufferBytes = 0; - const next = this.walChain.then(() => appendToFile(this.walPath, data, this.fsync)); + const next = this.walChain.then(async () => { + await appendToFile(this.walPath, data, this.fsync); + this.walBytesSinceCompact += Buffer.byteLength(data); + }); this.walChain = next.catch((err) => { console.warn(`[engine-store] WAL append failed for ${this.walPath}:`, err); }); + // Scheduled OUTSIDE the chain: compact() awaits walChain, so calling it + // from within would deadlock. + void this.walChain.then(() => this.maybeCompact()); return next; } + // Fold the WAL back into the snapshot once it has grown past both thresholds. + // Runs in the background — writers never block on it. + private maybeCompact(): void { + if (this.compacting || !this.entriesMap) return; + if (this.walBytesSinceCompact < Math.max(WAL_COMPACT_MIN_BYTES, this.approx * WAL_COMPACT_RATIO)) return; + this.compacting = true; + void this.compact() + .catch((err) => { + console.warn(`[engine-store] WAL compaction failed for ${this.walPath}:`, err); + }) + .finally(() => { + this.compacting = false; + }); + } + private dropBufferedWal(): void { if (this.walTimer) { clearTimeout(this.walTimer); diff --git a/src/server/index.ts b/src/server/index.ts index 1b4c608..e987ed3 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -23,6 +23,7 @@ import { LambdaRuntimeManager } from './services/lambda-runtime-manager.js'; import { GatewayManager } from './services/gateway-manager.js'; import { SourceWatcher } from './services/source-watcher.js'; import { startDynamoProxy } from './dev/dynamo-proxy.js'; +import { applyRegionToExplorers } from './services/explorer-region.js'; import type { AossSidecarHandle } from './engine/aoss-sidecar.js'; const __filename = fileURLToPath(import.meta.url); @@ -56,9 +57,11 @@ app.get('/api/health', (_req, res) => { const engine = EngineManager.getInstance(); res.json({ status: 'ok', - // Kept for client/UI compatibility: truthy when the ACTIVE engine - // (LocalStack or self) is healthy. + // Deprecated alias for engineRunning, kept so older clients keep working. + // It says "localstack" even when the self engine is the one running, which + // is exactly the naming the dashboard now avoids. localstack: engine.isRunning(), + engineRunning: engine.isRunning(), engine: engine.healthDetail(), dynamoProxy: { enabled: configManager.isEnableDynamoProxy(), @@ -73,6 +76,15 @@ app.get('/api/health', (_req, res) => { }); }); +// Anything under /api that no router claimed is a 404 in JSON, not the SPA. +// Without this the catch-all below answers 200 text/html for a mistyped API +// path, which reads as success to curl, to the LssClient and to any test +// asserting on the response — the single most confusing failure mode when +// driving LSS from an automated suite. +app.use('/api', (req, res) => { + res.status(404).json({ error: `No such API route: ${req.method} /api${req.path}` }); +}); + // Serve frontend build (fallback for SPA) // __dirname is dist/server, so ../ui points to dist/ui const uiBuildPath = path.join(__dirname, '../ui'); @@ -116,10 +128,26 @@ async function start() { } } - app.listen(PORT, () => { + // An EADDRINUSE on the dashboard port has to be a named, actionable + // failure: without an 'error' listener it surfaces as an unhandled + // exception AFTER the engine has already bound its own port and started + // its delivery loops, leaving a half-alive process behind. + const httpServer = app.listen(PORT, () => { console.log(`✅ Server running on http://localhost:${PORT}`); console.log(`✅ Engine (${engine.getKind()}) running on ${engine.getEndpoint()}`); }); + httpServer.on('error', (error: NodeJS.ErrnoException) => { + if (error.code === 'EADDRINUSE') { + console.error( + `❌ Orchestrator could not bind port ${PORT}: address already in use. ` + + 'Another LSS instance (or another process) is listening there — stop it, ' + + 'or set serverPort in lss.config.json to a free port.', + ); + } else { + console.error('❌ Orchestrator HTTP server failed:', error); + } + void shutdown(1); + }); QueueInspector.getInstance().startPolling(); @@ -130,6 +158,12 @@ async function start() { onFullReload: name => ServiceRegistrar.getInstance().reregister(name), }); + // Every explorer answers requests that omit `?region=` — the CLI, the + // LssClient and plain curl all do. Pin their default to the configured + // region here so those callers see the same resources the dashboard does + // (which only worked because it always sends the region from /api/config). + applyRegionToExplorers(configManager.getRegion()); + // Seed Secrets Manager BEFORE reactivating services so any handler that // reads a secret on its first invocation (including relay-triggered handlers // that fire during rehydrate) already finds an AWSCURRENT version. Non-fatal @@ -162,8 +196,10 @@ async function start() { } } -// Graceful shutdown -async function shutdown() { +// Graceful shutdown. `code` is non-zero when a fatal boot problem (e.g. the +// dashboard port already taken) triggers the teardown, so the CLI reports the +// failure instead of a clean stop. +async function shutdown(code = 0) { console.log('\n🛑 Shutting down gracefully...'); QueueInspector.getInstance().stopPolling(); SourceWatcher.getInstance().unwatchAll(); @@ -174,11 +210,11 @@ async function shutdown() { await aossSidecar?.close(); aossSidecar = null; await EngineManager.getInstance().stop(); - process.exit(0); + process.exit(code); } -process.on('SIGINT', shutdown); +process.on('SIGINT', () => void shutdown()); // The CLI stops the daemonized server with SIGTERM — same cleanup path. -process.on('SIGTERM', shutdown); +process.on('SIGTERM', () => void shutdown()); start(); diff --git a/src/server/routes/config.ts b/src/server/routes/config.ts index a35dea4d..ebbe83b 100644 --- a/src/server/routes/config.ts +++ b/src/server/routes/config.ts @@ -6,6 +6,7 @@ import { ServicePackageConfig, } from '../services/config-manager.js'; import { FunctionRegistry } from '../services/function-registry.js'; +import { applyRegionToExplorers } from '../services/explorer-region.js'; const router = Router(); @@ -85,6 +86,12 @@ function buildConfigSnapshot(cm: ConfigManager) { watch: raw.lambdaRuntime?.watch ?? null, invokePortOffset: cm.getInvokePortOffset(), invokeHost: cm.getInvokeHost(), + // Residency policy: how many worker processes this stack may hold and for + // how long. Resolved (not raw) because maxWarmWorkers' default is derived + // from the host's RAM — the number that matters is the effective one. + lazy: cm.isLambdaRuntimeLazy(), + idleTimeoutMs: cm.getLambdaIdleTimeoutMs(), + maxWarmWorkers: cm.getLambdaMaxWarmWorkers(), }, serviceRuntime: raw.serviceRuntime ?? {}, secretSeedCount: Object.keys(cm.getSecretSeeds()).length, @@ -109,6 +116,10 @@ router.put('/', (req: Request, res: Response) => { const cm = ConfigManager.getInstance(); try { const result = cm.updateConfig(req.body); + // `region` is lazily consumed, so a patch that changes it takes effect at + // once — the explorers' default has to follow or they keep answering for + // the previous region. + applyRegionToExplorers(cm.getRegion()); res.json({ config: buildConfigSnapshot(cm), configPath: result.path, @@ -132,6 +143,7 @@ router.post('/reload', (_req: Request, res: Response) => { const cm = ConfigManager.getInstance(); try { const result = cm.reloadFromDisk(); + applyRegionToExplorers(cm.getRegion()); res.json({ config: buildConfigSnapshot(cm), configPath: result.path, diff --git a/src/server/routes/lambdas.ts b/src/server/routes/lambdas.ts index 57328e2..926ba15 100644 --- a/src/server/routes/lambdas.ts +++ b/src/server/routes/lambdas.ts @@ -20,6 +20,10 @@ function describeFunction(ref: ReturnType[num triggers: ref.fn.triggers, invokePort: ref.service.invokePort, status: info.status, + // False while the service's worker has not been forked yet (lazy start or + // idle unload) — the function is still invocable, the first call just pays + // a cold start. + warm: info.warm ?? false, executionMode: info.resolvedMode, invocations: history.length, errors: history.filter(h => !h.ok).length, diff --git a/src/server/routes/services.ts b/src/server/routes/services.ts index 641510d..a4e7125 100644 --- a/src/server/routes/services.ts +++ b/src/server/routes/services.ts @@ -121,6 +121,9 @@ router.get('/', async (_req: Request, res: Response) => { functionsCount: s.functions?.length ?? 0, routesCount: s.routes?.length ?? 0, runtimeStatus: runtime.status, + // Whether a worker process is actually alive — false means the + // service is ready but not yet forked (lazy start / idle unload). + runtimeWarm: runtime.warm ?? false, gateway, }; }), diff --git a/src/server/services/cache-manager.ts b/src/server/services/cache-manager.ts index ad5c07a..33955f3 100644 --- a/src/server/services/cache-manager.ts +++ b/src/server/services/cache-manager.ts @@ -1,10 +1,14 @@ import fs from 'fs/promises'; import path from 'path'; import os from 'os'; -import crypto from 'crypto'; import { ConfigManager } from './config-manager.js'; +import { projectCacheSegment } from './project-scope.js'; import type { RegisteredFunction, HttpRoute, AuthorizerConfig } from './serverless-state-parser.js'; +// Re-exported for the existing importers (the segment itself now lives in +// project-scope.ts, which config-manager can import without a cycle). +export { projectCacheSegment }; + export interface ServiceMetadata { name: string; root: string; @@ -22,20 +26,6 @@ export interface ServiceMetadata { authorizers?: AuthorizerConfig[]; } -// Stable, filesystem-safe cache segment for one project root: a readable slug -// from the directory basename plus a short hash of the absolute path, so two -// projects whose directories share a basename still get distinct namespaces. -export function projectCacheSegment(projectRoot: string): string { - const absoluteRoot = path.resolve(projectRoot); - const slug = path.basename(absoluteRoot) - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, '') - .slice(0, 40) || 'project'; - const hash = crypto.createHash('sha256').update(absoluteRoot).digest('hex').slice(0, 8); - return `${slug}-${hash}`; -} - export class CacheManager { private cacheDir: string; diff --git a/src/server/services/config-manager.ts b/src/server/services/config-manager.ts index 0c4742e..200d354 100644 --- a/src/server/services/config-manager.ts +++ b/src/server/services/config-manager.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import os from 'os'; import path from 'path'; +import { projectCacheSegment } from './project-scope.js'; import type { SecretSeedValue } from './secret-value.js'; // Symlink-stable spelling of a directory (e.g. macOS /tmp -> /private/tmp), @@ -113,6 +114,23 @@ export interface LambdaRuntimeConfig { // resolve to this machine — e.g. Docker-in-Docker devcontainers, where the // correct host is the docker network gateway (e.g. "172.17.0.1"). invokeHost?: string; + // Fork a service's worker on its first invocation instead of at registration + // (default: true). Each worker is a Node process costing ~48 MB resident, so + // a 40-service monorepo paid ~1.9 GB before a single handler ran. Deferring + // the fork costs one cold start (~200 ms) per service actually exercised. + // Set false to restore the eager behaviour. + lazy?: boolean; + // Stop a worker that has served nothing for this long, returning it to the + // lazy state (default: 60000 — one minute). LSS is a development stack, not a + // production workload: a handler only needs to be resident while it is being + // used, and a cold start costs ~20 ms. Set 0 to keep workers alive forever. + idleTimeoutMs?: number; + // Hard ceiling on how many workers may be resident at once. When a fork + // pushes past it, the least-recently-invoked idle worker is unloaded. This is + // the guarantee that a burst across every service in a large monorepo cannot + // exhaust the host's memory: the ceiling is on services in flight, not on + // services registered. Default: one per GB of system RAM, clamped to 2..12. + maxWarmWorkers?: number; } // Per-service runtime overrides, keyed like `servicePackaging` (directory @@ -290,7 +308,7 @@ export interface LSSConfig { // subkey) so a partial edit never drops sibling settings like `branding.logo`; // every other kind replaces the key wholesale. A top-level null deletes the key. interface ConfigKeySpec { - kind: 'port' | 'positiveInt' | 'boolean' | 'string' | 'stringArray' | 'stringRecord' | 'object'; + kind: 'port' | 'positiveInt' | 'nonNegativeInt' | 'boolean' | 'string' | 'stringArray' | 'stringRecord' | 'object'; enum?: readonly string[]; // Fixed-shape object blocks: every subkey is validated against its own spec // and unknown subkeys are rejected — a garbage nested value would otherwise @@ -345,6 +363,9 @@ const EDITABLE_CONFIG_KEYS: Record = { watch: { kind: 'boolean' }, invokePortOffset: { kind: 'positiveInt' }, invokeHost: { kind: 'string' }, + lazy: { kind: 'boolean' }, + idleTimeoutMs: { kind: 'nonNegativeInt' }, + maxWarmWorkers: { kind: 'nonNegativeInt' }, }, }, serviceRuntime: { @@ -425,7 +446,7 @@ const CONFIG_ENV_OVERRIDES: Record = { packageTimeoutMs: ['LSS_PACKAGE_TIMEOUT_MS'], lambdaRuntime: ['LSS_LAMBDA_RUNTIME', 'LSS_LAMBDA_EXECUTION', 'LSS_LAMBDA_WATCH', 'LSS_INVOKE_HOST'], engine: ['LSS_ENGINE'], - selfEngine: ['LSS_ENGINE_PORT'], + selfEngine: ['LSS_ENGINE_PORT', 'LSS_ENGINE_DATA_DIR'], }; function isPlainObject(value: unknown): value is Record { @@ -442,6 +463,11 @@ function validateValue(key: string, value: unknown, spec: ConfigKeySpec): string return Number.isInteger(value) && (value as number) > 0 ? null : `"${key}" must be a positive integer`; + // 0 is meaningful for these (idleTimeoutMs: 0 = never unload). + case 'nonNegativeInt': + return Number.isInteger(value) && (value as number) >= 0 + ? null + : `"${key}" must be an integer >= 0`; case 'boolean': return typeof value === 'boolean' ? null : `"${key}" must be a boolean`; case 'string': @@ -671,6 +697,15 @@ export class ConfigManager { port: parseInt(process.env.LSS_ENGINE_PORT, 10), }; } + // Give every instance its own engine state without editing a config file: + // `LSS_ENGINE_DATA_DIR=... LSS_ENGINE_PORT=... lss start` is enough to run a + // second stack (a test run, a second checkout) beside the dev one. + if (process.env.LSS_ENGINE_DATA_DIR) { + this.config.selfEngine = { + ...this.config.selfEngine, + dataDir: process.env.LSS_ENGINE_DATA_DIR, + }; + } } getConfig(): LSSConfig { @@ -826,6 +861,30 @@ export class ConfigManager { return this.config.lambdaRuntime?.invokePortOffset ?? 10000; } + // Defer forking a service's worker to its first invocation. On by default: + // one Node process per registered service is ~48 MB, which a 40-service + // monorepo pays entirely up front for handlers it may never call. + isLambdaRuntimeLazy(): boolean { + return this.config.lambdaRuntime?.lazy ?? true; + } + + // A worker only stays resident while it is being used. 0 disables unloading. + getLambdaIdleTimeoutMs(): number { + const raw = this.config.lambdaRuntime?.idleTimeoutMs; + if (raw === undefined) return 60_000; + return typeof raw === 'number' && raw > 0 ? raw : 0; + } + + // Ceiling on resident workers. Default: one per GB of system RAM, clamped to + // 2..12 — the point is that the host's memory is bounded by how many services + // are in flight, never by how many are registered. 0 disables the ceiling. + getLambdaMaxWarmWorkers(): number { + const raw = this.config.lambdaRuntime?.maxWarmWorkers; + if (typeof raw === 'number' && raw >= 0) return Math.floor(raw); + const gib = Math.floor(os.totalmem() / (1024 ** 3)); + return Math.max(2, Math.min(12, gib)); + } + getInvokeHost(): string { if (this.config.lambdaRuntime?.invokeHost) { return this.config.lambdaRuntime.invokeHost; @@ -869,7 +928,7 @@ export class ConfigManager { const selfEngine = this.config.selfEngine ?? {}; const stateDir = this.getStateDir(); const rawDataDir = selfEngine.dataDir - ?? (stateDir ? path.join(stateDir, 'engine') : path.join(os.homedir(), '.lss', 'engine')); + ?? (stateDir ? path.join(stateDir, 'engine') : this.homeStateDir('engine')); return { port: selfEngine.port ?? 14566, dataDir: path.isAbsolute(rawDataDir) ? rawDataDir : path.resolve(process.cwd(), rawDataDir), @@ -893,11 +952,20 @@ export class ConfigManager { port, endpoint: `http://localhost:${port}`, // Mirrors the self-engine default so both persistence roots sit side by - // side (/aoss for test isolation, else ~/.lss/aoss). - dataDir: stateDir ? path.join(stateDir, 'aoss') : path.join(os.homedir(), '.lss', 'aoss'), + // side (/aoss for test isolation, else the per-project dir + // under ~/.lss). + dataDir: stateDir ? path.join(stateDir, 'aoss') : this.homeStateDir('aoss'), }; } + // Fallback state root when the config declares no stateDir. Scoped to this + // project: a flat ~/.lss/ meant every project on the machine shared one + // set of DynamoDB tables, queues and OpenSearch indices, so opening a second + // repo silently showed the first one's data. + private homeStateDir(kind: string): string { + return path.join(os.homedir(), '.lss', 'projects', projectCacheSegment(this.getProjectRoot()), kind); + } + // The AWS endpoint every SDK-based consumer (provisioner, explorers, seeds) // should target for the active engine. getEngineEndpoint(): string { diff --git a/src/server/services/dynamo-explorer.ts b/src/server/services/dynamo-explorer.ts index ab29f76..e23fb55 100644 --- a/src/server/services/dynamo-explorer.ts +++ b/src/server/services/dynamo-explorer.ts @@ -71,7 +71,15 @@ export class DynamoExplorer { private clients = new Map(); private defaultRegion: string = 'us-east-1'; - private constructor() {} + // Seed the default from the active engine config (same as S3Explorer / + // QueueInspector). Without this a project on any region but us-east-1 got an + // empty table list from every caller that omits `?region=` — the CLI, the + // LssClient and a bare curl all hit that path; only the dashboard was safe + // because it always sends the region it read from /api/config. + private constructor() { + const region = LocalStackManager.getInstance().getConfig().region; + if (region) this.defaultRegion = region; + } static getInstance(): DynamoExplorer { if (!DynamoExplorer.instance) DynamoExplorer.instance = new DynamoExplorer(); @@ -94,13 +102,27 @@ export class DynamoExplorer { } async listTables(region?: string): Promise { - const client = this.clientFor(region); - const list = await client.send(new ListTablesCommand({})); - const names = list.TableNames ?? []; + const names = await this.listTableNames(region); const summaries = await Promise.all(names.map((name: string) => this.summarize(name, region))); return summaries.filter((s: DynamoTableSummary | null): s is DynamoTableSummary => s !== null); } + // ListTables answers at most 100 names per page (AWS's hard limit, faithfully + // reproduced by the self engine). A monorepo with 40 services x 10 tables has + // 400 — following LastEvaluatedTableName is the difference between the + // dashboard showing everything and silently showing the first quarter. + async listTableNames(region?: string): Promise { + const client = this.clientFor(region); + const names: string[] = []; + let exclusiveStartTableName: string | undefined; + do { + const page = await client.send(new ListTablesCommand({ ExclusiveStartTableName: exclusiveStartTableName })); + names.push(...(page.TableNames ?? [])); + exclusiveStartTableName = page.LastEvaluatedTableName; + } while (exclusiveStartTableName); + return names; + } + private async summarize(name: string, region?: string): Promise { try { const client = this.clientFor(region); diff --git a/src/server/services/explorer-region.ts b/src/server/services/explorer-region.ts new file mode 100644 index 0000000..0227d69 --- /dev/null +++ b/src/server/services/explorer-region.ts @@ -0,0 +1,23 @@ +// One place that pins the default AWS region on every explorer/inspector. +// +// The explorers all accept an optional `?region=` and fall back to a default. +// The dashboard always sends one (it reads the region from /api/config), so a +// wrong default stayed invisible there — but the CLI, the LssClient and a bare +// curl all omit it, and a project on any region other than us-east-1 got empty +// lists back. Boot calls this with the configured region; keeping it in a +// single module means a new explorer is one line away from being covered. + +import { DynamoExplorer } from './dynamo-explorer.js'; +import { S3Explorer } from './s3-explorer.js'; +import { SecretsExplorer } from './secrets-explorer.js'; +import { OpenSearchExplorer } from './opensearch-explorer.js'; +import { QueueInspector } from './queue-inspector.js'; + +export function applyRegionToExplorers(region: string): void { + if (!region) return; + DynamoExplorer.getInstance().setDefaultRegion(region); + S3Explorer.getInstance().setDefaultRegion(region); + SecretsExplorer.getInstance().setDefaultRegion(region); + OpenSearchExplorer.getInstance().setDefaultRegion(region); + QueueInspector.getInstance().setDefaultRegion(region); +} diff --git a/src/server/services/lambda-runtime-manager.ts b/src/server/services/lambda-runtime-manager.ts index c5085a2..01ffad3 100644 --- a/src/server/services/lambda-runtime-manager.ts +++ b/src/server/services/lambda-runtime-manager.ts @@ -11,13 +11,18 @@ import crypto from 'crypto'; import { fileURLToPath } from 'url'; import AdmZip from 'adm-zip'; import { ConfigManager, LambdaExecutionMode } from './config-manager.js'; +import { projectCacheSegment } from './cache-manager.js'; import { FunctionRegistry, ServiceEntry } from './function-registry.js'; import { resolveArtifacts } from './artifact-resolver.js'; import type { RegisteredFunction } from './serverless-state-parser.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); -export type RuntimeStatus = 'stopped' | 'starting' | 'online' | 'error'; +// `idle` is internal: the service is registered and ready, but its worker has +// not been forked yet (lazy mode) or was unloaded after sitting unused. +// getRuntimeInfo() reports it as `online` with `warm: false`, because for every +// consumer — dashboard, routes, dispatch — it means "an invoke will be served". +export type RuntimeStatus = 'stopped' | 'idle' | 'starting' | 'online' | 'error'; export interface InvokeResult { ok: boolean; @@ -49,7 +54,11 @@ export function httpStatusOf(payload: unknown): number | undefined { } export interface RuntimeInfo { + // Never 'idle' — see the RuntimeStatus note; use `warm` to tell a forked + // worker from one that will be forked on demand. status: RuntimeStatus; + // False when no worker process is alive yet (lazy start or idle unload). + warm?: boolean; executionMode?: LambdaExecutionMode; resolvedMode?: 'artifact' | 'source'; handlerRoot?: string; @@ -84,6 +93,8 @@ interface ServiceRuntime { restartCount: number; lastRestartAt: number; history: InvocationRecord[]; + // Set while a worker is alive and idleTimeoutMs is configured. + idleTimer?: NodeJS.Timeout; } const HISTORY_LIMIT = 50; @@ -128,6 +139,15 @@ export class LambdaRuntimeManager { history: this.runtimes.get(entry.name)?.history ?? [], }; this.runtimes.set(entry.name, runtime); + + // Lazy (default): resolve where the handlers live now — so an unusable + // artifact still fails loudly at registration — but leave the fork to the + // first invocation. A worker is ~48 MB resident; a 40-service monorepo was + // paying ~1.9 GB before a single handler ran. + if (this.configManager.isLambdaRuntimeLazy()) { + if (this.resolveHandlerRootInto(runtime)) runtime.status = 'idle'; + return; + } this.startWorker(runtime); } @@ -143,6 +163,7 @@ export class LambdaRuntimeManager { if (!runtime) return; runtime.status = 'stopped'; runtime.error = undefined; + this.clearIdleTimer(runtime); const worker = runtime.worker; runtime.worker = undefined; if (worker) { @@ -171,13 +192,72 @@ export class LambdaRuntimeManager { await this.syncService(runtime.entry); } + // Drop a live worker back to `idle` (the next invoke re-forks it). Never + // interrupts an in-flight invocation; returns false when it declined. + private unloadWorker(runtime: ServiceRuntime, reason: string): boolean { + if (runtime.status !== 'online' || runtime.pending.size > 0) return false; + this.clearIdleTimer(runtime); + const worker = runtime.worker; + runtime.worker = undefined; + runtime.status = 'idle'; + worker?.removeAllListeners(); + worker?.kill('SIGTERM'); + console.log(`💤 Lambda runtime for "${runtime.entry.name}" unloaded (${reason})`); + return true; + } + + // Unload a worker that has served nothing for idleTimeoutMs. LSS is a + // development stack: a handler only needs to be resident while it is in use, + // and re-forking costs ~20 ms. + private armIdleUnload(runtime: ServiceRuntime): void { + this.clearIdleTimer(runtime); + const timeoutMs = this.configManager.getLambdaIdleTimeoutMs(); + if (!timeoutMs || !this.configManager.isLambdaRuntimeLazy()) return; + runtime.idleTimer = setTimeout(() => { + runtime.idleTimer = undefined; + this.unloadWorker(runtime, `idle for ${timeoutMs} ms`); + }, timeoutMs); + runtime.idleTimer.unref(); + } + + // Hard ceiling on resident workers, enforced when one comes online: evict the + // least-recently-invoked idle worker until the count is back under the cap. + // Without it, a burst that touches every service inside the idle window (a + // full test run, a boot script) would still hold N x ~48 MB at once — the + // ceiling is what keeps host memory a function of services *in flight* + // rather than services registered. + private enforceWarmCap(justStarted: ServiceRuntime): void { + const max = this.configManager.getLambdaMaxWarmWorkers(); + if (!max || !this.configManager.isLambdaRuntimeLazy()) return; + for (;;) { + const warm = [...this.runtimes.values()].filter(r => r.worker); + if (warm.length <= max) return; + const victim = warm + .filter(r => r !== justStarted && r.status === 'online' && r.pending.size === 0) + .sort((a, b) => (a.lastInvokedAt ?? a.startedAt ?? 0) - (b.lastInvokedAt ?? b.startedAt ?? 0))[0]; + // Nothing evictable right now (everything else is busy or still booting): + // the cap is exceeded transiently rather than blocking the invocation. + if (!victim || !this.unloadWorker(victim, `warm-worker cap of ${max} reached`)) return; + } + } + + private clearIdleTimer(runtime: ServiceRuntime): void { + if (runtime.idleTimer) { + clearTimeout(runtime.idleTimer); + runtime.idleTimer = undefined; + } + } + getRuntimeInfo(serviceName: string): RuntimeInfo { const runtime = this.runtimes.get(serviceName); if (!runtime) { return { status: 'stopped', invocations: 0, errors: 0 }; } return { - status: runtime.status, + // `idle` means "ready, not forked yet" — every consumer treats it as + // online; `warm` is the field that distinguishes the two. + status: runtime.status === 'idle' ? 'online' : runtime.status, + warm: Boolean(runtime.worker), executionMode: runtime.executionMode, resolvedMode: runtime.resolvedMode, handlerRoot: runtime.handlerRoot, @@ -208,6 +288,19 @@ export class LambdaRuntimeManager { ); } + // Lazy runtime, first invocation (or first after an idle unload): this is + // the cold start the deferred fork trades the resident memory for. + if (runtime.status === 'idle') { + this.startWorker(runtime); + if ((runtime.status as RuntimeStatus) === 'error') { + return this.errorResult( + 'RuntimeUnavailable', + `Lambda runtime for service "${serviceName}" failed to start (${runtime.error})`, + 0, + ); + } + } + if (runtime.status === 'starting') { await new Promise(resolve => runtime.queue.push(resolve)); if ((runtime.status as RuntimeStatus) !== 'online') { @@ -253,6 +346,7 @@ export class LambdaRuntimeManager { runtime.invocations++; runtime.lastInvokedAt = Date.now(); + this.armIdleUnload(runtime); if (!result.ok) runtime.errors++; runtime.history.push({ at: startedAt, @@ -268,20 +362,27 @@ export class LambdaRuntimeManager { return result; } - private startWorker(runtime: ServiceRuntime): void { - let handlerRoot: string; - let resolvedMode: 'artifact' | 'source'; + // Resolve (and, in artifact mode, extract) where this service's handlers + // live. Returns false and parks the runtime in `error` when that fails, so + // an unusable registration is reported at registration time even when the + // fork itself is deferred. + private resolveHandlerRootInto(runtime: ServiceRuntime): boolean { try { - ({ handlerRoot, resolvedMode } = this.resolveHandlerRoot(runtime.entry, runtime.executionMode)); + const { handlerRoot, resolvedMode } = this.resolveHandlerRoot(runtime.entry, runtime.executionMode); + runtime.handlerRoot = handlerRoot; + runtime.resolvedMode = resolvedMode; + runtime.error = undefined; + return true; } catch (err) { runtime.status = 'error'; runtime.error = err instanceof Error ? err.message : String(err); console.error(`❌ Lambda runtime for "${runtime.entry.name}": ${runtime.error}`); - return; + return false; } + } - runtime.handlerRoot = handlerRoot; - runtime.resolvedMode = resolvedMode; + private startWorker(runtime: ServiceRuntime): void { + if (!this.resolveHandlerRootInto(runtime)) return; runtime.status = 'starting'; runtime.error = undefined; @@ -319,7 +420,9 @@ export class LambdaRuntimeManager { if (msg?.type === 'ready') { runtime.status = 'online'; runtime.startedAt = Date.now(); - console.log(`✅ Lambda runtime online for "${runtime.entry.name}" (${resolvedMode} mode, ${runtime.entry.functions.length} functions)`); + console.log(`✅ Lambda runtime online for "${runtime.entry.name}" (${runtime.resolvedMode} mode, ${runtime.entry.functions.length} functions)`); + this.armIdleUnload(runtime); + this.enforceWarmCap(runtime); const queued = runtime.queue; runtime.queue = []; queued.forEach(release => release()); @@ -393,6 +496,12 @@ export class LambdaRuntimeManager { // Extract artifact zips into a content-addressed dir under ~/.lss so repeated // registrations with unchanged artifacts reuse the same extraction. + // + // Scoped per project, like the template cache: the path used to be keyed on + // the service name alone, so two orchestrators serving different checkouts + // that both own a service called "api" shared one directory — and the + // stale-extraction rmSync below would delete the code the other instance's + // worker was running from. private extractArtifacts(serviceName: string, artifacts: string[]): string { const stamp = artifacts .map(p => { @@ -401,7 +510,10 @@ export class LambdaRuntimeManager { }) .join('|'); const hash = crypto.createHash('sha256').update(stamp).digest('hex').slice(0, 12); - const baseDir = path.join(os.homedir(), '.lss', 'orchestrator', 'runtime', serviceName); + const baseDir = path.join( + os.homedir(), '.lss', 'orchestrator', 'runtime', + projectCacheSegment(this.configManager.getProjectRoot()), serviceName, + ); const targetDir = path.join(baseDir, hash); if (!fs.existsSync(targetDir)) { diff --git a/src/server/services/opensearch-explorer.ts b/src/server/services/opensearch-explorer.ts index eba093e..2564e8f 100644 --- a/src/server/services/opensearch-explorer.ts +++ b/src/server/services/opensearch-explorer.ts @@ -53,7 +53,13 @@ export class OpenSearchExplorer { private clients = new Map(); private defaultRegion: string = 'us-east-1'; - private constructor() {} + // Seeded from the active engine config so a caller that omits `?region=` + // (CLI, LssClient, curl) still reads the project's own region — see the + // matching note in DynamoExplorer. + private constructor() { + const region = LocalStackManager.getInstance().getConfig().region; + if (region) this.defaultRegion = region; + } static getInstance(): OpenSearchExplorer { if (!OpenSearchExplorer.instance) OpenSearchExplorer.instance = new OpenSearchExplorer(); diff --git a/src/server/services/project-scope.ts b/src/server/services/project-scope.ts new file mode 100644 index 0000000..5ec5aae --- /dev/null +++ b/src/server/services/project-scope.ts @@ -0,0 +1,24 @@ +// One naming scheme for "state that belongs to this project", used by every +// place that falls back to a shared location under ~/.lss. +// +// A single global namespace let two checkouts (or two examples, or a dev stack +// and a test stack) collide: same-named services overwrote each other's cached +// templates and artifact extractions, and an engine data dir with no stateDir +// meant every project on the machine shared one set of DynamoDB tables. + +import crypto from 'crypto'; +import path from 'path'; + +// Stable, filesystem-safe segment for one project root: a readable slug from +// the directory basename plus a short hash of the absolute path, so two +// projects whose directories share a basename still get distinct namespaces. +export function projectCacheSegment(projectRoot: string): string { + const absoluteRoot = path.resolve(projectRoot); + const slug = path.basename(absoluteRoot) + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 40) || 'project'; + const hash = crypto.createHash('sha256').update(absoluteRoot).digest('hex').slice(0, 8); + return `${slug}-${hash}`; +} diff --git a/src/server/services/queue-inspector.ts b/src/server/services/queue-inspector.ts index bd102bf..1ac78f4 100644 --- a/src/server/services/queue-inspector.ts +++ b/src/server/services/queue-inspector.ts @@ -505,10 +505,19 @@ export class QueueInspector { } } + // Paginated: ListQueues answers at most 1000 URLs per page. A large monorepo + // (one queue + one DLQ per bounded context) crosses that, and a truncated + // list would drop consumers from the dashboard and from await-idle. private async fetchQueueUrls(region?: string): Promise { try { - const response = await this.sqsClientFor(region).send(new ListQueuesCommand({})); - return response.QueueUrls || []; + const urls: string[] = []; + let nextToken: string | undefined; + do { + const response = await this.sqsClientFor(region).send(new ListQueuesCommand({ NextToken: nextToken })); + urls.push(...(response.QueueUrls || [])); + nextToken = response.NextToken; + } while (nextToken); + return urls; } catch { return []; } diff --git a/src/server/services/resource-provisioner.ts b/src/server/services/resource-provisioner.ts index aabc02f..5f7daa6 100644 --- a/src/server/services/resource-provisioner.ts +++ b/src/server/services/resource-provisioner.ts @@ -1096,19 +1096,35 @@ export const handler = async (event, context) => { return { tables, queues, topics, buckets, collections }; } + // Paginated: ListTables caps a page at 100 names, and GET /api/resources is + // built from this list — a 40-service monorepo would show only its first 100 + // tables in the dashboard and in the client. private async listDynamoDBTables(client: DynamoDBClient = this.dynamoClient): Promise { try { - const response = await client.send(new ListTablesCommand({})); - return response.TableNames || []; + const names: string[] = []; + let exclusiveStartTableName: string | undefined; + do { + const response = await client.send(new ListTablesCommand({ ExclusiveStartTableName: exclusiveStartTableName })); + names.push(...(response.TableNames || [])); + exclusiveStartTableName = response.LastEvaluatedTableName; + } while (exclusiveStartTableName); + return names; } catch { return []; } } + // Paginated for the same reason as the tables above (ListQueues caps at 1000). private async listSQSQueues(client: SQSClient = this.sqsClient): Promise { try { - const response = await client.send(new ListQueuesCommand({})); - return response.QueueUrls?.map(url => url.split('/').pop()!) || []; + const urls: string[] = []; + let nextToken: string | undefined; + do { + const response = await client.send(new ListQueuesCommand({ NextToken: nextToken })); + urls.push(...(response.QueueUrls || [])); + nextToken = response.NextToken; + } while (nextToken); + return urls.map(url => url.split('/').pop()!); } catch { return []; } diff --git a/src/server/services/secrets-explorer.ts b/src/server/services/secrets-explorer.ts index 2b482f1..021964e 100644 --- a/src/server/services/secrets-explorer.ts +++ b/src/server/services/secrets-explorer.ts @@ -47,7 +47,13 @@ export class SecretsExplorer { private clients = new Map(); private defaultRegion = 'us-east-1'; - private constructor() {} + // Seeded from the active engine config so a caller that omits `?region=` + // (CLI, LssClient, curl) still reads the project's own region — see the + // matching note in DynamoExplorer. + private constructor() { + const region = LocalStackManager.getInstance().getConfig().region; + if (region) this.defaultRegion = region; + } static getInstance(): SecretsExplorer { if (!SecretsExplorer.instance) SecretsExplorer.instance = new SecretsExplorer(); diff --git a/src/server/services/seed-manager.ts b/src/server/services/seed-manager.ts index 4bf8ae7..c9006e1 100644 --- a/src/server/services/seed-manager.ts +++ b/src/server/services/seed-manager.ts @@ -447,11 +447,20 @@ export class SeedManager { } } + // Paginated: ListTables caps a page at 100 names, so a monorepo with more + // tables than that would silently report every seed file past the cap as + // "no matching live table". private async listTables(region?: string): Promise { try { const client = this.clientFor(region); - const res = await client.send(new ListTablesCommand({})); - return res.TableNames ?? []; + const names: string[] = []; + let exclusiveStartTableName: string | undefined; + do { + const res = await client.send(new ListTablesCommand({ ExclusiveStartTableName: exclusiveStartTableName })); + names.push(...(res.TableNames ?? [])); + exclusiveStartTableName = res.LastEvaluatedTableName; + } while (exclusiveStartTableName); + return names; } catch { return []; } diff --git a/src/server/services/source-watcher.ts b/src/server/services/source-watcher.ts index d82add3..18dcf74 100644 --- a/src/server/services/source-watcher.ts +++ b/src/server/services/source-watcher.ts @@ -15,7 +15,9 @@ export interface WatchStatus { interface WatchedService { root: string; - watcher: fs.FSWatcher; + // One entry per watched subtree (see watch()): the service root itself, + // non-recursively, plus a recursive watch on each interesting child dir. + watchers: fs.FSWatcher[]; debounce?: NodeJS.Timeout; pendingFullReload: boolean; status: WatchStatus; @@ -48,24 +50,47 @@ export class SourceWatcher { this.handlers = handlers; } + // One recursive watch on the service root is the obvious implementation and + // the expensive one: on Linux, Node registers an inotify watch per directory + // in the subtree, and node_modules dominates it (measured on the shipped + // example: 1756 directories, of which 4 hold source). Forty services would + // ask the kernel for ~70k watches — past fs.inotify.max_user_watches on a + // stock machine — to observe 160 interesting directories. IGNORED_SEGMENTS + // only ever filtered the events, never the watches. + // + // So: watch the root non-recursively (that is where serverless.yml and + // package.json live) and add one recursive watch per child directory that + // isn't ignored. watch(serviceName: string, root: string): void { this.unwatch(serviceName); - try { - const watcher = fs.watch(root, { recursive: true }, (_event, filename) => { - this.onChange(serviceName, filename ? String(filename) : ''); + const watchers: fs.FSWatcher[] = []; + const add = (dir: string, recursive: boolean, prefix: string): void => { + const watcher = fs.watch(dir, { recursive }, (_event, filename) => { + const name = filename ? String(filename) : ''; + this.onChange(serviceName, name && prefix ? path.join(prefix, name) : name); }); watcher.on('error', err => { console.warn(`⚠️ Watcher for "${serviceName}" failed: ${err.message}`); this.unwatch(serviceName); }); + watchers.push(watcher); + }; + + try { + add(root, false, ''); + for (const entry of fs.readdirSync(root, { withFileTypes: true })) { + if (!entry.isDirectory() || IGNORED_SEGMENTS.has(entry.name)) continue; + add(path.join(root, entry.name), true, entry.name); + } this.watched.set(serviceName, { root, - watcher, + watchers, pendingFullReload: false, status: { watching: true }, }); - console.log(`👀 Watching ${root} for changes (service "${serviceName}")`); + console.log(`👀 Watching ${root} for changes (service "${serviceName}", ${watchers.length} watch(es))`); } catch (err) { + for (const watcher of watchers) watcher.close(); console.warn(`⚠️ Could not watch ${root}: ${err instanceof Error ? err.message : err}`); } } @@ -74,7 +99,7 @@ export class SourceWatcher { const watched = this.watched.get(serviceName); if (!watched) return; if (watched.debounce) clearTimeout(watched.debounce); - watched.watcher.close(); + for (const watcher of watched.watchers) watcher.close(); this.watched.delete(serviceName); } diff --git a/src/ui/src/App.vue b/src/ui/src/App.vue index 1cdd477..d7afc3e 100644 --- a/src/ui/src/App.vue +++ b/src/ui/src/App.vue @@ -7,6 +7,7 @@ import { } from '@treeui/vue'; import type { TNavMenuItem } from '@treeui/vue'; import { currentRegion, regionOptions, applyConfiguredRegion } from './services/region'; +import { applyEngineKind, engineLabel } from './services/engine'; import { api } from './services/api'; import type { HealthInfo } from './services/api'; import { branding, loadBranding, applyTheme } from './services/branding'; @@ -62,11 +63,16 @@ function onMenuSelect(value: string) { async function checkHealth() { try { health.value = await api.checkHealth(); + applyEngineKind(health.value.engine?.kind); } catch (error) { console.error('Health check failed:', error); } } +// `localstack` is the deprecated alias; prefer engineRunning when the server +// is new enough to send it. +const engineRunning = computed(() => health.value.engineRunning ?? health.value.localstack); + onMounted(async () => { checkHealth(); healthTimer = window.setInterval(checkHealth, 10000); @@ -74,7 +80,10 @@ onMounted(async () => { // but a region the user picks while /api/config is in flight must stick. const regionAtMount = currentRegion.value; api.getConfig() - .then((config) => applyConfiguredRegion(config.region, currentRegion.value !== regionAtMount)) + .then((config) => { + applyConfiguredRegion(config.region, currentRegion.value !== regionAtMount); + applyEngineKind(config.engine.kind); + }) .catch(() => { /* keep stored/default region */ }); await loadBranding(); theme.value = @@ -112,10 +121,10 @@ onBeforeUnmount(() => { - - - {{ health?.localstack ? 'Running' : 'Offline' }} + + + {{ engineRunning ? 'Running' : 'Offline' }} - {{ config?.localstack?.endpoint || '—' }} + {{ config?.engine?.endpoint || '—' }} - - {{ config?.localstack?.image || '—' }} - - - {{ config?.localstack?.mode || '—' }} + + + + this process — no Docker @@ -229,7 +245,7 @@ onBeforeUnmount(() => { {{ config?.serverPort || '—' }} - + (); const router = useRouter(); @@ -402,7 +403,7 @@ watch(() => props.serviceName, load); ('localstack'); + +export function applyEngineKind(kind: EngineKind | undefined): void { + if (kind) engineKind.value = kind; +} + +export const isSelfEngine = computed(() => engineKind.value === 'self'); + +/** Display name for the active engine — use in any user-facing string. */ +export const engineLabel = computed(() => (isSelfEngine.value ? 'Self engine' : 'LocalStack')); diff --git a/tests/unit/cli/cli.test.ts b/tests/unit/cli/cli.test.ts index 0f9b5a4..0f47df2 100644 --- a/tests/unit/cli/cli.test.ts +++ b/tests/unit/cli/cli.test.ts @@ -810,6 +810,37 @@ describe('bin/cli.js helpers', () => { expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Self Engine: http://localhost:14566')); }); + // The self engine's whole premise is "no LocalStack here". Exporting + // LSS_LOCALSTACK_* would also make GET /api/config report those keys as + // env-overridden, greying them out in the Settings tab for values the user + // never set. + it('exports no LocalStack env var in self-engine mode', () => { + jest.useFakeTimers(); + mockFs.existsSync.mockImplementation((p: any) => { + const s = String(p); + return s.endsWith('index.js') || s.endsWith('lss.config.json'); + }); + mockFs.readFileSync.mockReturnValue( + JSON.stringify({ engine: 'self', localstackPort: 4600, localstackVersion: '3.0', localstackImage: 'my/img' }), + ); + mockSpawn.mockReturnValue(makeChild() as any); + const cli = loadCli(['node', 'cli.js', 'start']); + cli.startOrchestrator(); + const [, , opts] = mockSpawn.mock.calls[0]; + const env = (opts as any).env; + expect(env.LSS_ENGINE).toBe('self'); + for (const key of [ + 'LSS_LOCALSTACK_PORT', + 'LSS_LOCALSTACK_MODE', + 'LSS_LOCALSTACK_EDITION', + 'LSS_LOCALSTACK_VERSION', + 'LSS_LOCALSTACK_IMAGE', + 'LOCALSTACK_AUTH_TOKEN', + ]) { + expect(env[key]).toBeUndefined(); + } + }); + it('engine "self" from the config file selects the self engine with its configured port', () => { jest.useFakeTimers(); mockFs.existsSync.mockImplementation((p: any) => { diff --git a/tests/unit/dev/dynamo-proxy.test.ts b/tests/unit/dev/dynamo-proxy.test.ts index 6f16f9c..78418c5 100644 --- a/tests/unit/dev/dynamo-proxy.test.ts +++ b/tests/unit/dev/dynamo-proxy.test.ts @@ -73,11 +73,37 @@ describe('startDynamoProxy', () => { it('defaults the port to 8000 when not provided', async () => { // Stub http.createServer so we never bind 8000; assert the default arg is used. - const fakeServer = { listen: jest.fn((_p: number, cb?: () => void) => cb && cb()) } as unknown as http.Server; + const fakeServer = { + listen: jest.fn((_p: number, cb?: () => void) => cb && cb()), + on: jest.fn(), + } as unknown as http.Server; const spy = jest.spyOn(http, 'createServer').mockReturnValue(fakeServer); const returned = startDynamoProxy('http://localhost:4566'); expect(returned).toBe(fakeServer); expect(spy).toHaveBeenCalled(); expect((fakeServer.listen as jest.Mock)).toHaveBeenCalledWith(8000, expect.any(Function)); + expect((fakeServer.on as jest.Mock)).toHaveBeenCalledWith('error', expect.any(Function)); + }); + + // The proxy is optional: a busy port warns and leaves the orchestrator up, + // instead of throwing an unhandled 'error' event that kills the process. + it('warns instead of throwing when the port is already in use', () => { + const handlers: Record void> = {}; + const fakeServer = { + listen: jest.fn(), + on: jest.fn((event: string, handler: (err: NodeJS.ErrnoException) => void) => { + handlers[event] = handler; + }), + } as unknown as http.Server; + jest.spyOn(http, 'createServer').mockReturnValue(fakeServer); + const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined); + + startDynamoProxy('http://localhost:4566', 8123); + handlers.error(Object.assign(new Error('bind failed'), { code: 'EADDRINUSE' })); + expect(warn).toHaveBeenCalledWith(expect.stringContaining('port 8123 is already in use')); + + handlers.error(Object.assign(new Error('some other failure'), { code: 'EACCES' })); + expect(warn).toHaveBeenCalledWith(expect.stringContaining('some other failure')); + warn.mockRestore(); }); }); diff --git a/tests/unit/engine/dispatch/helpers.ts b/tests/unit/engine/dispatch/helpers.ts index a7f077f..a8c436a 100644 --- a/tests/unit/engine/dispatch/helpers.ts +++ b/tests/unit/engine/dispatch/helpers.ts @@ -48,9 +48,23 @@ export function makeCtx(overrides: Partial = {}): Test return { ctx, dir, + // Root cause of the intermittent `ENOTEMPTY: rmdir '/tmp/lss-engine-dispatch-*'`: + // catalog writes are debounced (20 ms) and WAL appends are buffered, so the + // old cleanup raced the store — rm walked the tree while a flush was still + // creating files in it. flushAll() drains both; the retry covers the tail a + // dispatch loop's synchronous stop() can still emit under parallel load. cleanup: async () => { store.stopSweeper(); - await fs.promises.rm(dir, { recursive: true, force: true }); + await store.flushAll(); + for (let attempt = 0; ; attempt++) { + try { + await fs.promises.rm(dir, { recursive: true, force: true }); + return; + } catch (err) { + if ((err as NodeJS.ErrnoException).code !== 'ENOTEMPTY' || attempt >= 4) throw err; + await new Promise(resolve => setTimeout(resolve, 25)); + } + } }, }; } diff --git a/tests/unit/engine/store/item-table.test.ts b/tests/unit/engine/store/item-table.test.ts index 5691f40..3f04167 100644 --- a/tests/unit/engine/store/item-table.test.ts +++ b/tests/unit/engine/store/item-table.test.ts @@ -233,6 +233,39 @@ describe('compaction', () => { await table.compact(); expect(fs.existsSync(snapshotPath('db/t'))).toBe(false); }); + + // Compaction used to be reachable only through dehydrate(), which the idle + // sweep and the LRU budget drive — so a table under sustained write load + // never compacted and its WAL grew for the whole session (replayed in full on + // the next boot). A hot table has to fold its own WAL back into the snapshot. + test('a hot table self-compacts once the WAL outgrows the resident data', async () => { + const table = makeStore().table('db/hot'); + await table.hydrate(); + + // Rewrite the same few keys with a large payload: resident size stays flat + // while the WAL keeps growing, which is exactly the runaway case. + const payload = 'x'.repeat(64 * 1024); + for (let i = 0; i < 200; i++) { + table.put(`k${i % 4}`, `${i}:${payload}`); + await table.flush(); + } + + // Give the background compaction its turn. + for (let i = 0; i < 50 && fs.statSync(walPath('db/hot')).size > 8 * 1024 * 1024; i++) { + await sleep(20); + } + + const walSize = fs.statSync(walPath('db/hot')).size; + const totalWritten = 200 * payload.length; // ~13 MB of appends + expect(walSize).toBeLessThan(totalWritten / 2); + expect(fs.existsSync(snapshotPath('db/hot'))).toBe(true); + + // The fold must be lossless: a fresh store replays snapshot + WAL tail. + const replayed = makeStore().table('db/hot'); + await replayed.hydrate(); + expect(replayed.size()).toBe(4); + expect(replayed.get('k3')).toBe(`199:${payload}`); + }); }); describe('dehydrate / destroy', () => { diff --git a/tests/unit/engine/store/memory-store.test.ts b/tests/unit/engine/store/memory-store.test.ts new file mode 100644 index 0000000..3dbc682 --- /dev/null +++ b/tests/unit/engine/store/memory-store.test.ts @@ -0,0 +1,143 @@ +// `persistence: false` swaps the file-backed store for the in-memory one. +// The contract under test is the promise the flag makes: nothing is written to +// dataDir, and a fresh store starts empty — that is what makes an automated +// test run reproducible and what keeps a disabled feature from leaving a +// `.lss/engine/` tree behind. +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { createEngineStore } from '../../../../src/server/engine/store/engine-store.js'; +import { MemoryEngineStore } from '../../../../src/server/engine/store/memory-store.js'; + +let dataDir: string; + +const makeStore = (persistence: boolean | undefined) => + createEngineStore({ dataDir, idleUnloadMs: 300_000, memoryBudgetMb: 128, fsync: false, persistence }); + +beforeEach(() => { + dataDir = path.join(os.tmpdir(), `lss-memory-store-${process.pid}-${Math.random().toString(36).slice(2)}`); +}); + +afterEach(() => { + fs.rmSync(dataDir, { recursive: true, force: true }); +}); + +describe('createEngineStore(persistence)', () => { + test('persistence:false selects the in-memory store and never touches dataDir', async () => { + const store = makeStore(false); + expect(store).toBeInstanceOf(MemoryEngineStore); + + const catalog = store.catalog<{ n: number }>('dynamodb/us-east-1/tables'); + await catalog.load(); + catalog.set('users', { n: 1 }); + await catalog.flush(); + store.table('dynamodb/us-east-1/users/items').put('k', { v: 1 }); + await store.flushAll(); + + expect(fs.existsSync(dataDir)).toBe(false); + }); + + test('persistence:true (and the default) still selects the file store', () => { + expect(makeStore(true)).not.toBeInstanceOf(MemoryEngineStore); + expect(makeStore(undefined)).not.toBeInstanceOf(MemoryEngineStore); + expect(fs.existsSync(dataDir)).toBe(true); + }); + + test('a second in-memory store starts empty (clean slate per run)', () => { + makeStore(false).catalog<{ n: number }>('c').set('a', { n: 1 }); + expect(makeStore(false).catalog<{ n: number }>('c').get('a')).toBeUndefined(); + }); +}); + +describe('MemoryEngineStore', () => { + let store: MemoryEngineStore; + + beforeEach(() => { + store = new MemoryEngineStore(); + }); + + test('dir() returns a virtual path and creates nothing', () => { + const dir = store.dir('s3', 'bucket', 'blobs'); + expect(dir).toBe('/lss-memory/s3/bucket/blobs'); + expect(fs.existsSync(dir)).toBe(false); + expect(store.dir()).toBe('/lss-memory'); + }); + + test('catalog: memoized, CRUD, keys/values, load/flush are no-ops', async () => { + const catalog = store.catalog('cat'); + expect(store.catalog('cat')).toBe(catalog); + + await catalog.load(); + catalog.set('a', 1); + catalog.set('b', 2); + expect(catalog.get('a')).toBe(1); + expect(catalog.get('missing')).toBeUndefined(); + expect(catalog.keys()).toEqual(['a', 'b']); + expect(catalog.values()).toEqual([1, 2]); + expect(catalog.delete('a')).toBe(true); + expect(catalog.delete('a')).toBe(false); + await expect(catalog.flush()).resolves.toBeUndefined(); + }); + + test('table: memoized, CRUD, insertion order, size and byte accounting', async () => { + const table = store.table('t'); + expect(store.table('t')).toBe(table); + + await table.hydrate(); + expect(table.isHydrated()).toBe(true); + + table.put('k1', { v: 'a' }); + table.put('k2', { v: 'b' }); + const afterTwo = table.approxBytes(); + expect(afterTwo).toBeGreaterThan(0); + + // Overwrite must replace, not double-count. + table.put('k1', { v: 'aaaaaaaaaa' }); + expect(table.size()).toBe(2); + expect(table.approxBytes()).toBeGreaterThan(afterTwo); + + expect(table.get('k1')).toEqual({ v: 'aaaaaaaaaa' }); + expect(table.has('k2')).toBe(true); + expect(table.has('nope')).toBe(false); + expect([...table.entries()].map(([k]) => k)).toEqual(['k1', 'k2']); + + expect(table.delete('k1')).toBe(true); + expect(table.delete('k1')).toBe(false); + expect(table.size()).toBe(1); + expect(table.lastTouchedAt()).toBeGreaterThan(0); + }); + + test('table: flush/compact/dehydrate are inert and keep the rows', async () => { + const table = store.table('t'); + table.put('k', { v: 1 }); + await table.flush(); + await table.compact(); + // No snapshot to reload from — dehydrating would be data loss, not eviction. + await table.dehydrate(); + expect(table.isHydrated()).toBe(true); + expect(table.get('k')).toEqual({ v: 1 }); + + await table.destroy(); + expect(table.size()).toBe(0); + expect(table.approxBytes()).toBe(0); + }); + + test('blobs are content-addressed, readable, de-duplicated and deletable', async () => { + const body = Buffer.from('hello'); + const handle = await store.writeBlob('s3/b/blobs', body); + expect(handle).toBe(await store.writeBlob('s3/b/blobs', Buffer.from('hello'))); + expect(await store.readBlob(handle)).toEqual(body); + + const other = await store.writeBlob('s3/b/blobs', Buffer.from('world')); + expect(other).not.toBe(handle); + + await store.deleteBlob(handle); + await expect(store.readBlob(handle)).rejects.toMatchObject({ code: 'ENOENT' }); + }); + + test('sweeper and flushAll are no-ops', async () => { + store.startSweeper(); + store.stopSweeper(); + await expect(store.flushAll()).resolves.toBeUndefined(); + }); +}); diff --git a/tests/unit/routes/lambdas.test.ts b/tests/unit/routes/lambdas.test.ts index 880ed97..bc540a1 100644 --- a/tests/unit/routes/lambdas.test.ts +++ b/tests/unit/routes/lambdas.test.ts @@ -93,6 +93,9 @@ describe('GET /api/lambdas', () => { triggers: ['http'], invokePort: 13001, status: 'online', + // The stubbed RuntimeInfo carries no `warm`, so the route reports the + // conservative default: ready, but no worker forked yet. + warm: false, executionMode: 'source', invocations: 2, errors: 1, diff --git a/tests/unit/services/config-manager.test.ts b/tests/unit/services/config-manager.test.ts index 855c028..6f730c0 100644 --- a/tests/unit/services/config-manager.test.ts +++ b/tests/unit/services/config-manager.test.ts @@ -4,6 +4,7 @@ // and env overrides we mock fs, set process.env, then jest.resetModules() + // re-require to construct a fresh singleton under those conditions. import path from 'path'; +import { projectCacheSegment } from '../../../src/server/services/project-scope'; jest.mock('fs'); const fs = require('fs') as jest.Mocked; @@ -39,6 +40,7 @@ const LSS_ENV_VARS = [ 'LSS_INVOKE_HOST', 'LSS_ENGINE', 'LSS_ENGINE_PORT', + 'LSS_ENGINE_DATA_DIR', 'HOME', ]; @@ -698,6 +700,46 @@ describe('lambdaRuntime config', () => { expect(cm.getInvokePortOffset()).toBe(10000); }); + // A worker per registered service costs ~48 MB resident, and LSS is a + // development stack: a handler is only resident while it is being used. + it('lazy defaults to true and idleTimeoutMs to one minute', () => { + const cm = freshConfigManager(); + expect(cm.isLambdaRuntimeLazy()).toBe(true); + expect(cm.getLambdaIdleTimeoutMs()).toBe(60_000); + }); + + it('reads lazy/idleTimeoutMs from the config file', () => { + const cm = cmWith({ lambdaRuntime: { lazy: false, idleTimeoutMs: 900000 } }); + expect(cm.isLambdaRuntimeLazy()).toBe(false); + expect(cm.getLambdaIdleTimeoutMs()).toBe(900000); + }); + + it('treats an explicit 0 or a bad value as "keep workers alive forever"', () => { + expect(cmWith({ lambdaRuntime: { idleTimeoutMs: 0 } }).getLambdaIdleTimeoutMs()).toBe(0); + expect(cmWith({ lambdaRuntime: { idleTimeoutMs: -1 } }).getLambdaIdleTimeoutMs()).toBe(0); + expect(cmWith({ lambdaRuntime: { idleTimeoutMs: 'soon' } as never }).getLambdaIdleTimeoutMs()).toBe(0); + }); + + // The ceiling is what makes host memory a function of services in flight + // rather than services registered. + it('maxWarmWorkers defaults to one per GB of RAM, clamped to 2..12', () => { + const totalmem = jest.spyOn(require('os'), 'totalmem'); + totalmem.mockReturnValue(8 * 1024 ** 3); + expect(freshConfigManager().getLambdaMaxWarmWorkers()).toBe(8); + totalmem.mockReturnValue(1 * 1024 ** 3); // tiny host → floor of 2 + expect(freshConfigManager().getLambdaMaxWarmWorkers()).toBe(2); + totalmem.mockReturnValue(64 * 1024 ** 3); // big host → cap of 12 + expect(freshConfigManager().getLambdaMaxWarmWorkers()).toBe(12); + totalmem.mockRestore(); + }); + + it('honors an explicit maxWarmWorkers, including 0 (no ceiling)', () => { + expect(cmWith({ lambdaRuntime: { maxWarmWorkers: 3 } }).getLambdaMaxWarmWorkers()).toBe(3); + expect(cmWith({ lambdaRuntime: { maxWarmWorkers: 0 } }).getLambdaMaxWarmWorkers()).toBe(0); + // Garbage falls back to the RAM-derived default rather than uncapping. + expect(cmWith({ lambdaRuntime: { maxWarmWorkers: -2 } }).getLambdaMaxWarmWorkers()).toBeGreaterThan(0); + }); + it('LSS_LAMBDA_RUNTIME=true / "1" enables, anything else disables', () => { process.env.LSS_LAMBDA_RUNTIME = 'true'; expect(freshConfigManager().isLambdaRuntimeEnabled()).toBe(true); @@ -939,10 +981,23 @@ describe('engine selection (self engine)', () => { expect(resolved.account).toBe('111111111111'); }); + // Port + data dir from the environment is all a second instance needs: no + // config file to write, nothing shared with the dev stack. + it('LSS_ENGINE_DATA_DIR overrides the resolved dataDir', () => { + process.env.LSS_ENGINE_DATA_DIR = '/tmp/lss-run-7/engine'; + const cm = cmWith({ engine: 'self', selfEngine: { dataDir: '/from/file' } }); + expect(cm.getSelfEngineConfig().dataDir).toBe('/tmp/lss-run-7/engine'); + }); + it('getSelfEngineConfig applies every default', () => { - const resolved = freshConfigManager().getSelfEngineConfig(); + const cm = freshConfigManager(); + const resolved = cm.getSelfEngineConfig(); expect(resolved.port).toBe(14566); - expect(resolved.dataDir).toBe(path.join(require('os').homedir(), '.lss', 'engine')); + // With no stateDir the fallback root is scoped to this project — a flat + // ~/.lss/engine made every checkout on the machine share one engine state. + expect(resolved.dataDir).toBe( + path.join(require('os').homedir(), '.lss', 'projects', projectCacheSegment(cm.getProjectRoot()), 'engine'), + ); expect(resolved.account).toBe('000000000000'); expect(resolved.idleUnloadMs).toBe(300000); expect(resolved.memoryBudgetMb).toBe(128); @@ -1027,12 +1082,15 @@ describe('getAossSidecarConfig', () => { return freshConfigManager(); } - it('defaults: enabled on the LocalStack engine, port 14567, dataDir under ~/.lss', () => { - const resolved = freshConfigManager().getAossSidecarConfig(); + it('defaults: enabled on the LocalStack engine, port 14567, per-project dataDir under ~/.lss', () => { + const cm = freshConfigManager(); + const resolved = cm.getAossSidecarConfig(); expect(resolved.enabled).toBe(true); expect(resolved.port).toBe(14567); expect(resolved.endpoint).toBe('http://localhost:14567'); - expect(resolved.dataDir).toBe(path.join(require('os').homedir(), '.lss', 'aoss')); + expect(resolved.dataDir).toBe( + path.join(require('os').homedir(), '.lss', 'projects', projectCacheSegment(cm.getProjectRoot()), 'aoss'), + ); }); it('defaults dataDir under stateDir when stateDir is set (test isolation)', () => { @@ -1337,6 +1395,19 @@ describe('updateConfig', () => { expect(fs.writeFileSync).not.toHaveBeenCalled(); }); + // idleTimeoutMs accepts 0 (meaning "never unload"), so it validates as + // nonNegativeInt rather than positiveInt. + it('rejects a negative or fractional idleTimeoutMs but accepts 0', () => { + expect(updateErr(setupFile({}), { lambdaRuntime: { idleTimeoutMs: -5 } }).details).toEqual([ + '"lambdaRuntime.idleTimeoutMs" must be an integer >= 0', + ]); + expect(updateErr(setupFile({}), { lambdaRuntime: { idleTimeoutMs: 1.5 } }).details).toEqual([ + '"lambdaRuntime.idleTimeoutMs" must be an integer >= 0', + ]); + const cm = setupFile({}); + expect(() => cm.updateConfig({ lambdaRuntime: { idleTimeoutMs: 0 } })).not.toThrow(); + }); + it('validates subkeys of fixed-shape object blocks — garbage never reaches the file', () => { const cm = setupFile({}); expect(updateErr(cm, { selfEngine: { dataDir: 123 } }).details).toEqual([ diff --git a/tests/unit/services/dynamo-explorer.test.ts b/tests/unit/services/dynamo-explorer.test.ts index 77a8cd8..0109f7c 100644 --- a/tests/unit/services/dynamo-explorer.test.ts +++ b/tests/unit/services/dynamo-explorer.test.ts @@ -69,6 +69,22 @@ describe('listTables / summarize', () => { expect(await explorer.listTables()).toEqual([]); }); + // ListTables caps a page at 100 names. A monorepo with 40 services x 10 + // tables has 400 — without following LastEvaluatedTableName the dashboard + // silently showed the first quarter. + it('follows LastEvaluatedTableName across pages', async () => { + ddbMock + .on(ListTablesCommand, { ExclusiveStartTableName: undefined }) + .resolves({ TableNames: ['a', 'b'], LastEvaluatedTableName: 'b' }) + .on(ListTablesCommand, { ExclusiveStartTableName: 'b' }) + .resolves({ TableNames: ['c'], LastEvaluatedTableName: 'c' }) + .on(ListTablesCommand, { ExclusiveStartTableName: 'c' }) + .resolves({ TableNames: ['d'] }); + + expect(await explorer.listTableNames()).toEqual(['a', 'b', 'c', 'd']); + expect(ddbMock.commandCalls(ListTablesCommand)).toHaveLength(3); + }); + it('summarizes each table with full metadata (GSI/LSI/stream/ttl/billing/created)', async () => { ddbMock.on(ListTablesCommand).resolves({ TableNames: ['t1'] }); ddbMock.on(DescribeTableCommand).resolves({ diff --git a/tests/unit/services/explorer-region.test.ts b/tests/unit/services/explorer-region.test.ts new file mode 100644 index 0000000..1d0f320 --- /dev/null +++ b/tests/unit/services/explorer-region.test.ts @@ -0,0 +1,38 @@ +// applyRegionToExplorers pins the default region on every explorer/inspector. +// The dashboard always sends `?region=`, so a wrong default only ever hurt the +// callers that omit it (CLI, LssClient, curl) — this is the guard that keeps +// a newly added explorer from silently regressing to us-east-1. +import { applyRegionToExplorers } from '../../../src/server/services/explorer-region'; +import { DynamoExplorer } from '../../../src/server/services/dynamo-explorer'; +import { S3Explorer } from '../../../src/server/services/s3-explorer'; +import { SecretsExplorer } from '../../../src/server/services/secrets-explorer'; +import { OpenSearchExplorer } from '../../../src/server/services/opensearch-explorer'; +import { QueueInspector } from '../../../src/server/services/queue-inspector'; + +const singletons = () => [ + DynamoExplorer.getInstance(), + S3Explorer.getInstance(), + SecretsExplorer.getInstance(), + OpenSearchExplorer.getInstance(), + QueueInspector.getInstance(), +]; + +beforeEach(() => { + for (const s of singletons()) (s as any).defaultRegion = 'us-east-1'; +}); + +describe('applyRegionToExplorers', () => { + it('pins the region on every explorer and inspector', () => { + applyRegionToExplorers('sa-east-1'); + for (const s of singletons()) { + expect((s as any).defaultRegion).toBe('sa-east-1'); + } + }); + + it('is a no-op for an empty region (config without one keeps the default)', () => { + applyRegionToExplorers(''); + for (const s of singletons()) { + expect((s as any).defaultRegion).toBe('us-east-1'); + } + }); +}); diff --git a/tests/unit/services/queue-inspector.test.ts b/tests/unit/services/queue-inspector.test.ts index 2a3ebcd..a57e8ec 100644 --- a/tests/unit/services/queue-inspector.test.ts +++ b/tests/unit/services/queue-inspector.test.ts @@ -112,6 +112,23 @@ describe('listQueues', () => { expect(await inspector.listQueues()).toEqual([]); }); + // ListQueues answers at most 1000 URLs per page; a truncated list would drop + // queues (and their consumers) from the dashboard and from await-idle. + it('follows NextToken across pages', async () => { + sqsMock + .on(ListQueuesCommand, { NextToken: undefined }) + .resolves({ QueueUrls: [URL_Q], NextToken: 'page-2' }) + .on(ListQueuesCommand, { NextToken: 'page-2' }) + .resolves({ QueueUrls: [URL_FIFO] }); + sqsMock.on(GetQueueAttributesCommand).resolves({ + Attributes: { ApproximateNumberOfMessages: '0', ApproximateNumberOfMessagesNotVisible: '0', QueueArn: ARN_Q }, + }); + lambdaMock.on(ListEventSourceMappingsCommand).resolves({ EventSourceMappings: [] }); + + const queues = await inspector.listQueues(); + expect(queues.map(q => q.name)).toEqual(['q', 'q.fifo']); + }); + it('builds snapshots for each queue and drops the ones that fail', async () => { sqsMock.on(ListQueuesCommand).resolves({ QueueUrls: [URL_Q, URL_FIFO] }); sqsMock.on(GetQueueAttributesCommand, { QueueUrl: URL_Q }).resolves({ diff --git a/tests/unit/services/resource-provisioner.test.ts b/tests/unit/services/resource-provisioner.test.ts index 5e00ded..6f32164 100644 --- a/tests/unit/services/resource-provisioner.test.ts +++ b/tests/unit/services/resource-provisioner.test.ts @@ -1373,6 +1373,28 @@ describe('listAllResources', () => { expect(result).toEqual({ tables: ['t1'], queues: ['q1'], topics: ['topic1'], buckets: ['b1'], collections: ['products'] }); }); + // GET /api/resources is built from these lists. ListTables caps a page at + // 100 names and ListQueues at 1000 — a 40-service monorepo crosses both. + it('pages through ListTables and ListQueues', async () => { + dynamoMock + .on(ListTablesCommand, { ExclusiveStartTableName: undefined }) + .resolves({ TableNames: ['t1'], LastEvaluatedTableName: 't1' }) + .on(ListTablesCommand, { ExclusiveStartTableName: 't1' }) + .resolves({ TableNames: ['t2'] }); + sqsMock + .on(ListQueuesCommand, { NextToken: undefined }) + .resolves({ QueueUrls: ['http://localhost:4566/000/q1'], NextToken: 'p2' }) + .on(ListQueuesCommand, { NextToken: 'p2' }) + .resolves({ QueueUrls: ['http://localhost:4566/000/q2'] }); + snsMock.on(ListTopicsCommand).resolves({ Topics: [] }); + s3Mock.on(ListBucketsCommand).resolves({ Buckets: [] }); + openSearchMock.on(ListCollectionsCommand).resolves({ collectionSummaries: [] }); + + const result = await provisioner.listAllResources(); + expect(result.tables).toEqual(['t1', 't2']); + expect(result.queues).toEqual(['q1', 'q2']); + }); + it('builds fresh clients for a different region', async () => { dynamoMock.on(ListTablesCommand).resolves({ TableNames: [] }); sqsMock.on(ListQueuesCommand).resolves({ QueueUrls: [] }); diff --git a/tests/unit/services/seed-manager.test.ts b/tests/unit/services/seed-manager.test.ts index 0f3e947..7245ee1 100644 --- a/tests/unit/services/seed-manager.test.ts +++ b/tests/unit/services/seed-manager.test.ts @@ -147,6 +147,17 @@ describe('listLiveTables / listTables', () => { ddbMock.on(ListTablesCommand).rejects(new Error('down')); expect(await manager.listLiveTables()).toEqual([]); }); + + // Past the 100-name page cap the seed↔table mismatch diagnostic would report + // every table beyond the first page as "seed file with no live table". + it('follows LastEvaluatedTableName across pages', async () => { + ddbMock + .on(ListTablesCommand, { ExclusiveStartTableName: undefined }) + .resolves({ TableNames: ['A'], LastEvaluatedTableName: 'A' }) + .on(ListTablesCommand, { ExclusiveStartTableName: 'A' }) + .resolves({ TableNames: ['B'] }); + expect(await manager.listLiveTables()).toEqual(['A', 'B']); + }); }); describe('list', () => { From dee4ee83eacdd73447c4af46aaa0017e80b35d2f Mon Sep 17 00:00:00 2001 From: Viserion77 Date: Fri, 31 Jul 2026 00:12:17 +0000 Subject: [PATCH 02/16] feat(mcp): add TypeScript configuration and initial server implementation - Created a new TypeScript configuration file for the MCP module. - Updated the UI to reflect the new project branding with a new favicon and title. - Added a new SVG favicon for the project. - Implemented unit tests for the MCP CLI commands, ensuring proper resolution of the MCP server path and package version handling. - Introduced unit tests for the MCP HTTP layer, covering base URL resolution and HTTP request handling. - Developed tests for the MCP JSON-RPC protocol, including handshake and tool invocation. - Added tests for the MCP server's stdio handling, ensuring correct response framing and error reporting. - Created tests for various MCP tools, validating their endpoint mappings and input handling. --- .mcp.json | 8 + .vscode/tasks.json | 4 +- AGENTS.md | 2 + README.md | 7 + REVISAO-2026-07-29.md | 117 +++++++++++- assets/icon.svg | 37 ++++ assets/logo.svg | 38 ++++ bin/cli.js | 53 ++++++ docs/FEATURES.md | 18 ++ docs/MCP.md | 126 +++++++++++++ jest.config.js | 1 + package-lock.json | 4 +- package.json | 16 +- src/mcp/http.ts | 94 ++++++++++ src/mcp/protocol.ts | 127 +++++++++++++ src/mcp/server.ts | 51 +++++ src/mcp/tools.ts | 319 ++++++++++++++++++++++++++++++++ src/mcp/tsconfig.json | 9 + src/ui/index.html | 4 +- src/ui/public/favicon.svg | 37 ++++ tests/unit/cli/cli.test.ts | 33 ++++ tests/unit/mcp/http.test.ts | 144 ++++++++++++++ tests/unit/mcp/protocol.test.ts | 160 ++++++++++++++++ tests/unit/mcp/server.test.ts | 104 +++++++++++ tests/unit/mcp/tools.test.ts | 177 ++++++++++++++++++ 25 files changed, 1677 insertions(+), 13 deletions(-) create mode 100644 .mcp.json create mode 100644 assets/icon.svg create mode 100644 assets/logo.svg create mode 100644 docs/MCP.md create mode 100644 src/mcp/http.ts create mode 100644 src/mcp/protocol.ts create mode 100644 src/mcp/server.ts create mode 100644 src/mcp/tools.ts create mode 100644 src/mcp/tsconfig.json create mode 100644 src/ui/public/favicon.svg create mode 100644 tests/unit/mcp/http.test.ts create mode 100644 tests/unit/mcp/protocol.test.ts create mode 100644 tests/unit/mcp/server.test.ts create mode 100644 tests/unit/mcp/tools.test.ts diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..421344c --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "lss": { + "command": "node", + "args": ["./bin/cli.js", "mcp"] + } + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ff186d6..35c2b1f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -117,9 +117,9 @@ }, { "label": "typecheck: all projects", - "detail": "tsc --noEmit em server/client/plugin + vue-tsc na UI", + "detail": "tsc --noEmit em server/client/mcp/plugin + vue-tsc na UI", "type": "shell", - "command": "npx tsc --noEmit -p src/server/tsconfig.json && npx tsc --noEmit -p src/client/tsconfig.json && npx tsc --noEmit -p packages/serverless-plugin/tsconfig.json && cd src/ui && npx vue-tsc --noEmit", + "command": "npx tsc --noEmit -p src/server/tsconfig.json && npx tsc --noEmit -p src/client/tsconfig.json && npx tsc --noEmit -p src/mcp/tsconfig.json && npx tsc --noEmit -p packages/serverless-plugin/tsconfig.json && cd src/ui && npx vue-tsc --noEmit", "group": "test", "icon": { "id": "verified", "color": "terminal.ansiBlue" }, "problemMatcher": ["$tsc"] diff --git a/AGENTS.md b/AGENTS.md index 25da080..0e7e6e1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,6 +28,7 @@ Published as the npm package `local-serverless-stack` (CLI: `lss`), plus the wor | `src/server/` | The orchestrator: `index.ts` (boot), `routes/` (HTTP API), `services/` (registrar, CFN parser, provisioner, seeds, gateway/lambda managers), `runtime/` (Lambda workers), `dev/` | | `src/server/engine/` | **The self engine.** `emulators/` (dynamodb, sqs, sns, s3, events, secretsmanager, opensearch, lambda-ctl, sts), `dispatch/` (stream-tailer, sqs-poller, scheduler, dispatcher), `store/` (JSONL snapshot + WAL), `http/` (router, sigv4, protocols), `bus.ts` | | `src/client/` | `LssClient` — the programmatic API | +| `src/mcp/` | MCP server (`lss mcp`) — the stack as tools for an AI coding agent | | `src/ui/` | Vue 3 dashboard (own workspace) | | `packages/serverless-plugin/` | The `serverless-lss` plugin (separately versioned & published) | | `examples/` | `self-hosted` (self engine, no Docker), `localstack-free`, `localstack-ultimate` | @@ -63,6 +64,7 @@ it mirrors CI. Shell equivalent: npm run lint \ && npx tsc --noEmit -p src/server/tsconfig.json \ && npx tsc --noEmit -p src/client/tsconfig.json \ + && npx tsc --noEmit -p src/mcp/tsconfig.json \ && npx tsc --noEmit -p packages/serverless-plugin/tsconfig.json \ && (cd src/ui && npx vue-tsc --noEmit) \ && npm run test:coverage \ diff --git a/README.md b/README.md index 43f71a1..73fb4a8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +

+ LSS Self Engine +

+ # Local Serverless Stack (LSS) [![npm version](https://img.shields.io/npm/v/local-serverless-stack.svg)](https://www.npmjs.com/package/local-serverless-stack) @@ -57,6 +61,9 @@ LSS features come in two layers: - Lambda authorizers: REST `token`/`request`, HTTP API `request` (simple responses), identity-source extraction, TTL cache + cache-clear, cross-service resolution by ARN - Raw `AWS::ApiGatewayV2::*` routes from CFN `resources:` — on their own `::Api` or the framework's `HttpApi`; `Target`/`IntegrationUri`/`AuthorizerUri`/`SourceArn` reduced through `Fn::Sub` (incl. `${Id.Arn}`), `Fn::Join`, `Fn::GetAtt`, `Fn::ImportValue` and the apigateway invocation-URI wrapper; de-duplicated against `httpApi:` events - Hot reload: source changes restart the worker; `serverless.yml` changes re-package + re-register +- **MCP server** (`npx lss mcp`) — exposes the running stack to an AI coding agent (Claude Code and any + other MCP client) as 23 tools: inspect resources, invoke Lambdas, scan tables, send messages and + block on `await-idle`. Zero new dependencies, off until a client is configured. See [docs/MCP.md](docs/MCP.md) - **Explorers & testing primitives** (HTTP API + dashboard) - **Queues** (`/api/queues`): list + metrics (available/inFlight/processed/delayed), send/receive/delete/purge (FIFO group/dedup), `reset-processed`, `await-idle` (block until drained), `hold`/`captured`/`release` (capture-and-replay) - **DynamoDB** (`/api/dynamo`): list/describe (keys, GSI/LSI, stream, TTL), scan/query with filters, item CRUD, get/set TTL diff --git a/REVISAO-2026-07-29.md b/REVISAO-2026-07-29.md index 217a09c..1bac052 100644 --- a/REVISAO-2026-07-29.md +++ b/REVISAO-2026-07-29.md @@ -37,7 +37,7 @@ Medição do antes/depois com 40 serviços registrados, ociosos: | cold start da 1ª invocação | — | **~23 ms** (morno: ~1 ms) | | watches inotify por serviço | 1.756 | 4 | -O gate `validate: pre-prod` passa inteiro: lint 0 erros, `tsc` nos 4 projetos, **2.405 testes +O gate `validate: pre-prod` passa inteiro: lint 0 erros, `tsc` nos 4 projetos, **2.462 testes verdes com cobertura 100%**, build completo. --- @@ -443,6 +443,121 @@ não documentado; 76 `style=` inline violando o contrato TreeUI sem registro no --- +--- + +## 5b. Segunda rodada — v0.18.0, MCP, logo e o veredito da v2 + +### Bump + +`0.17.2 → **0.18.0**` (raiz + lockfile). Minor, não patch: os defaults de residência do runtime +Lambda mudam comportamento observável, e há superfície nova de API (`warm`, `runtimeWarm`, +`engineRunning`, 404 em `/api/*`) e o servidor MCP. O plugin `serverless-lss` continua em `0.2.2` +— nada nele mudou. **Não há hook de pre-commit no repo** (`.git/hooks` só tem samples, sem +husky/lint-staged); o portão que rodei é o `validate: pre-prod`. + +### O critério da v2 — testado, não estimado + +Você condicionou a v2 a "rodar tudo que damos suporte ao LocalStack Ultimate no modo self". +Rodei os **dois exemplos LocalStack inteiros contra o self engine**, sem Docker e sem token. + +**`localstack-ultimate`** (região `eu-west-1`, 45 recursos): registrou com os mesmos dois avisos +que dá no LocalStack (`SecurityPolicy`/`AccessPolicy` de OpenSearch são no-op nos dois). Todos os +caminhos dispararam, **zero erros**: + +| caminho | prova | +|---|---| +| REST `http:` payload v1 | `/health`, `/users`, `/orders`, `/uploads`, `/audit`, `/products`, `/search`, `/stats` | +| DynamoDB chave composta + GSI `ByStatus` + seeds | `listUsers` devolveu seeds + registro novo | +| SQS + **DLQ redrive** (`maxReceiveCount: 3`) | pedido envenenado parou na `-OrderProcessingDLQ` | +| DynamoDB Streams → Lambda → **SNS Publish** | `onOrderStream` inv=3, `published order.insert ...` | +| EventBridge bus + regra com pattern | `auditEvents` inv=2, gravou no `AuditTrail` | +| **Schedule `rate(2 minutes)`** | `purgeSessions` inv=1 | +| S3 notificação com filtro `prefix: incoming/` | `onUpload` inv=1 | +| OpenSearch Serverless | index + `multi_match` + agregação | + +**`localstack-free`** (região `sa-east-1`): 4 dos 5 stacks registraram e rodaram — REST authorizer +v1 local (`whoami`), **httpApi v2 simple-response authorizer em TypeScript** (source mode), +**authorizer cross-service por ARN** (orders-service usando o do auth-service), httpApi + REST, +SQS→Lambda, Streams→Lambda, EventBridge cross-service (`onUserSignedUp`), tópico SNS e bucket +provisionados. `AWS::Events::Archive` avisa e pula — igual ao LocalStack, que "mocka" Archives. + +> O 5º (`gateway-stack`, ApiGatewayV2 raw) não empacotou **na minha cópia**: ele nunca teve +> `node_modules` instalado no repo e eu não posso rodar `npm install` (AGENTS.md §1). É limitação +> de empacotamento, não do engine — o caminho raw ApiGatewayV2 é código do gateway do LSS, +> idêntico nos dois engines, coberto por 4 suítes unitárias. + +**Veredito: o critério está atendido.** As lacunas documentadas que sobram no self engine +(fan-out/assinaturas de SNS, protocolo Query legado do SQS, multipart do S3, `UpdateTable`/PartiQL, +operadores `anything-but`/`numeric`/`suffix`/`wildcard`/`cidr` do EventBridge, versions/aliases de +Lambda, SigV4/IAM) **não são exercitadas por nenhum dos dois exemplos** — o `Publish` do ultimate +funciona porque ninguém assina o tópico. + +### Por que a v2 não está neste diff + +A v2, do seu jeito, é "self como default **e** sem LocalStack". Publicar um `2.0.0` com o +LocalStack ainda na árvore seria mentira no `package.json`, e a remoção é grande e destrutiva: + +| a remover | tamanho | +|---|---| +| `src/**` mencionando localstack | **367 linhas em 45 arquivos** | +| testes mencionando localstack | 201 linhas em 32 arquivos | +| módulos dedicados | `localstack-backend.ts`, `localstack-manager.ts`, `aoss-sidecar.ts` | +| exemplos + suíte de integração | `localstack-free` (483 MB), `localstack-ultimate` (142 MB), `tests/integration` (135 MB) | +| config | `mode`, `localstackPort/Endpoint/Edition/Version/Image/AuthToken`, `services`, `aossSidecar` + flags `--external/--pro/--localstack-token` | + +É uma passada própria, com seu próprio review — e apaga 760 MB e a única suíte de integração que +existe. **Não fiz sem seu ok.** Ordem que eu seguiria: + +1. `lss.config.json` da raiz → `engine: "self"` (o repo passa a se desenvolver no diferencial). +2. Inverter o default de `engine` para `'self'` e adicionar a flag simétrica `--localstack`. +3. Substituir `tests/integration` por uma suíte e2e no self engine — **sem Docker e sem token, roda + em qualquer CI**, o que hoje não acontece. Fazer isso *antes* de apagar, para não passar por um + ponto sem cobertura e2e nenhuma. +4. Apagar `localstack-backend.ts` / `localstack-manager.ts` / `aoss-sidecar.ts` e colapsar + `EngineManager` no self backend. +5. Remover as chaves de config, as flags de CLI e os campos da UI/client; `GET /api/config` perde o + bloco `localstack` (resolve o item 2 do §5). +6. Apagar os dois exemplos; promover `self-hosted` a exemplo principal. +7. Docs + `CHANGELOG` + `2.0.0`. + +### Servidor MCP (`npx lss mcp`) + +**23 tools** sobre a REST API do orquestrador, para um agente dirigir o stack em vez de receber +saída de `curl`. **Zero dependência nova** — JSON-RPC 2.0 sobre stdio implementado à mão em +`src/mcp/` (~250 linhas), porque eu não posso rodar `npm install` e o SDK oficial custaria mais do +que economiza. + +- `src/mcp/tools.ts` — catálogo; tools que mutam dizem `MUTATES` na descrição, que é o texto que o + cliente mostra ao humano antes de aprovar. +- `src/mcp/protocol.ts` — `initialize` / `ping` / `tools/list` / `tools/call`, puro e testável. +- `src/mcp/http.ts` — descoberta da base URL igual à do `LssClient`; erro de conexão vira **uma** + mensagem acionável (`npx lss start`), não um `TypeError` de fetch. +- `src/mcp/server.ts` — só a costura de stdio. +- `bin/cli.js` ganhou o comando `mcp`; `.mcp.json` na raiz registra o servidor no Claude Code. + +**Ligar/desligar:** o servidor não sobe sozinho — só quando um cliente o lança. No Claude Code, +`/mcp` lista, habilita e desabilita; remover a entrada do `.mcp.json` tira de vez. + +Provado contra o stack `localstack-ultimate` rodando no self engine: handshake, `tools/list` (23), +`lss_health`, `lss_resources`, `lss_invoke` de um handler real, `lss_dynamo_scan`, e uma fila +inexistente voltando `isError: true` com a mensagem do orquestrador. Guia: [docs/MCP.md](docs/MCP.md). + +Destaque para testes automatizados: `lss_queue_await_idle` bloqueia até a fila drenar, então o +agente faz arrange → act → **esperar** → assert num pipeline assíncrono em vez de chutar um sleep. + +### Logo + +`assets/icon.svg` (quadrado, 64×64) e `assets/logo.svg` (lockup horizontal com "LSS / SELF ENGINE"). + +O mark diz o que o produto é: **um chip, não uma nuvem**. O die é o processo do orquestrador, os +doze pinos são os serviços AWS que ele serve no fio, e o raio é a entrega de eventos in-process (sem +container no meio). Lê como raio-dentro-de-chip a 16 px e como die com pinout a 512 px. Paleta teal +(`#2dd4bf` → `#0d9488`) alinhada aos tokens de marca do exemplo `self-hosted`; o wordmark usa +`currentColor`, então inverte com o tema do dashboard. + +Também virou o favicon default do dashboard (`src/ui/public/favicon.svg`), que antes não tinha +nenhum — `branding.favicon` continua sobrescrevendo em runtime. + ## 6. Respostas diretas às suas perguntas **"Todas as features estão documentadas?"** Quase. A enumeração está boa — os 47 endpoints, diff --git a/assets/icon.svg b/assets/icon.svg new file mode 100644 index 0000000..d0babc5 --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1,37 @@ + + LSS Self Engine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..1fb349c --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,38 @@ + + LSS Self Engine + + + + + + + + + + + + + + + + + + + + + + + + + + + + LSS + SELF ENGINE + + diff --git a/bin/cli.js b/bin/cli.js index d631ce6..6d87dcd 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -4,6 +4,7 @@ const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); const os = require('os'); +const { pathToFileURL } = require('url'); // Default paths used when no config is present. The actual paths are derived // per-invocation by runtimePaths() below, scoped to the configured serverPort @@ -640,6 +641,49 @@ async function clearSeed(tableName) { } } +/** + * `lss mcp` — run the Model Context Protocol server on stdio. + * + * Started by an MCP client (Claude Code reads .mcp.json), never by a human at a + * prompt: stdout is the JSON-RPC frame stream, so nothing else may be written + * there. This process only talks HTTP to an already-running orchestrator — it + * never boots one — so `lss start` has to have happened first. + */ +function getMcpServerPath() { + const candidates = [ + path.join(__dirname, '../dist/mcp/server.js'), + path.join(__dirname, '..', 'dist', 'mcp', 'server.js'), + ]; + return candidates.find(candidate => fs.existsSync(candidate)) || null; +} + +function getPackageVersion() { + try { + return JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8')).version || '0.0.0'; + } catch { + return '0.0.0'; + } +} + +function runMcpServer() { + const serverPath = getMcpServerPath(); + const version = getPackageVersion(); + /* istanbul ignore else: the "found" path falls through to the dynamic import below, which is the process entry point (it binds this process's stdio) and so is not unit-testable */ + if (!serverPath) { + console.error('❌ MCP server build not found. Run `npm run build` first.'); + process.exit(1); // never returns + } + // Dynamic import: the MCP build is ESM, and loading it only for this command + // keeps every other CLI invocation free of it. + /* istanbul ignore next: process entry point — loads the ESM build and binds this process's stdio */ + import(pathToFileURL(serverPath).href) + .then(mod => mod.main(version)) + .catch(error => { + console.error('❌ Failed to start the MCP server:', error && error.message ? error.message : error); + process.exit(1); + }); +} + function showHelp() { console.log(` Local Serverless Stack (LSS) CLI @@ -657,6 +701,9 @@ Commands: tables with a seed file when no arg is given). Pede confirmação interativa (digitar "confirmar") antes de qualquer escrita. + mcp Run the Model Context Protocol server on stdio, so an MCP + client (Claude Code) can drive this stack with tools. + Requires a running orchestrator; see docs/MCP.md. help Show this help message Options: @@ -752,6 +799,9 @@ function firstPositional() { module.exports = { loadConfig, getConfig, + getMcpServerPath, + getPackageVersion, + runMcpServer, getArgValue, runtimePaths, getOrchestratorPath, @@ -798,6 +848,9 @@ if (require.main === module) { case 'seed:clear': clearSeed(firstPositional()); break; + case 'mcp': + runMcpServer(); + break; case 'help': case '--help': case '-h': diff --git a/docs/FEATURES.md b/docs/FEATURES.md index d4aaaaf..aeae644 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -23,6 +23,7 @@ by the live integration suite (`npm run test:integration`). | `lss stop` | Gracefully stops the orchestrator addressed by the active config. | integration (`features.test.ts` teardown) + unit (`cli`) | | `lss status` | Reports RUNNING/NOT RUNNING + ports for the addressed instance. | unit (`cli`) | | `lss logs` | Prints the tail of the instance log. | unit (`cli`) | +| `lss mcp` | Runs the MCP server on stdio for an AI coding agent. Requires a running orchestrator. | unit (`cli`, `mcp/*`) | | `lss seed [table]` | Applies `{table}.json` seed files from `seedsDir` into DynamoDB (all matching tables, or one). | unit (`cli-seed`) + integration | | `lss seed:clear [table]` | Deletes seeded items after an interactive `confirmar` prompt (or `--yes`); refuses any non-local endpoint. | unit (`cli-seed`, `seed-manager-guard`) | | `--config ` | Loads config from an explicit file, taking precedence over the cwd/home search; also via `LSS_CONFIG`. | unit (`cli`) + integration | @@ -196,6 +197,23 @@ serverless-offline process running. See `docs/PRD_API_LAMBDA_EMULATION.md` for t | `LssClient` namespaces | `lambdas.list/get/invoke/logs`, `apis.list/clearAuthorizerCache`, `services.runtime/startRuntime/stopRuntime`. | unit (`client/*`) | | Dashboard menus | Lambdas (list/detail with invoke + logs) and APIs (routes per service with listener status) sections in the Vue UI. | manual (like the rest of the UI) | +## 12b. MCP server (`npx lss mcp`) + +Exposes the running orchestrator to any [Model Context Protocol](https://modelcontextprotocol.io) client +(Claude Code included) as **23 tools**, so an AI agent drives the stack directly instead of being handed +`curl` output: health/config/ports, services, resources and owners, lambdas + per-invocation logs, invoke, +HTTP routes, DynamoDB tables/scan/query/put, queues + send + **await-idle**, buckets + object listings, +secrets (names only, never values), OpenSearch search, and seeds. + +JSON-RPC 2.0 over stdio, protocol revision `2024-11-05`, `tools` capability only — implemented in +`src/mcp/` with **no new runtime dependency**. It is a wrapper over this same REST API, so there is no +second source of truth. It never boots an orchestrator: a stack must already be running, and when none +answers, every tool returns one actionable error naming `npx lss start`. Mutating tools say `MUTATES` in +their description so a client can surface that before a human approves. Failures come back as error +*results* carrying the orchestrator's own message, not as transport errors. Off until a client is +configured; `.mcp.json` (project-scoped) plus the client's own toggle are the on/off switch. +Full guide: [MCP.md](MCP.md). Asserted by: unit (`mcp/protocol`, `mcp/tools`, `mcp/http`, `mcp/server`, `cli`). + ## 13. Self engine (in-process AWS emulator — LocalStack replacement) Opt-in via `engine: "self"` / `lss start --self-engine`: the orchestrator serves the AWS wire API diff --git a/docs/MCP.md b/docs/MCP.md new file mode 100644 index 0000000..c8a17d1 --- /dev/null +++ b/docs/MCP.md @@ -0,0 +1,126 @@ +# MCP server — driving LSS from an AI coding agent + +`npx lss mcp` exposes the running stack to any [Model Context +Protocol](https://modelcontextprotocol.io) client as a set of tools. Instead of +pasting `curl` output into a chat, the agent inspects and drives your local AWS +directly: list what is provisioned, invoke a Lambda, scan a table, send a +message, wait for a queue to drain. + +It is a thin, read-mostly wrapper over the orchestrator's REST API — the same +API the dashboard and the `LssClient` use. No AWS SDK, no second source of +truth, and **no new runtime dependency**: the JSON-RPC 2.0 stdio transport is +implemented in `src/mcp/` (~250 lines). + +--- + +## Turning it on + +The server is **off unless a client is configured to launch it**, and every MCP +client has its own on/off switch. Nothing is enabled just by installing LSS. + +### Claude Code + +This repository ships a project-scoped [`.mcp.json`](../.mcp.json): + +```json +{ + "mcpServers": { + "lss": { "command": "node", "args": ["./bin/cli.js", "mcp"] } + } +} +``` + +In **your own** project, install LSS and use the published binary: + +```json +{ + "mcpServers": { + "lss": { "command": "npx", "args": ["lss", "mcp"] } + } +} +``` + +Then: + +- `/mcp` in Claude Code lists the server, its tools and its connection state. +- The same `/mcp` view enables or disables it — that is the on/off switch. +- Deleting the entry from `.mcp.json` removes it entirely. + +### Any other MCP client + +Point it at the command `npx lss mcp` with stdio transport. The server speaks +protocol revision `2024-11-05` and advertises only the `tools` capability. + +### Environment + +| Variable | Effect | +|---|---| +| `LSS_BASE_URL` | Orchestrator URL. Wins over everything else — use it when the agent runs somewhere other than the project directory. | +| `LSS_CONFIG` | Explicit config file to read `serverPort` from. | + +With neither set, the server reads `serverPort` from `lss.config.json` (then +`.lssrc`) in its working directory, and falls back to `http://localhost:3100`. + +> **The orchestrator has to be running.** `lss mcp` never boots one — it only +> talks HTTP to a stack you started with `lss start`. If nothing answers, every +> tool returns one actionable error telling the agent to run `npx lss start`. + +--- + +## Tools + +Tools whose description starts with **MUTATES** change state; a client shows +that text before asking a human to approve the call. + +| Tool | What it answers | +|---|---| +| `lss_health` | Which engine is active, its endpoint, how many event-source loops and schedule rules are armed | +| `lss_config` | Effective configuration (no secret values), including the lambda residency policy | +| `lss_ports` | Every local port: orchestrator, engine, per-service API and invoke listeners | +| `lss_services` | Registered services: resources, routes, runtime status, `runtimeWarm` | +| `lss_resources` / `lss_resource_owners` | Provisioned resources, and which service declared each | +| `lss_lambdas` / `lss_lambda_logs` | Functions with triggers and counters; per-invocation logs | +| `lss_invoke` | **MUTATES.** Run a handler with a JSON event, sync or `Event` | +| `lss_apis` | HTTP routes per service, with authorizer and listener status | +| `lss_dynamo_tables` / `lss_dynamo_scan` / `lss_dynamo_query` | Table metadata and reads (full AWS expression language) | +| `lss_dynamo_put_item` | **MUTATES.** Write one plain-JSON item | +| `lss_queues` / `lss_queue_send` / `lss_queue_await_idle` | Queue metrics and consumers; send; block until drained | +| `lss_buckets` / `lss_bucket_objects` | S3 buckets and object listings (prefix/delimiter) | +| `lss_secrets` | Secret names, ARNs and version stages — **never values** | +| `lss_opensearch_search` | Raw OpenSearch DSL against a collection | +| `lss_seeds` / `lss_seed_run` | Seed files vs live tables; **MUTATES** on run | + +Every tool takes an optional `region`; omitted, the orchestrator's configured +region is used. + +### The one that makes agents useful on async work + +`lss_queue_await_idle` blocks server-side until a queue drains, then returns. +It is what lets an agent do arrange → act → **wait** → assert on a pipeline that +crosses SQS and Lambda, instead of guessing at a sleep: + +``` +lss_invoke createOrder with an event +lss_queue_await_idle orders-to-process, sinceProcessed: 1 +lss_dynamo_scan notifications-Notifications +``` + +--- + +## Design notes + +- **Text results.** Every tool answers pretty-printed JSON in a `text` content + block. Structured content is optional in the MCP spec and unevenly supported; + text renders everywhere. +- **Failures are results, not transport errors.** A 404 from the orchestrator + comes back as `isError: true` with the orchestrator's own message + (`Queue not found`), so the model reads and reacts instead of the client + aborting the call. +- **stdout is protocol-only.** Diagnostics go to stderr, which the client shows + as server logs. A stray `console.log` on stdout corrupts the frame stream. +- **Ordered responses.** Requests are answered in arrival order, so a slow tool + never lets a later one overtake it. Clients tolerate out-of-order responses; + ordered output just makes transcripts readable. + +Covered by `tests/unit/mcp/` (protocol, tools, HTTP transport, stdio framing) at +the repository's 100% gate. diff --git a/jest.config.js b/jest.config.js index 7544af1..d4bb6f8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,7 @@ module.exports = { 'src/server/routes/**/*.ts', 'src/server/dev/**/*.ts', 'src/client/**/*.ts', + 'src/mcp/**/*.ts', 'packages/serverless-plugin/src/**/*.ts', 'bin/cli.js', // Integration-only by nature — excluded from the coverage denominator: diff --git a/package-lock.json b/package-lock.json index e810f9e..f47de15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "local-serverless-stack", - "version": "0.17.2", + "version": "0.18.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "local-serverless-stack", - "version": "0.17.2", + "version": "0.18.0", "license": "MIT", "workspaces": [ "packages/*", diff --git a/package.json b/package.json index 1914507..898f1aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "local-serverless-stack", - "version": "0.17.2", + "version": "0.18.0", "description": "Local control plane for serverless development with LocalStack orchestration", "author": "LSS Contributors", "license": "MIT", @@ -33,19 +33,20 @@ "local" ], "files": [ + "CHANGELOG.md", + "LICENSE", + "README.md", + "assets/", "bin/", "dist/", - "packages/serverless-plugin/dist/", - "README.md", - "LICENSE", - "CHANGELOG.md" + "packages/serverless-plugin/dist/" ], "workspaces": [ "packages/*", "src/ui" ], "scripts": { - "build": "npm run ui:build && npm run server:build && npm run client:build && npm run plugin:build", + "build": "npm run ui:build && npm run server:build && npm run client:build && npm run mcp:build && npm run plugin:build", "server:dev": "tsx watch src/server/index.ts", "server:build": "tsc --project src/server/tsconfig.json", "client:build": "tsc --project src/client/tsconfig.json", @@ -61,7 +62,8 @@ "test:coverage": "jest -c jest.config.js --coverage", "test:integration": "jest -c jest.integration.config.js", "lint": "eslint .", - "lint:fix": "eslint . --fix" + "lint:fix": "eslint . --fix", + "mcp:build": "tsc --project src/mcp/tsconfig.json" }, "dependencies": { "@aws-sdk/client-dynamodb": "^3.709.0", diff --git a/src/mcp/http.ts b/src/mcp/http.ts new file mode 100644 index 0000000..16fa4ff --- /dev/null +++ b/src/mcp/http.ts @@ -0,0 +1,94 @@ +// Where the MCP server finds the orchestrator, and how it talks to it. +// +// Resolution mirrors the LssClient (src/client/config-discovery.ts) so both +// entry points agree: an explicit base URL wins, then the serverPort from the +// project's config file, then the documented default. The MCP process is +// started by the editor from the project directory, so the cwd lookup is the +// case that matters in practice. + +import fs from 'fs'; +import path from 'path'; + +const DEFAULT_PORT = 3100; +const DEFAULT_TIMEOUT_MS = 130_000; // above await-idle's 120 s server-side clamp + +export interface ResolveOptions { + baseUrl?: string; + cwd?: string; + configPath?: string; +} + +function readServerPort(cwd: string, configPath?: string): number { + const candidates = configPath + ? [path.resolve(cwd, configPath)] + : [path.join(cwd, 'lss.config.json'), path.join(cwd, '.lssrc')]; + for (const candidate of candidates) { + try { + const parsed = JSON.parse(fs.readFileSync(candidate, 'utf-8')) as { serverPort?: unknown }; + if (typeof parsed.serverPort === 'number' && Number.isInteger(parsed.serverPort)) { + return parsed.serverPort; + } + } catch { + // Unreadable or unparseable: fall through to the next candidate. + } + } + return DEFAULT_PORT; +} + +export function resolveBaseUrl(options: ResolveOptions = {}): string { + const explicit = options.baseUrl ?? process.env.LSS_BASE_URL; + if (explicit) return explicit.endsWith('/') ? explicit.slice(0, -1) : explicit; + const cwd = options.cwd ?? process.cwd(); + const configPath = options.configPath ?? process.env.LSS_CONFIG; + return `http://localhost:${readServerPort(cwd, configPath)}`; +} + +export class LssUnreachableError extends Error {} + +/** + * Minimal JSON HTTP caller over global fetch (Node >= 20). + * A non-2xx answer throws with the orchestrator's own error message, so the + * model sees "Queue not found" rather than "HTTP 404". + */ +export function createHttp(baseUrl: string, timeoutMs = DEFAULT_TIMEOUT_MS) { + return async function http(method: string, urlPath: string, body?: unknown): Promise { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + let response: Response; + try { + response = await fetch(baseUrl + urlPath, { + method, + headers: body === undefined ? undefined : { 'Content-Type': 'application/json' }, + body: body === undefined ? undefined : JSON.stringify(body), + signal: controller.signal, + }); + } catch (error) { + const reason = (error as { name?: string }).name === 'AbortError' + ? `timed out after ${timeoutMs}ms` + : (error as Error).message; + throw new LssUnreachableError( + `Could not reach the LSS orchestrator at ${baseUrl} (${reason}). ` + + 'Start it with `npx lss start` in the project directory, or set LSS_BASE_URL.', + ); + } finally { + clearTimeout(timer); + } + + const raw = await response.text(); + let parsed: unknown = raw; + try { + parsed = raw ? JSON.parse(raw) : null; + } catch { + // Keep the raw text — the caller reports it verbatim. + } + // await-idle answers 408 with a meaningful body (`drained: false`); that is + // a result, not a failure. + if (!response.ok && response.status !== 408) { + const detail = parsed && typeof parsed === 'object' && 'error' in parsed + ? String((parsed as { error: unknown }).error) + : raw.slice(0, 300) || response.statusText; + throw new Error(`${method} ${urlPath} → ${response.status}: ${detail}`); + } + return parsed; + }; +} diff --git a/src/mcp/protocol.ts b/src/mcp/protocol.ts new file mode 100644 index 0000000..aca9cdb --- /dev/null +++ b/src/mcp/protocol.ts @@ -0,0 +1,127 @@ +// MCP over JSON-RPC 2.0, hand-rolled. +// +// Why not the official SDK: this package ships with a deliberately small +// dependency tree (express, cors, aws-sdk clients) and the stdio transport is +// newline-delimited JSON-RPC — a few dozen lines. Adding an SDK for that would +// cost more than it saves. +// +// This module is pure: `handleMessage` maps a request object to a response +// object and never touches stdio, which is what makes it testable. The +// stdio wiring lives in server.ts. + +import { TOOLS_BY_NAME, toolListPayload, type HttpLike } from './tools.js'; + +// The revision of the MCP spec this server implements. Clients that ask for a +// different one are answered with ours; per the spec they then decide whether +// to continue. +export const PROTOCOL_VERSION = '2024-11-05'; + +export interface JsonRpcRequest { + jsonrpc?: string; + id?: string | number | null; + method?: string; + params?: Record; +} + +export interface JsonRpcResponse { + jsonrpc: '2.0'; + id: string | number | null; + result?: unknown; + error?: { code: number; message: string }; +} + +export const ERROR_CODES = { + parse: -32700, + invalidRequest: -32600, + methodNotFound: -32601, + internal: -32603, +} as const; + +export interface ServerContext { + http: HttpLike; + serverName: string; + serverVersion: string; +} + +function ok(id: string | number | null, result: unknown): JsonRpcResponse { + return { jsonrpc: '2.0', id, result }; +} + +function fail(id: string | number | null, code: number, message: string): JsonRpcResponse { + return { jsonrpc: '2.0', id, error: { code, message } }; +} + +function textContent(payload: unknown, isError = false): unknown { + const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2); + return { content: [{ type: 'text', text }], ...(isError ? { isError: true } : {}) }; +} + +async function callTool(params: Record, ctx: ServerContext): Promise { + const toolName = params.name; + if (typeof toolName !== 'string') { + return textContent('tools/call requires a "name"', true); + } + const tool = TOOLS_BY_NAME.get(toolName); + if (!tool) { + return textContent(`Unknown tool: ${toolName}`, true); + } + const args = (params.arguments ?? {}) as Record; + try { + return textContent(await tool.run(args, ctx.http)); + } catch (error) { + // A tool that fails is a normal outcome the model should read and react to + // — surfaced as an error RESULT, not a transport-level JSON-RPC error. + return textContent(error instanceof Error ? error.message : String(error), true); + } +} + +/** + * Handle one decoded JSON-RPC message. + * Returns `null` for notifications (no `id`), which must not be answered. + */ +export async function handleMessage( + message: JsonRpcRequest, + ctx: ServerContext, +): Promise { + const id = message.id ?? null; + const isNotification = message.id === undefined || message.id === null; + const method = message.method; + + if (typeof method !== 'string') { + return isNotification ? null : fail(id, ERROR_CODES.invalidRequest, 'missing "method"'); + } + + switch (method) { + case 'initialize': + return ok(id, { + protocolVersion: PROTOCOL_VERSION, + capabilities: { tools: { listChanged: false } }, + serverInfo: { name: ctx.serverName, version: ctx.serverVersion }, + }); + case 'ping': + return ok(id, {}); + case 'tools/list': + return ok(id, { tools: toolListPayload() }); + case 'tools/call': + return ok(id, await callTool(message.params ?? {}, ctx)); + default: + // Notifications we do not implement (notifications/initialized, + // notifications/cancelled, ...) are silently accepted, as the spec + // requires — only a REQUEST for an unknown method is an error. + return isNotification ? null : fail(id, ERROR_CODES.methodNotFound, `Unknown method: ${method}`); + } +} + +/** Decode a line and dispatch it. Malformed JSON answers a parse error. */ +export async function handleLine(line: string, ctx: ServerContext): Promise { + let parsed: unknown; + try { + parsed = JSON.parse(line); + } catch { + return fail(null, ERROR_CODES.parse, 'invalid JSON'); + } + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + return fail(null, ERROR_CODES.invalidRequest, 'expected a JSON-RPC object'); + } + return handleMessage(parsed as JsonRpcRequest, ctx); +} diff --git a/src/mcp/server.ts b/src/mcp/server.ts new file mode 100644 index 0000000..8020c6f --- /dev/null +++ b/src/mcp/server.ts @@ -0,0 +1,51 @@ +#!/usr/bin/env node +// MCP stdio entry point — `npx lss mcp`. +// +// Transport per the MCP spec: newline-delimited JSON-RPC 2.0 on stdin/stdout. +// stdout carries ONLY protocol frames (any stray write corrupts the stream), so +// diagnostics go to stderr, which the client surfaces as server logs. +// +// Kept thin on purpose: the protocol and the tools are pure modules with their +// own tests; this file is the I/O seam. + +import { createInterface } from 'readline'; +import { createHttp, resolveBaseUrl } from './http.js'; +import { handleLine, type ServerContext } from './protocol.js'; + +export function startStdioServer( + ctx: ServerContext, + input: NodeJS.ReadableStream, + output: { write(chunk: string): unknown }, +): void { + const lines = createInterface({ input, terminal: false }); + // Requests are handled in arrival order: a queue keeps a slow tool from + // letting a later, faster one answer first. MCP clients tolerate + // out-of-order responses, but ordered output makes transcripts readable. + let chain: Promise = Promise.resolve(); + + lines.on('line', line => { + const trimmed = line.trim(); + if (!trimmed) return; + chain = chain.then(async () => { + const response = await handleLine(trimmed, ctx); + if (response) output.write(`${JSON.stringify(response)}\n`); + }).catch(error => { + process.stderr.write(`[lss-mcp] unhandled: ${error instanceof Error ? error.stack : String(error)}\n`); + }); + }); + + lines.on('close', () => { + void chain.then(() => process.exit(0)); + }); +} + +/* istanbul ignore next: process entry point, exercised by the CLI smoke test */ +export function main(version: string): void { + const baseUrl = resolveBaseUrl(); + process.stderr.write(`[lss-mcp] orchestrator: ${baseUrl}\n`); + startStdioServer( + { http: createHttp(baseUrl), serverName: 'lss', serverVersion: version }, + process.stdin, + process.stdout, + ); +} diff --git a/src/mcp/tools.ts b/src/mcp/tools.ts new file mode 100644 index 0000000..5de48e0 --- /dev/null +++ b/src/mcp/tools.ts @@ -0,0 +1,319 @@ +// The tool surface an MCP client (Claude Code) gets over the running +// orchestrator. Everything here is a thin, typed wrapper over the same REST API +// the dashboard and the LssClient use — no second source of truth, and no AWS +// SDK in this process. +// +// Design rules for this file: +// - Read-only tools first; anything that mutates says so in its description, +// because the client shows those descriptions to a human before approving. +// - Every tool answers TEXT (JSON, pretty-printed). MCP clients render text +// reliably; structured content is optional in the spec and unevenly +// supported. +// - Errors come back as `isError` results, not JSON-RPC errors: a failed tool +// call is a normal outcome the model should read and react to, not a +// transport fault. + +export interface HttpLike { + (method: string, path: string, body?: unknown): Promise; +} + +export interface ToolDefinition { + name: string; + description: string; + inputSchema: { + type: 'object'; + properties: Record; + required?: string[]; + }; + // Mutating tools are flagged so a client can group/annotate them. + mutates?: boolean; + run: (args: Record, http: HttpLike) => Promise; +} + +const str = (description: string) => ({ type: 'string', description }); +const num = (description: string) => ({ type: 'number', description }); +const obj = (description: string) => ({ type: 'object', description }); + +function region(args: Record): string { + return typeof args.region === 'string' && args.region ? `?region=${encodeURIComponent(args.region)}` : ''; +} + +function name(args: Record, key = 'name'): string { + const value = args[key]; + if (typeof value !== 'string' || !value) throw new Error(`"${key}" is required`); + return encodeURIComponent(value); +} + +const REGION_PROP = { + region: str('AWS region. Defaults to the region the orchestrator is configured with.'), +}; + +export const TOOLS: ToolDefinition[] = [ + { + name: 'lss_health', + description: + 'Orchestrator and engine health: which engine is active (self or localstack), its endpoint, ' + + 'how many event-source loops and schedule rules are armed. Use this first to confirm a stack is up.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/health'), + }, + { + name: 'lss_config', + description: + 'Effective LSS configuration (secret values never included): ports, engine, region, seeds dir, ' + + 'lambda runtime residency policy, and which keys are currently masked by an environment variable.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/config'), + }, + { + name: 'lss_ports', + description: 'Every local port this stack exposes: orchestrator, engine, and each service\'s HTTP API and invoke listener.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/config/ports'), + }, + { + name: 'lss_services', + description: + 'Registered services with their resource breakdown, HTTP routes, runtime status and ports. ' + + '`runtimeWarm: false` means the service is ready but its worker has not been forked yet.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/services'), + }, + { + name: 'lss_resources', + description: 'Provisioned AWS resources (DynamoDB tables, SQS queues, SNS topics, S3 buckets, OpenSearch collections).', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/resources${region(a)}`), + }, + { + name: 'lss_resource_owners', + description: 'Maps each provisioned resource to the service that declared it — use it to find who owns a table or queue.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/resources/owners${region(a)}`), + }, + { + name: 'lss_lambdas', + description: 'Every registered function with its triggers, execution mode, invocation counters and warm state.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/lambdas'), + }, + { + name: 'lss_lambda_logs', + description: 'Invocation history for one function: duration, ok/error, HTTP status and the captured log lines per call.', + inputSchema: { + type: 'object', + properties: { name: str('Function name (short name or fully qualified).') }, + required: ['name'], + }, + run: (a, http) => http('GET', `/api/lambdas/${name(a)}/logs`), + }, + { + name: 'lss_invoke', + description: + 'MUTATES. Invoke a Lambda with a JSON payload and return its result plus captured logs. ' + + 'This runs the real handler against the real local AWS state.', + mutates: true, + inputSchema: { + type: 'object', + properties: { + name: str('Function name (short name or fully qualified).'), + payload: obj('Event object passed to the handler. Defaults to {}.'), + async: { type: 'boolean', description: 'Fire and forget (Event invocation type). Defaults to false.' }, + }, + required: ['name'], + }, + run: (a, http) => + http('POST', `/api/lambdas/${name(a)}/invoke`, { + payload: a.payload ?? {}, + invocationType: a.async ? 'Event' : 'RequestResponse', + }), + }, + { + name: 'lss_apis', + description: 'HTTP routes served per service: method, path, target function, payload version, authorizer and listener status.', + inputSchema: { type: 'object', properties: {} }, + run: (_a, http) => http('GET', '/api/apis'), + }, + { + name: 'lss_dynamo_tables', + description: 'DynamoDB tables with key schema, GSI/LSI, stream and TTL state. Paginated internally — all tables are returned.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/dynamo/tables${region(a)}`), + }, + { + name: 'lss_dynamo_scan', + description: + 'Scan a DynamoDB table. Supports filterExpression / projectionExpression / expressionAttributeNames / ' + + 'expressionAttributeValues / indexName / limit / exclusiveStartKey, exactly like the AWS SDK.', + inputSchema: { + type: 'object', + properties: { + table: str('Table name.'), + input: obj('ScanInput fields (filterExpression, limit, indexName, ...). Optional.'), + ...REGION_PROP, + }, + required: ['table'], + }, + run: (a, http) => http('POST', `/api/dynamo/tables/${name(a, 'table')}/scan${region(a)}`, a.input ?? {}), + }, + { + name: 'lss_dynamo_query', + description: 'Query a DynamoDB table or index. Requires keyConditionExpression in `input`.', + inputSchema: { + type: 'object', + properties: { + table: str('Table name.'), + input: obj('QueryInput fields — keyConditionExpression is required.'), + ...REGION_PROP, + }, + required: ['table', 'input'], + }, + run: (a, http) => http('POST', `/api/dynamo/tables/${name(a, 'table')}/query${region(a)}`, a.input ?? {}), + }, + { + name: 'lss_dynamo_put_item', + description: 'MUTATES. Write one item into a DynamoDB table. `item` is a plain JSON object (not AttributeValue-typed).', + mutates: true, + inputSchema: { + type: 'object', + properties: { table: str('Table name.'), item: obj('Plain JSON item.'), ...REGION_PROP }, + required: ['table', 'item'], + }, + run: (a, http) => http('POST', `/api/dynamo/tables/${name(a, 'table')}/items${region(a)}`, { item: a.item }), + }, + { + name: 'lss_queues', + description: + 'SQS queues with live metrics (available, in flight, delayed, processed) and the Lambda consumers attached to each.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/queues${region(a)}`), + }, + { + name: 'lss_queue_send', + description: 'MUTATES. Send a message to a queue. FIFO queues accept messageGroupId / messageDeduplicationId.', + mutates: true, + inputSchema: { + type: 'object', + properties: { + queue: str('Queue name (logical name, e.g. "orders-to-process").'), + body: str('Message body.'), + messageGroupId: str('FIFO group id.'), + messageDeduplicationId: str('FIFO dedup id.'), + delaySeconds: num('Delivery delay in seconds.'), + ...REGION_PROP, + }, + required: ['queue', 'body'], + }, + run: (a, http) => + http('POST', `/api/queues/${name(a, 'queue')}/messages${region(a)}`, { + body: a.body, + messageGroupId: a.messageGroupId, + messageDeduplicationId: a.messageDeduplicationId, + delaySeconds: a.delaySeconds, + }), + }, + { + name: 'lss_queue_await_idle', + description: + 'Block until a queue drains (available and in-flight both zero), then return. The reliable way to wait for an ' + + 'async pipeline to finish before asserting. Pass `sinceProcessed` to also require a minimum processed count. ' + + 'Answers even on timeout — check the `drained` field.', + inputSchema: { + type: 'object', + properties: { + queue: str('Queue name.'), + timeoutMs: num('How long to wait. Server clamps to 100..120000. Default 15000.'), + sinceProcessed: num('Also require at least this many messages processed.'), + ...REGION_PROP, + }, + required: ['queue'], + }, + run: (a, http) => + http('POST', `/api/queues/${name(a, 'queue')}/await-idle${region(a)}`, { + timeoutMs: a.timeoutMs, + sinceProcessed: a.sinceProcessed, + }), + }, + { + name: 'lss_buckets', + description: 'S3 buckets with object count, total size, versioning and notification configuration.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/buckets${region(a)}`), + }, + { + name: 'lss_bucket_objects', + description: 'List objects in a bucket. Supports prefix and delimiter.', + inputSchema: { + type: 'object', + properties: { + bucket: str('Bucket name.'), + prefix: str('Key prefix filter.'), + delimiter: str('Group keys by this delimiter (e.g. "/").'), + ...REGION_PROP, + }, + required: ['bucket'], + }, + run: (a, http) => { + const params = new URLSearchParams(); + if (typeof a.prefix === 'string' && a.prefix) params.set('prefix', a.prefix); + if (typeof a.delimiter === 'string' && a.delimiter) params.set('delimiter', a.delimiter); + if (typeof a.region === 'string' && a.region) params.set('region', a.region); + const query = params.toString(); + return http('GET', `/api/buckets/${name(a, 'bucket')}/objects${query ? `?${query}` : ''}`); + }, + }, + { + name: 'lss_secrets', + description: 'Secrets Manager entries (names, ARNs, version stages, tags). Values are NOT included.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/secrets${region(a)}`), + }, + { + name: 'lss_opensearch_search', + description: 'Run an OpenSearch query against a collection. `body` is the raw search DSL.', + inputSchema: { + type: 'object', + properties: { + collection: str('Collection name.'), + body: obj('OpenSearch query DSL (query, sort, size, aggs, ...).'), + index: str('Index to search. Defaults to the collection\'s only index when there is one.'), + ...REGION_PROP, + }, + required: ['collection'], + }, + run: (a, http) => + http('POST', `/api/opensearch/collections/${name(a, 'collection')}/search${region(a)}`, { + index: a.index, + body: a.body ?? {}, + }), + }, + { + name: 'lss_seeds', + description: 'Seed files on disk and the live tables they map to — including the mismatch diagnostic.', + inputSchema: { type: 'object', properties: { ...REGION_PROP } }, + run: (a, http) => http('GET', `/api/seeds${region(a)}`), + }, + { + name: 'lss_seed_run', + description: 'MUTATES. Apply seed files into DynamoDB. Omit `table` to apply every seed file.', + mutates: true, + inputSchema: { + type: 'object', + properties: { table: str('Seed a single table. Omit for all.'), ...REGION_PROP }, + required: [], + }, + run: (a, http) => + http('POST', `/api/seeds/run${region(a)}`, typeof a.table === 'string' && a.table ? { tableName: a.table } : {}), + }, +]; + +export const TOOLS_BY_NAME = new Map(TOOLS.map(tool => [tool.name, tool])); + +// The wire shape a client sees — `run` is server-side only. +export function toolListPayload(): unknown[] { + return TOOLS.map(({ name: toolName, description, inputSchema }) => ({ + name: toolName, + description, + inputSchema, + })); +} diff --git a/src/mcp/tsconfig.json b/src/mcp/tsconfig.json new file mode 100644 index 0000000..2049131 --- /dev/null +++ b/src/mcp/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/mcp", + "rootDir": "." + }, + "include": ["./**/*.ts"], + "exclude": ["**/*.test.ts"] +} diff --git a/src/ui/index.html b/src/ui/index.html index db4ff76..8457989 100644 --- a/src/ui/index.html +++ b/src/ui/index.html @@ -4,7 +4,9 @@ - LSS Orchestrator + + + LSS Self Engine diff --git a/src/ui/public/favicon.svg b/src/ui/public/favicon.svg new file mode 100644 index 0000000..d0babc5 --- /dev/null +++ b/src/ui/public/favicon.svg @@ -0,0 +1,37 @@ + + LSS Self Engine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/unit/cli/cli.test.ts b/tests/unit/cli/cli.test.ts index 0f47df2..06c0a36 100644 --- a/tests/unit/cli/cli.test.ts +++ b/tests/unit/cli/cli.test.ts @@ -1418,4 +1418,37 @@ describe('bin/cli.js helpers', () => { expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Local Serverless Stack (LSS) CLI')); }); }); + + // `lss mcp` launcher. The dynamic import of the ESM build is the process entry + // point (it binds this process's stdio), so only the resolution and the + // missing-build guard are unit-testable — the rest is covered by starting the + // server for real in the MCP suite. + describe('mcp command', () => { + it('resolves the built MCP server next to the CLI', () => { + mockFs.existsSync.mockImplementation((p: any) => String(p).endsWith('dist/mcp/server.js')); + const cli = loadCli(['node', 'cli.js', 'mcp']); + expect(cli.getMcpServerPath()).toMatch(/dist\/mcp\/server\.js$/); + }); + + it('returns null when nothing is built', () => { + mockFs.existsSync.mockReturnValue(false); + expect(loadCli().getMcpServerPath()).toBeNull(); + }); + + it('reads the package version, falling back when package.json is unreadable', () => { + mockFs.readFileSync.mockReturnValue(JSON.stringify({ version: '9.9.9' })); + expect(loadCli().getPackageVersion()).toBe('9.9.9'); + mockFs.readFileSync.mockReturnValue('{ not json'); + expect(loadCli().getPackageVersion()).toBe('0.0.0'); + mockFs.readFileSync.mockReturnValue(JSON.stringify({})); + expect(loadCli().getPackageVersion()).toBe('0.0.0'); + }); + + it('tells the user to build before it can serve MCP', async () => { + mockFs.existsSync.mockReturnValue(false); + const cli = loadCli(['node', 'cli.js', 'mcp']); + expect(await expectExit(() => cli.runMcpServer())).toBe(1); + expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('MCP server build not found')); + }); + }); }); diff --git a/tests/unit/mcp/http.test.ts b/tests/unit/mcp/http.test.ts new file mode 100644 index 0000000..c8db023 --- /dev/null +++ b/tests/unit/mcp/http.test.ts @@ -0,0 +1,144 @@ +// Base-URL discovery and the JSON caller. The failure message matters as much +// as the happy path: when the stack is down, the model must be told to run +// `lss start` rather than shown a bare TypeError from fetch. +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { createHttp, resolveBaseUrl, LssUnreachableError } from '../../../src/mcp/http'; + +let dir: string; +const origEnv = { ...process.env }; + +beforeEach(() => { + dir = fs.mkdtempSync(path.join(os.tmpdir(), 'lss-mcp-http-')); + delete process.env.LSS_BASE_URL; + delete process.env.LSS_CONFIG; +}); + +afterEach(() => { + fs.rmSync(dir, { recursive: true, force: true }); + process.env = { ...origEnv }; + jest.restoreAllMocks(); +}); + +describe('resolveBaseUrl', () => { + it('prefers an explicit base url and trims a trailing slash', () => { + expect(resolveBaseUrl({ baseUrl: 'http://host:9/' })).toBe('http://host:9'); + expect(resolveBaseUrl({ baseUrl: 'http://host:9' })).toBe('http://host:9'); + }); + + it('falls back to LSS_BASE_URL', () => { + process.env.LSS_BASE_URL = 'http://elsewhere:1234'; + expect(resolveBaseUrl({ cwd: dir })).toBe('http://elsewhere:1234'); + }); + + it('reads serverPort from lss.config.json in the working directory', () => { + fs.writeFileSync(path.join(dir, 'lss.config.json'), JSON.stringify({ serverPort: 3140 })); + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3140'); + }); + + it('falls back to .lssrc when there is no lss.config.json', () => { + fs.writeFileSync(path.join(dir, '.lssrc'), JSON.stringify({ serverPort: 3222 })); + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3222'); + }); + + it('honours an explicit config path', () => { + const custom = path.join(dir, 'lss.e2e.json'); + fs.writeFileSync(custom, JSON.stringify({ serverPort: 3999 })); + expect(resolveBaseUrl({ cwd: dir, configPath: 'lss.e2e.json' })).toBe('http://localhost:3999'); + process.env.LSS_CONFIG = custom; + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3999'); + }); + + it('defaults to 3100 when nothing is readable, unparseable, or has no numeric serverPort', () => { + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3100'); + fs.writeFileSync(path.join(dir, 'lss.config.json'), '{ not json'); + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3100'); + fs.writeFileSync(path.join(dir, 'lss.config.json'), JSON.stringify({ serverPort: '3140' })); + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3100'); + fs.writeFileSync(path.join(dir, 'lss.config.json'), JSON.stringify({ serverPort: 1.5 })); + expect(resolveBaseUrl({ cwd: dir })).toBe('http://localhost:3100'); + }); + + it('defaults the working directory to the process cwd', () => { + jest.spyOn(process, 'cwd').mockReturnValue(dir); + fs.writeFileSync(path.join(dir, 'lss.config.json'), JSON.stringify({ serverPort: 3777 })); + expect(resolveBaseUrl()).toBe('http://localhost:3777'); + }); +}); + +function mockFetch(impl: (url: string, init: RequestInit) => Partial | Promise) { + const spy = jest.fn(async (url: unknown, init: unknown) => impl(String(url), init as RequestInit)); + (globalThis as { fetch: unknown }).fetch = spy; + return spy; +} + +const res = (status: number, body: string, statusText = '') => + ({ ok: status >= 200 && status < 300, status, statusText, text: async () => body }) as Partial; + +describe('createHttp', () => { + it('GETs without a content-type and parses the JSON body', async () => { + const spy = mockFetch(() => res(200, '{"status":"ok"}')); + const http = createHttp('http://localhost:3100'); + expect(await http('GET', '/api/health')).toEqual({ status: 'ok' }); + expect(spy.mock.calls[0][0]).toBe('http://localhost:3100/api/health'); + expect((spy.mock.calls[0][1] as RequestInit).headers).toBeUndefined(); + }); + + it('POSTs a JSON body with the content-type header', async () => { + const spy = mockFetch(() => res(200, '{}')); + await createHttp('http://x')('POST', '/api/seeds/run', { tableName: 'Users' }); + const init = spy.mock.calls[0][1] as RequestInit; + expect(init.headers).toEqual({ 'Content-Type': 'application/json' }); + expect(init.body).toBe('{"tableName":"Users"}'); + }); + + it('returns null for an empty body and the raw text when it is not JSON', async () => { + mockFetch(() => res(200, '')); + expect(await createHttp('http://x')('GET', '/a')).toBeNull(); + mockFetch(() => res(200, 'plain text')); + expect(await createHttp('http://x')('GET', '/a')).toBe('plain text'); + }); + + it('treats 408 as a result — await-idle answers a meaningful body on timeout', async () => { + mockFetch(() => res(408, '{"drained":false}')); + expect(await createHttp('http://x')('POST', '/api/queues/q/await-idle', {})).toEqual({ drained: false }); + }); + + it('raises the orchestrator error message, not the bare status', async () => { + mockFetch(() => res(404, '{"error":"Queue not found"}')); + await expect(createHttp('http://x')('GET', '/api/queues/ghost')).rejects.toThrow( + 'GET /api/queues/ghost → 404: Queue not found', + ); + }); + + it('falls back to the body text, then the status text, when there is no error field', async () => { + mockFetch(() => res(500, 'boom')); + await expect(createHttp('http://x')('GET', '/a')).rejects.toThrow('→ 500: boom'); + mockFetch(() => res(503, '', 'Service Unavailable')); + await expect(createHttp('http://x')('GET', '/a')).rejects.toThrow('→ 503: Service Unavailable'); + }); + + it('a connection failure explains how to start the stack', async () => { + mockFetch(() => Promise.reject(Object.assign(new Error('ECONNREFUSED'), { name: 'TypeError' }))); + await expect(createHttp('http://localhost:3100')('GET', '/api/health')).rejects.toThrow(LssUnreachableError); + await expect(createHttp('http://localhost:3100')('GET', '/api/health')).rejects.toThrow( + /Could not reach the LSS orchestrator at http:\/\/localhost:3100 \(ECONNREFUSED\).*npx lss start/s, + ); + }); + + it('an abort is reported as a timeout with the budget that elapsed', async () => { + mockFetch(() => Promise.reject(Object.assign(new Error('aborted'), { name: 'AbortError' }))); + await expect(createHttp('http://x', 25)('GET', '/a')).rejects.toThrow('timed out after 25ms'); + }); + + // The real timer path: a hanging orchestrator must not hang the MCP client. + it('aborts a request that outlives its budget', async () => { + mockFetch((_url, init) => new Promise((_resolve, reject) => { + init.signal?.addEventListener('abort', () => { + reject(Object.assign(new Error('aborted'), { name: 'AbortError' })); + }); + }) as Promise); + await expect(createHttp('http://x', 10)('GET', '/slow')).rejects.toThrow('timed out after 10ms'); + }); +}); diff --git a/tests/unit/mcp/protocol.test.ts b/tests/unit/mcp/protocol.test.ts new file mode 100644 index 0000000..1ca6d29 --- /dev/null +++ b/tests/unit/mcp/protocol.test.ts @@ -0,0 +1,160 @@ +// MCP JSON-RPC layer. The contract that matters: a client's handshake works, +// notifications are never answered (answering one desynchronises the stream), +// and a failing tool comes back as an error RESULT rather than a transport +// error — so the model reads the message instead of the client aborting. +import { + handleLine, + handleMessage, + ERROR_CODES, + PROTOCOL_VERSION, + type ServerContext, +} from '../../../src/mcp/protocol'; + +function ctx(http: ServerContext['http'] = async () => ({ ok: true })): ServerContext { + return { http, serverName: 'lss', serverVersion: '9.9.9' }; +} + +describe('handshake', () => { + it('initialize advertises the tools capability and the server identity', async () => { + const res = await handleMessage({ jsonrpc: '2.0', id: 1, method: 'initialize' }, ctx()); + expect(res).toEqual({ + jsonrpc: '2.0', + id: 1, + result: { + protocolVersion: PROTOCOL_VERSION, + capabilities: { tools: { listChanged: false } }, + serverInfo: { name: 'lss', version: '9.9.9' }, + }, + }); + }); + + it('ping answers an empty result', async () => { + expect(await handleMessage({ id: 'p', method: 'ping' }, ctx())).toEqual({ + jsonrpc: '2.0', + id: 'p', + result: {}, + }); + }); + + it('notifications are never answered', async () => { + expect(await handleMessage({ method: 'notifications/initialized' }, ctx())).toBeNull(); + expect(await handleMessage({ method: 'notifications/cancelled', id: null }, ctx())).toBeNull(); + // Including a notification with no method at all. + expect(await handleMessage({}, ctx())).toBeNull(); + }); + + it('a request with no method, or an unknown method, is a JSON-RPC error', async () => { + expect(await handleMessage({ id: 2 }, ctx())).toMatchObject({ + error: { code: ERROR_CODES.invalidRequest }, + }); + expect(await handleMessage({ id: 3, method: 'resources/list' }, ctx())).toMatchObject({ + error: { code: ERROR_CODES.methodNotFound, message: 'Unknown method: resources/list' }, + }); + }); +}); + +describe('tools/list', () => { + it('lists tools with a name, a description and an object input schema, and never leaks `run`', async () => { + const res = await handleMessage({ id: 4, method: 'tools/list' }, ctx()); + const tools = (res as { result: { tools: Record[] } }).result.tools; + expect(tools.length).toBeGreaterThan(10); + for (const tool of tools) { + expect(typeof tool.name).toBe('string'); + expect((tool.description as string).length).toBeGreaterThan(20); + expect((tool.inputSchema as { type: string }).type).toBe('object'); + expect(tool).not.toHaveProperty('run'); + expect(tool).not.toHaveProperty('mutates'); + } + expect(tools.map(t => t.name)).toContain('lss_health'); + }); +}); + +describe('tools/call', () => { + it('returns the tool payload as pretty-printed JSON text', async () => { + const http = jest.fn(async () => ({ status: 'ok' })); + const res = await handleMessage( + { id: 5, method: 'tools/call', params: { name: 'lss_health', arguments: {} } }, + ctx(http), + ); + expect(http).toHaveBeenCalledWith('GET', '/api/health'); + expect((res as { result: unknown }).result).toEqual({ + content: [{ type: 'text', text: JSON.stringify({ status: 'ok' }, null, 2) }], + }); + }); + + it('defaults missing params and arguments to empty', async () => { + const http = jest.fn(async () => []); + await handleMessage({ id: 6, method: 'tools/call', params: { name: 'lss_lambdas' } }, ctx(http)); + expect(http).toHaveBeenCalledWith('GET', '/api/lambdas'); + const res = await handleMessage({ id: 7, method: 'tools/call' }, ctx(http)); + expect((res as { result: { isError: boolean } }).result.isError).toBe(true); + }); + + it('an unknown tool is an error RESULT, not a JSON-RPC error', async () => { + const res = await handleMessage( + { id: 8, method: 'tools/call', params: { name: 'lss_nope' } }, + ctx(), + ); + expect(res).not.toHaveProperty('error'); + expect((res as { result: unknown }).result).toEqual({ + content: [{ type: 'text', text: 'Unknown tool: lss_nope' }], + isError: true, + }); + }); + + it('a non-string tool name is rejected as an error result', async () => { + const res = await handleMessage( + { id: 9, method: 'tools/call', params: { name: 42 } }, + ctx(), + ); + expect((res as { result: { isError: boolean } }).result.isError).toBe(true); + }); + + it('a throwing tool surfaces the orchestrator message the model needs', async () => { + const http = jest.fn(async () => { + throw new Error('GET /api/queues/ghost → 404: Queue not found'); + }); + const res = await handleMessage( + { id: 10, method: 'tools/call', params: { name: 'lss_queues' } }, + ctx(http), + ); + expect((res as { result: { content: { text: string }[]; isError: boolean } }).result).toEqual({ + content: [{ type: 'text', text: 'GET /api/queues/ghost → 404: Queue not found' }], + isError: true, + }); + }); + + it('a thrown non-Error is stringified rather than lost', async () => { + const http = jest.fn(async () => { + throw 'boom'; + }); + const res = await handleMessage( + { id: 11, method: 'tools/call', params: { name: 'lss_queues' } }, + ctx(http as never), + ); + expect((res as { result: { content: { text: string }[] } }).result.content[0].text).toBe('boom'); + }); +}); + +describe('handleLine', () => { + it('decodes and dispatches a framed request', async () => { + const res = await handleLine('{"id":1,"method":"ping"}', ctx()); + expect(res).toEqual({ jsonrpc: '2.0', id: 1, result: {} }); + }); + + it('malformed JSON answers a parse error on the null id', async () => { + expect(await handleLine('{not json', ctx())).toEqual({ + jsonrpc: '2.0', + id: null, + error: { code: ERROR_CODES.parse, message: 'invalid JSON' }, + }); + }); + + it('a valid JSON non-object is an invalid request', async () => { + for (const line of ['[1,2]', '"hello"', 'null']) { + expect(await handleLine(line, ctx())).toMatchObject({ + error: { code: ERROR_CODES.invalidRequest }, + }); + } + }); +}); diff --git a/tests/unit/mcp/server.test.ts b/tests/unit/mcp/server.test.ts new file mode 100644 index 0000000..e50171c --- /dev/null +++ b/tests/unit/mcp/server.test.ts @@ -0,0 +1,104 @@ +// The stdio seam. Two invariants a broken MCP server usually violates: +// responses are newline-framed one per line, and notifications produce NO line +// at all — an extra frame desynchronises every client. +import { PassThrough } from 'stream'; +import { startStdioServer } from '../../../src/mcp/server'; + +function harness(http = async () => ({ ok: true })) { + const input = new PassThrough(); + const chunks: string[] = []; + const output = { write: (chunk: string) => { chunks.push(chunk); return true; } }; + startStdioServer( + { http, serverName: 'lss', serverVersion: '1.2.3' }, + input as never, + output as never, + ); + return { input, chunks }; +} + +const settle = () => new Promise(resolve => setImmediate(resolve)); + +describe('startStdioServer', () => { + it('answers one newline-framed JSON-RPC response per request', async () => { + const { input, chunks } = harness(); + input.write('{"id":1,"method":"ping"}\n'); + await settle(); + expect(chunks).toEqual(['{"jsonrpc":"2.0","id":1,"result":{}}\n']); + }); + + it('writes nothing for a notification or a blank line', async () => { + const { input, chunks } = harness(); + input.write('\n'); + input.write(' \n'); + input.write('{"method":"notifications/initialized"}\n'); + await settle(); + expect(chunks).toEqual([]); + }); + + it('preserves request order even when an earlier tool is slower', async () => { + const delays = [30, 0]; + let call = 0; + const http = jest.fn(async () => { + const wait = delays[call++] ?? 0; + await new Promise(resolve => setTimeout(resolve, wait)); + return { call }; + }); + const { input, chunks } = harness(http as never); + input.write('{"id":"slow","method":"tools/call","params":{"name":"lss_health"}}\n'); + input.write('{"id":"fast","method":"tools/call","params":{"name":"lss_services"}}\n'); + await new Promise(resolve => setTimeout(resolve, 80)); + expect(chunks).toHaveLength(2); + expect(JSON.parse(chunks[0]).id).toBe('slow'); + expect(JSON.parse(chunks[1]).id).toBe('fast'); + }); + + it('reports an unexpected failure on stderr without killing the stream', async () => { + const stderr = jest.spyOn(process.stderr, 'write').mockImplementation(() => true); + const input = new PassThrough(); + const output = { + write: jest.fn((chunk: string) => { + if (chunk.includes('"boom"')) throw new Error('stdout exploded'); + return true; + }), + }; + startStdioServer( + { http: async () => ({ ok: true }), serverName: 'lss', serverVersion: '1' }, + input as never, + output as never, + ); + input.write('{"id":"boom","method":"ping"}\n'); + await settle(); + expect(stderr).toHaveBeenCalledWith(expect.stringContaining('[lss-mcp] unhandled')); + // The reader survives: a following request is still answered. + input.write('{"id":"next","method":"ping"}\n'); + await settle(); + expect(output.write).toHaveBeenCalledWith(expect.stringContaining('"next"')); + stderr.mockRestore(); + }); + + it('stringifies a non-Error failure instead of losing it', async () => { + const stderr = jest.spyOn(process.stderr, 'write').mockImplementation(() => true); + const input = new PassThrough(); + const output = { write: () => { throw 'not-an-error'; } }; + startStdioServer( + { http: async () => ({ ok: true }), serverName: 'lss', serverVersion: '1' }, + input as never, + output as never, + ); + input.write('{"id":1,"method":"ping"}\n'); + await settle(); + expect(stderr).toHaveBeenCalledWith('[lss-mcp] unhandled: not-an-error\n'); + stderr.mockRestore(); + }); + + it('exits cleanly once stdin closes and the queue has drained', async () => { + const exit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never); + const { input } = harness(); + input.write('{"id":1,"method":"ping"}\n'); + input.end(); + await settle(); + await settle(); + expect(exit).toHaveBeenCalledWith(0); + exit.mockRestore(); + }); +}); diff --git a/tests/unit/mcp/tools.test.ts b/tests/unit/mcp/tools.test.ts new file mode 100644 index 0000000..617a570 --- /dev/null +++ b/tests/unit/mcp/tools.test.ts @@ -0,0 +1,177 @@ +// Each tool maps to exactly one orchestrator endpoint. These tests pin the +// method + path + body, because a wrong path here is invisible until a model +// calls the tool against a live stack. +import { TOOLS, TOOLS_BY_NAME, toolListPayload } from '../../../src/mcp/tools'; + +function call(name: string, args: Record = {}) { + const http = jest.fn(async () => ({ ok: true })); + const tool = TOOLS_BY_NAME.get(name); + if (!tool) throw new Error(`no such tool: ${name}`); + // Normalised to a rejection the way the protocol layer sees it: `callTool` + // awaits `run` inside its try/catch, so an argument check that throws + // synchronously and one that rejects are the same outcome to a client. + return { promise: Promise.resolve().then(() => tool.run(args, http)), http }; +} + +async function expectCall(name: string, args: Record, expected: unknown[]) { + const { promise, http } = call(name, args); + await promise; + expect(http).toHaveBeenCalledWith(...expected); +} + +describe('tool catalogue', () => { + it('names are unique, prefixed and snake_case', () => { + const names = TOOLS.map(t => t.name); + expect(new Set(names).size).toBe(names.length); + for (const n of names) expect(n).toMatch(/^lss_[a-z0-9_]+$/); + }); + + it('every mutating tool announces it in its description', () => { + for (const tool of TOOLS.filter(t => t.mutates)) { + expect(tool.description).toContain('MUTATES'); + } + }); + + it('required properties are always declared in the schema', () => { + for (const tool of TOOLS) { + for (const key of tool.inputSchema.required ?? []) { + expect(Object.keys(tool.inputSchema.properties)).toContain(key); + } + } + }); + + it('toolListPayload strips the server-side runner', () => { + for (const entry of toolListPayload() as Record[]) { + expect(Object.keys(entry).sort()).toEqual(['description', 'inputSchema', 'name']); + } + }); +}); + +describe('read-only tools', () => { + it('maps each to its endpoint', async () => { + await expectCall('lss_health', {}, ['GET', '/api/health']); + await expectCall('lss_config', {}, ['GET', '/api/config']); + await expectCall('lss_ports', {}, ['GET', '/api/config/ports']); + await expectCall('lss_services', {}, ['GET', '/api/services']); + await expectCall('lss_lambdas', {}, ['GET', '/api/lambdas']); + await expectCall('lss_apis', {}, ['GET', '/api/apis']); + await expectCall('lss_resources', {}, ['GET', '/api/resources']); + await expectCall('lss_resource_owners', {}, ['GET', '/api/resources/owners']); + await expectCall('lss_dynamo_tables', {}, ['GET', '/api/dynamo/tables']); + await expectCall('lss_queues', {}, ['GET', '/api/queues']); + await expectCall('lss_buckets', {}, ['GET', '/api/buckets']); + await expectCall('lss_secrets', {}, ['GET', '/api/secrets']); + await expectCall('lss_seeds', {}, ['GET', '/api/seeds']); + }); + + it('appends ?region= only when a region is given', async () => { + await expectCall('lss_resources', { region: 'sa-east-1' }, ['GET', '/api/resources?region=sa-east-1']); + await expectCall('lss_resources', { region: '' }, ['GET', '/api/resources']); + await expectCall('lss_resources', { region: 7 }, ['GET', '/api/resources']); + }); + + it('encodes names so a slash in a secret or function name cannot escape the path', async () => { + await expectCall('lss_lambda_logs', { name: 'a/b' }, ['GET', '/api/lambdas/a%2Fb/logs']); + }); + + it('rejects a missing or non-string required name', async () => { + await expect(call('lss_lambda_logs', {}).promise).rejects.toThrow('"name" is required'); + await expect(call('lss_dynamo_scan', { table: 5 }).promise).rejects.toThrow('"table" is required'); + }); +}); + +describe('dynamo tools', () => { + it('scan and query post the input through, defaulting scan input to {}', async () => { + await expectCall('lss_dynamo_scan', { table: 'Users' }, ['POST', '/api/dynamo/tables/Users/scan', {}]); + await expectCall( + 'lss_dynamo_scan', + { table: 'Users', input: { limit: 5 }, region: 'eu-west-1' }, + ['POST', '/api/dynamo/tables/Users/scan?region=eu-west-1', { limit: 5 }], + ); + await expectCall( + 'lss_dynamo_query', + { table: 'Orders', input: { keyConditionExpression: '#pk = :pk' } }, + ['POST', '/api/dynamo/tables/Orders/query', { keyConditionExpression: '#pk = :pk' }], + ); + await expectCall('lss_dynamo_query', { table: 'Orders' }, ['POST', '/api/dynamo/tables/Orders/query', {}]); + }); + + it('put_item wraps the plain item the API expects', async () => { + await expectCall( + 'lss_dynamo_put_item', + { table: 'Users', item: { id: 'u-1' } }, + ['POST', '/api/dynamo/tables/Users/items', { item: { id: 'u-1' } }], + ); + }); +}); + +describe('queue tools', () => { + it('send passes FIFO fields through', async () => { + await expectCall( + 'lss_queue_send', + { queue: 'q.fifo', body: 'hi', messageGroupId: 'g', messageDeduplicationId: 'd', delaySeconds: 2 }, + ['POST', '/api/queues/q.fifo/messages', { + body: 'hi', messageGroupId: 'g', messageDeduplicationId: 'd', delaySeconds: 2, + }], + ); + }); + + it('await_idle forwards the wait budget and the processed threshold', async () => { + await expectCall( + 'lss_queue_await_idle', + { queue: 'orders', timeoutMs: 30000, sinceProcessed: 1 }, + ['POST', '/api/queues/orders/await-idle', { timeoutMs: 30000, sinceProcessed: 1 }], + ); + await expectCall('lss_queue_await_idle', { queue: 'orders' }, [ + 'POST', '/api/queues/orders/await-idle', { timeoutMs: undefined, sinceProcessed: undefined }, + ]); + }); +}); + +describe('invoke', () => { + it('defaults to a synchronous invocation with an empty event', async () => { + await expectCall('lss_invoke', { name: 'createOrder' }, [ + 'POST', '/api/lambdas/createOrder/invoke', { payload: {}, invocationType: 'RequestResponse' }, + ]); + }); + + it('async switches to the Event invocation type', async () => { + await expectCall('lss_invoke', { name: 'fn', payload: { a: 1 }, async: true }, [ + 'POST', '/api/lambdas/fn/invoke', { payload: { a: 1 }, invocationType: 'Event' }, + ]); + }); +}); + +describe('bucket objects', () => { + it('builds the query string from prefix, delimiter and region', async () => { + await expectCall('lss_bucket_objects', { bucket: 'b' }, ['GET', '/api/buckets/b/objects']); + await expectCall( + 'lss_bucket_objects', + { bucket: 'b', prefix: 'incoming/', delimiter: '/', region: 'us-west-2' }, + ['GET', '/api/buckets/b/objects?prefix=incoming%2F&delimiter=%2F®ion=us-west-2'], + ); + // Empty strings and wrong types are dropped rather than sent as blanks. + await expectCall('lss_bucket_objects', { bucket: 'b', prefix: '', delimiter: 3, region: '' }, [ + 'GET', '/api/buckets/b/objects', + ]); + }); +}); + +describe('opensearch and seeds', () => { + it('search forwards index and body, defaulting body to {}', async () => { + await expectCall('lss_opensearch_search', { collection: 'c', index: 'i', body: { size: 1 } }, [ + 'POST', '/api/opensearch/collections/c/search', { index: 'i', body: { size: 1 } }, + ]); + await expectCall('lss_opensearch_search', { collection: 'c' }, [ + 'POST', '/api/opensearch/collections/c/search', { index: undefined, body: {} }, + ]); + }); + + it('seed_run targets one table or all of them', async () => { + await expectCall('lss_seed_run', {}, ['POST', '/api/seeds/run', {}]); + await expectCall('lss_seed_run', { table: '' }, ['POST', '/api/seeds/run', {}]); + await expectCall('lss_seed_run', { table: 'Users', region: 'us-east-2' }, [ + 'POST', '/api/seeds/run?region=us-east-2', { tableName: 'Users' }, + ]); + }); +}); From c70b040b55a3af1ab4b92ce28f25392ad5d302ea Mon Sep 17 00:00:00 2001 From: Viserion77 Date: Fri, 31 Jul 2026 01:45:31 +0000 Subject: [PATCH 03/16] Refactor tests to replace LocalStackManager with EngineManager - Updated seed-manager-guard tests to use EngineManager instead of LocalStackManager. - Modified config-manager tests to remove deprecated LocalStack configurations and adjust expected values. - Adjusted OpenSearch Explorer tests to target the engine endpoint directly, removing sidecar references. - Refactored resource-provisioner tests to eliminate sidecar endpoint logic, focusing on engine endpoint. - Updated seed-manager tests to reflect changes in error messages and endpoint handling related to the engine. --- .github/workflows/tests.yml | 16 +- .vscode/tasks.json | 143 +- AGENTS.md | 10 +- CHANGELOG.md | 55 + README.md | 129 +- REVISAO-2026-07-29.md | 57 + bin/cli.js | 137 +- docs/CONFIGURATION.md | 170 +- docs/FEATURES.md | 51 +- docs/MIGRATION-v2.md | 157 + docs/README.md | 2 +- docs/SELF_ENGINE.md | 36 +- examples/README.md | 37 +- examples/localstack-free/.env.example | 7 - examples/localstack-free/.gitignore | 6 - examples/localstack-free/README.md | 254 - examples/localstack-free/assets/logo.svg | 4 - .../auth-service/package-lock.json | 2745 ---------- .../localstack-free/auth-service/package.json | 19 - .../auth-service/serverless.yml | 112 - .../auth-service/src/handlers/aws.js | 15 - .../auth-service/src/handlers/listSignups.js | 14 - .../auth-service/src/handlers/login.js | 40 - .../src/handlers/onUserSignedUp.js | 24 - .../src/handlers/session-authorizer.js | 47 - .../auth-service/src/handlers/whoami.js | 10 - .../events-stack/package-lock.json | 2600 --------- .../localstack-free/events-stack/package.json | 14 - .../events-stack/serverless.yml | 37 - examples/localstack-free/index.html | 262 - examples/localstack-free/lss.config.json | 32 - .../orders-service/package-lock.json | 2800 ---------- .../orders-service/package.json | 23 - .../orders-service/serverless.yml | 167 - .../orders-service/src/handlers/aws.js | 23 - .../src/handlers/cleanupExpiredOrders.js | 28 - .../src/handlers/createOrder.js | 39 - .../orders-service/src/handlers/listOrders.js | 13 - .../src/handlers/listUploads.js | 25 - .../src/handlers/onOrderStream.js | 34 - .../orders-service/src/handlers/onUpload.js | 53 - .../src/handlers/processOrderQueue.js | 31 - .../orders-service/src/handlers/uploadFile.js | 37 - examples/localstack-free/package.json | 20 - .../localstack-free/seeds/auth-Sessions.json | 7 - .../localstack-free/seeds/orders-Orders.json | 29 - .../localstack-free/seeds/users-Users.json | 14 - examples/localstack-ultimate/.env.example | 7 - examples/localstack-ultimate/.gitignore | 8 - examples/localstack-ultimate/README.md | 237 - examples/localstack-ultimate/assets/logo.svg | 4 - examples/localstack-ultimate/index.html | 320 -- examples/localstack-ultimate/lss.config.json | 27 - .../localstack-ultimate/package-lock.json | 4790 ----------------- examples/localstack-ultimate/package.json | 38 - .../localstack-ultimate/scripts/wire-dlq.js | 73 - .../seeds/localstack-ultimate-Orders.json | 32 - .../seeds/localstack-ultimate-Sessions.json | 20 - .../seeds/localstack-ultimate-Users.json | 26 - examples/localstack-ultimate/serverless.yml | 359 -- .../src/handlers/auditEvents.js | 27 - .../localstack-ultimate/src/handlers/aws.js | 21 - .../src/handlers/createProduct.js | 35 - .../src/handlers/createUser.js | 34 - .../src/handlers/deleteProduct.js | 14 - .../src/handlers/enqueueOrder.js | 32 - .../src/handlers/getAudit.js | 15 - .../src/handlers/getProduct.js | 13 - .../src/handlers/health.js | 3 - .../src/handlers/listUploads.js | 22 - .../src/handlers/listUsers.js | 10 - .../src/handlers/onOrderStream.js | 31 - .../src/handlers/onUpload.js | 54 - .../src/handlers/opensearch.js | 25 - .../src/handlers/processOrderQueue.js | 74 - .../src/handlers/productStats.js | 30 - .../src/handlers/purgeSessions.js | 41 - .../src/handlers/respond.js | 11 - .../src/handlers/searchProducts.js | 42 - .../src/handlers/uploadFile.js | 34 - examples/self-hosted/lss.config.json | 3 +- examples/self-hosted/package.json | 2 +- jest.integration.config.js | 8 +- lss.config.json | 19 +- lss.config.json.example | 32 +- package-lock.json | 30 +- package.json | 2 +- src/client/lifecycle.ts | 12 +- src/client/namespaces/health.ts | 2 +- src/client/namespaces/seeds.ts | 2 +- src/client/types.ts | 12 +- src/mcp/tools.ts | 2 +- src/server/engine/aoss-sidecar.ts | 117 - .../engine/backends/localstack-backend.ts | 229 - src/server/engine/backends/self-backend.ts | 3 +- src/server/engine/engine-backend.ts | 19 - src/server/engine/engine-manager.ts | 52 +- src/server/engine/http/router.ts | 10 +- src/server/index.ts | 47 +- src/server/routes/config.ts | 66 +- src/server/services/config-manager.ts | 295 +- src/server/services/dynamo-explorer.ts | 6 +- src/server/services/localstack-manager.ts | 38 - src/server/services/opensearch-explorer.ts | 17 +- src/server/services/queue-inspector.ts | 8 +- src/server/services/resource-provisioner.ts | 20 +- src/server/services/s3-explorer.ts | 6 +- src/server/services/secrets-explorer.ts | 6 +- src/server/services/seed-manager.ts | 12 +- src/ui/package.json | 2 +- src/ui/src/App.vue | 15 +- src/ui/src/components/QueuesView.vue | 8 +- src/ui/src/components/ServicesList.vue | 8 +- src/ui/src/components/apis/ApisView.vue | 6 +- src/ui/src/components/buckets/BucketsView.vue | 4 +- .../components/dynamo/DynamoTablesList.vue | 3 + .../src/components/lambdas/LambdaDetail.vue | 6 +- src/ui/src/components/lambdas/LambdasList.vue | 6 +- .../opensearch/OpenSearchCollectionView.vue | 2 +- .../opensearch/OpenSearchCollectionsList.vue | 4 +- src/ui/src/components/queues/QueueDetail.vue | 2 +- src/ui/src/pages/OverviewPage.vue | 48 +- src/ui/src/pages/ServiceDetailPage.vue | 8 +- src/ui/src/pages/SettingsPage.vue | 132 +- src/ui/src/services/api.ts | 38 +- src/ui/src/services/engine.ts | 24 +- src/ui/tsconfig.json | 6 + tests/integration/apigw-raw-routes.test.ts | 30 +- tests/integration/client.test.ts | 26 +- tests/integration/features.test.ts | 35 +- .../apigw-raw}/gateway-stack/package.json | 0 .../apigw-raw}/gateway-stack/serverless.yml | 2 +- .../fixtures/apigw-raw/lss.config.json | 11 + .../cloudformation-template-create-stack.json | 82 + .../cloudformation-template-update-stack.json | 905 ++++ .../.serverless/serverless-state.json | 1272 +++++ .../.serverless/users-service.zip | Bin 0 -> 2971801 bytes .../users-service/package-lock.json | 0 .../apigw-raw}/users-service/package.json | 0 .../apigw-raw}/users-service/serverless.yml | 4 +- .../users-service/src/handlers/aws.ts | 0 .../users-service/src/handlers/createUser.ts | 0 .../users-service/src/handlers/getUser.ts | 0 .../users-service/src/handlers/listUsers.ts | 0 .../src/handlers/session-authorizer-v2.ts | 0 .../apigw-raw}/users-service/tsconfig.json | 0 .../fixtures/lss.client.config.json | 8 +- .../fixtures/lss.integration.config.json | 8 +- .../sample-microservice/lss.config.json | 11 +- .../sample-microservice/serverless.yml | 4 +- tests/setup.integration.ts | 2 +- tests/unit/cli-seed.test.ts | 20 +- tests/unit/cli/cli.test.ts | 135 +- tests/unit/client/lifecycle.test.ts | 33 +- tests/unit/engine/aoss-sidecar.test.ts | 181 - .../engine/wire-secret-seed-on-boot.test.ts | 4 +- tests/unit/routes/config.test.ts | 57 +- tests/unit/seed-manager-guard.test.ts | 10 +- tests/unit/services/config-manager.test.ts | 322 +- .../unit/services/opensearch-explorer.test.ts | 40 +- .../services/resource-provisioner.test.ts | 52 +- tests/unit/services/seed-manager.test.ts | 12 +- 162 files changed, 3253 insertions(+), 18506 deletions(-) create mode 100644 docs/MIGRATION-v2.md delete mode 100644 examples/localstack-free/.env.example delete mode 100644 examples/localstack-free/.gitignore delete mode 100644 examples/localstack-free/README.md delete mode 100644 examples/localstack-free/assets/logo.svg delete mode 100644 examples/localstack-free/auth-service/package-lock.json delete mode 100644 examples/localstack-free/auth-service/package.json delete mode 100644 examples/localstack-free/auth-service/serverless.yml delete mode 100644 examples/localstack-free/auth-service/src/handlers/aws.js delete mode 100644 examples/localstack-free/auth-service/src/handlers/listSignups.js delete mode 100644 examples/localstack-free/auth-service/src/handlers/login.js delete mode 100644 examples/localstack-free/auth-service/src/handlers/onUserSignedUp.js delete mode 100644 examples/localstack-free/auth-service/src/handlers/session-authorizer.js delete mode 100644 examples/localstack-free/auth-service/src/handlers/whoami.js delete mode 100644 examples/localstack-free/events-stack/package-lock.json delete mode 100644 examples/localstack-free/events-stack/package.json delete mode 100644 examples/localstack-free/events-stack/serverless.yml delete mode 100644 examples/localstack-free/index.html delete mode 100644 examples/localstack-free/lss.config.json delete mode 100644 examples/localstack-free/orders-service/package-lock.json delete mode 100644 examples/localstack-free/orders-service/package.json delete mode 100644 examples/localstack-free/orders-service/serverless.yml delete mode 100644 examples/localstack-free/orders-service/src/handlers/aws.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/cleanupExpiredOrders.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/createOrder.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/listOrders.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/listUploads.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/onOrderStream.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/onUpload.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/processOrderQueue.js delete mode 100644 examples/localstack-free/orders-service/src/handlers/uploadFile.js delete mode 100644 examples/localstack-free/package.json delete mode 100644 examples/localstack-free/seeds/auth-Sessions.json delete mode 100644 examples/localstack-free/seeds/orders-Orders.json delete mode 100644 examples/localstack-free/seeds/users-Users.json delete mode 100644 examples/localstack-ultimate/.env.example delete mode 100644 examples/localstack-ultimate/.gitignore delete mode 100644 examples/localstack-ultimate/README.md delete mode 100644 examples/localstack-ultimate/assets/logo.svg delete mode 100644 examples/localstack-ultimate/index.html delete mode 100644 examples/localstack-ultimate/lss.config.json delete mode 100644 examples/localstack-ultimate/package-lock.json delete mode 100644 examples/localstack-ultimate/package.json delete mode 100644 examples/localstack-ultimate/scripts/wire-dlq.js delete mode 100644 examples/localstack-ultimate/seeds/localstack-ultimate-Orders.json delete mode 100644 examples/localstack-ultimate/seeds/localstack-ultimate-Sessions.json delete mode 100644 examples/localstack-ultimate/seeds/localstack-ultimate-Users.json delete mode 100644 examples/localstack-ultimate/serverless.yml delete mode 100644 examples/localstack-ultimate/src/handlers/auditEvents.js delete mode 100644 examples/localstack-ultimate/src/handlers/aws.js delete mode 100644 examples/localstack-ultimate/src/handlers/createProduct.js delete mode 100644 examples/localstack-ultimate/src/handlers/createUser.js delete mode 100644 examples/localstack-ultimate/src/handlers/deleteProduct.js delete mode 100644 examples/localstack-ultimate/src/handlers/enqueueOrder.js delete mode 100644 examples/localstack-ultimate/src/handlers/getAudit.js delete mode 100644 examples/localstack-ultimate/src/handlers/getProduct.js delete mode 100644 examples/localstack-ultimate/src/handlers/health.js delete mode 100644 examples/localstack-ultimate/src/handlers/listUploads.js delete mode 100644 examples/localstack-ultimate/src/handlers/listUsers.js delete mode 100644 examples/localstack-ultimate/src/handlers/onOrderStream.js delete mode 100644 examples/localstack-ultimate/src/handlers/onUpload.js delete mode 100644 examples/localstack-ultimate/src/handlers/opensearch.js delete mode 100644 examples/localstack-ultimate/src/handlers/processOrderQueue.js delete mode 100644 examples/localstack-ultimate/src/handlers/productStats.js delete mode 100644 examples/localstack-ultimate/src/handlers/purgeSessions.js delete mode 100644 examples/localstack-ultimate/src/handlers/respond.js delete mode 100644 examples/localstack-ultimate/src/handlers/searchProducts.js delete mode 100644 examples/localstack-ultimate/src/handlers/uploadFile.js delete mode 100644 src/server/engine/aoss-sidecar.ts delete mode 100644 src/server/engine/backends/localstack-backend.ts delete mode 100644 src/server/engine/engine-backend.ts delete mode 100644 src/server/services/localstack-manager.ts rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/gateway-stack/package.json (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/gateway-stack/serverless.yml (99%) create mode 100644 tests/integration/fixtures/apigw-raw/lss.config.json create mode 100644 tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-create-stack.json create mode 100644 tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-update-stack.json create mode 100644 tests/integration/fixtures/apigw-raw/users-service/.serverless/serverless-state.json create mode 100644 tests/integration/fixtures/apigw-raw/users-service/.serverless/users-service.zip rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/package-lock.json (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/package.json (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/serverless.yml (98%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/src/handlers/aws.ts (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/src/handlers/createUser.ts (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/src/handlers/getUser.ts (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/src/handlers/listUsers.ts (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/src/handlers/session-authorizer-v2.ts (100%) rename {examples/localstack-free => tests/integration/fixtures/apigw-raw}/users-service/tsconfig.json (100%) delete mode 100644 tests/unit/engine/aoss-sidecar.test.ts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 613956c..8fc3f67 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,13 +30,13 @@ jobs: run: npm run test:coverage integration: - name: Integration Tests (LocalStack) + name: Integration Tests (self engine) runs-on: ubuntu-latest - timeout-minutes: 25 - # ubuntu-latest runners ship Docker; LocalStack runs as an unprivileged - # container. Gated on the token: community images >= 2026.5 require it. - env: - LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} + timeout-minutes: 15 + # v2 removed the LocalStack backend: the engine runs in the orchestrator + # process, so this job needs no Docker, no service container and no secret. + # It is therefore unconditional — under v1 it skipped itself whenever the + # LocalStack auth token was absent, which was most of the time. steps: - name: Checkout code uses: actions/checkout@v4 @@ -48,19 +48,15 @@ jobs: cache: 'npm' - name: Install dependencies (root) - if: env.LOCALSTACK_AUTH_TOKEN != '' run: npm ci - name: Install dependencies (sample-microservice fixture) - if: env.LOCALSTACK_AUTH_TOKEN != '' run: npm ci --prefix tests/integration/fixtures/sample-microservice - name: Build project - if: env.LOCALSTACK_AUTH_TOKEN != '' run: npm run build - name: Run integration tests - if: env.LOCALSTACK_AUTH_TOKEN != '' run: npm run test:integration lint: diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 35c2b1f..8d3909d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -41,25 +41,6 @@ "icon": { "id": "play-circle", "color": "terminal.ansiCyan" }, "problemMatcher": [] }, - { - "label": "dev @ example localstack-free (watch, sem build)", - "detail": "npm run dev lendo examples/localstack-free/lss.config.json — orquestrador forçado em :3100 (a UI dev espera essa porta); exige Docker. UI em :3101", - "type": "shell", - "command": "LSS_DASHBOARD_PORT=3100 LSS_CONFIG_PATH=examples/localstack-free/lss.config.json npm run dev", - "isBackground": true, - "icon": { "id": "play-circle", "color": "terminal.ansiCyan" }, - "problemMatcher": [] - }, - { - "label": "dev @ example localstack-ultimate (watch, sem build)", - "detail": "Carrega examples/localstack-ultimate/.env (token) + lss.config.json e roda npm run dev — orquestrador forçado em :3100 (a UI dev espera essa porta); exige Docker. UI em :3101", - "type": "shell", - "command": "set -a; [ -f examples/localstack-ultimate/.env ] && . examples/localstack-ultimate/.env; set +a; LSS_DASHBOARD_PORT=3100 LSS_CONFIG_PATH=examples/localstack-ultimate/lss.config.json npm run dev", - "isBackground": true, - "icon": { "id": "play-circle", "color": "terminal.ansiCyan" }, - "problemMatcher": [] - }, - // ------------------------------------------------------------------ // Tests & validation // ------------------------------------------------------------------ @@ -90,8 +71,8 @@ "problemMatcher": [] }, { - "label": "test: integration (Docker + LOCALSTACK_AUTH_TOKEN)", - "detail": "Suite de integração com LocalStack real — exige Docker e token", + "label": "test: integration (self engine, no Docker)", + "detail": "Suite de integração ponta a ponta no self engine — sem Docker, sem token", "type": "npm", "script": "test:integration", "group": "test", @@ -214,126 +195,6 @@ ], "icon": { "id": "rocket", "color": "terminal.ansiYellow" }, "problemMatcher": [] - }, - - // ------------------------------------------------------------------ - // Example: localstack-free (LocalStack community 4.0 via Docker) - // ------------------------------------------------------------------ - { - "label": "example localstack-free: start (Docker)", - "detail": "Sobe o LSS com LocalStack community 4.0 gerenciado (exige Docker, sem token)", - "type": "shell", - "command": "npm run lss:start", - "options": { "cwd": "${workspaceFolder}/examples/localstack-free" }, - "icon": { "id": "server-environment", "color": "terminal.ansiGreen" }, - "problemMatcher": [] - }, - { - "label": "example localstack-free: register services", - "type": "shell", - "command": "npm run register:all", - "options": { "cwd": "${workspaceFolder}/examples/localstack-free" }, - "icon": { "id": "cloud-upload", "color": "terminal.ansiBlue" }, - "problemMatcher": [] - }, - { - "label": "example localstack-free: stop", - "type": "shell", - "command": "npm run lss:stop", - "options": { "cwd": "${workspaceFolder}/examples/localstack-free" }, - "icon": { "id": "debug-stop", "color": "terminal.ansiRed" }, - "problemMatcher": [] - }, - { - "label": "example localstack-free: restart (rebuild local)", - "detail": "build: all > stop > start — o CLI roda o dist/ compilado, então este é o caminho para ver mudanças locais no exemplo", - "dependsOrder": "sequence", - "dependsOn": [ - "build: all", - "example localstack-free: stop", - "example localstack-free: start (Docker)" - ], - "icon": { "id": "refresh", "color": "terminal.ansiYellow" }, - "problemMatcher": [] - }, - - // ------------------------------------------------------------------ - // Example: localstack-ultimate (LocalStack Pro via Docker + token) - // ------------------------------------------------------------------ - { - "label": "example localstack-ultimate: setup", - "detail": "npm install no exemplo (SDKs + serverless-offline + plugin LSS)", - "type": "shell", - "command": "npm run setup", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "desktop-download", "color": "terminal.ansiBlue" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: start (Docker + token)", - "detail": "Sobe o LSS com LocalStack Pro gerenciado — exige Docker e LOCALSTACK_AUTH_TOKEN obrigatório no .env", - "type": "shell", - "command": "npm run lss:start", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "server-environment", "color": "terminal.ansiGreen" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: offline (HTTP :3002)", - "detail": "sls package + RedrivePolicy (wire-dlq) + serverless-offline — fica em primeiro plano, não encadeie em dependsOn", - "type": "shell", - "command": "npm run offline", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "isBackground": true, - "icon": { "id": "play-circle", "color": "terminal.ansiCyan" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: seed", - "detail": "Recarrega os seeds (Users/Orders/Sessions) no LocalStack Pro — LSS precisa estar de pé", - "type": "shell", - "command": "npm run seed", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "database", "color": "terminal.ansiYellow" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: drive demo", - "detail": "POST /users e /orders (incl. ordem envenenada p/ DLQ) e lê /users e /audit em :3002", - "type": "shell", - "command": "curl -s -X POST http://localhost:3002/dev/users -H 'content-type: application/json' -d '{\"name\":\"Task Runner\",\"email\":\"task@example.com\"}' && echo && echo '--- USERS:' && curl -s http://localhost:3002/dev/users && echo && echo '--- ORDER (SQS -> DynamoDB -> EventBridge):' && curl -s -X POST http://localhost:3002/dev/orders -H 'content-type: application/json' -d '{\"userId\":\"u-alice\",\"items\":[{\"sku\":\"BOOK-02\",\"price\":42,\"qty\":1}]}' && echo && echo '--- POISON ORDER (total 0 -> DLQ apos 3 tentativas, ~30s):' && curl -s -X POST http://localhost:3002/dev/orders -H 'content-type: application/json' -d '{\"userId\":\"u-alice\",\"items\":[{\"sku\":\"BROKEN\",\"price\":0,\"qty\":1}]}' && echo && sleep 5 && echo '--- AUDIT:' && curl -s http://localhost:3002/dev/audit && echo", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "run-all", "color": "terminal.ansiCyan" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: drive catalog (OpenSearch)", - "detail": "Indexa produtos e roda busca full-text, filtros e agregações — coleção aoss servida pelo sidecar do LSS (:14567)", - "type": "shell", - "command": "curl -s -X POST http://localhost:3002/dev/products -H 'content-type: application/json' -d '{\"name\":\"Wireless Mouse\",\"category\":\"peripherals\",\"price\":25,\"tags\":[\"usb\",\"wireless\"]}' && echo && curl -s -X POST http://localhost:3002/dev/products -H 'content-type: application/json' -d '{\"name\":\"Mechanical Keyboard\",\"category\":\"peripherals\",\"price\":90,\"tags\":[\"usb\"]}' && echo && curl -s -X POST http://localhost:3002/dev/products -H 'content-type: application/json' -d '{\"name\":\"USB Hub\",\"category\":\"accessories\",\"price\":15,\"tags\":[\"usb\"]}' && echo && echo '--- SEARCH q=wireless:' && curl -s 'http://localhost:3002/dev/search?q=wireless' && echo && echo '--- SEARCH category+maxPrice:' && curl -s 'http://localhost:3002/dev/search?category=peripherals&maxPrice=50' && echo && echo '--- STATS:' && curl -s http://localhost:3002/dev/stats && echo", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "search", "color": "terminal.ansiCyan" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: stop", - "type": "shell", - "command": "npm run lss:stop", - "options": { "cwd": "${workspaceFolder}/examples/localstack-ultimate" }, - "icon": { "id": "debug-stop", "color": "terminal.ansiRed" }, - "problemMatcher": [] - }, - { - "label": "example localstack-ultimate: restart (rebuild local)", - "detail": "build: all > stop > start — o CLI roda o dist/ compilado, então este é o caminho para ver mudanças locais no exemplo", - "dependsOrder": "sequence", - "dependsOn": [ - "build: all", - "example localstack-ultimate: stop", - "example localstack-ultimate: start (Docker + token)" - ], - "icon": { "id": "refresh", "color": "terminal.ansiYellow" }, - "problemMatcher": [] } ] } diff --git a/AGENTS.md b/AGENTS.md index 0e7e6e1..641d741 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,9 +10,9 @@ LSS is a **local control plane for serverless development**. One orchestrator provisions and serves every AWS resource your services declare, so a monorepo of 15+ microservices needs a single local -stack instead of one LocalStack per service. It ships two interchangeable backends: the **self -engine** (an in-process AWS emulator — no Docker, no token, the project's differentiator) and -**LocalStack** (community or Pro). It also replaces `serverless-offline` with its own Lambda runtime +stack instead of one emulator per service. The AWS provider is the **self engine**: an in-process +emulator — no Docker, no container, no auth token — and since v2 the only engine LSS ships. It also +replaces `serverless-offline` with its own Lambda runtime and API Gateway emulation. Published as the npm package `local-serverless-stack` (CLI: `lss`), plus the workspace package @@ -31,7 +31,7 @@ Published as the npm package `local-serverless-stack` (CLI: `lss`), plus the wor | `src/mcp/` | MCP server (`lss mcp`) — the stack as tools for an AI coding agent | | `src/ui/` | Vue 3 dashboard (own workspace) | | `packages/serverless-plugin/` | The `serverless-lss` plugin (separately versioned & published) | -| `examples/` | `self-hosted` (self engine, no Docker), `localstack-free`, `localstack-ultimate` | +| `examples/` | `self-hosted` — four microservices on the engine (DynamoDB, SQS, S3, EventBridge, OpenSearch, Secrets) | | `tests/` | `unit/`, `integration/` (Docker + token gated), `fixtures/` | | `docs/` | `FEATURES.md`, `SELF_ENGINE.md`, `CONFIGURATION.md`, `RELEASE.md`, PRDs | @@ -97,8 +97,6 @@ shipping the change, not an afterthought. End-to-end proof lives in `examples/`, not in ad-hoc scripts: - `examples/self-hosted` — four microservices on the self engine (DynamoDB, SQS, S3, EventBridge). The default target. -- `examples/localstack-free` — API Gateway proxy, cross-service Lambda authorizers, shared bus, streams, S3 notifications. -- `examples/localstack-ultimate` — Pro-only surfaces. A new engine capability should gain (or extend) a fixture in one of these plus an assertion. When a full boot e2e isn't practical, drive the real backend from a `tests/unit/engine/wire-*.test.ts` diff --git a/CHANGELOG.md b/CHANGELOG.md index 814e0ae..ee0a71a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.0] - 2026-07-31 + +**LSS runs on one engine.** The LocalStack backend is gone — not deprecated, removed. The self +engine, an in-process AWS emulator with no Docker, no container and no auth token, is what LSS is. +Migration guide: [docs/MIGRATION-v2.md](docs/MIGRATION-v2.md); for a project already on +`engine: "self"` it is a matter of deleting a few config keys. + +The trigger was evidence, not preference. Both shipped LocalStack examples were run end to end +against the self engine first: `localstack-ultimate` (45 resources, `eu-west-1`) exercised REST +payload-v1 routes, a DynamoDB composite key + GSI + stream, SQS with DLQ redrive at +`maxReceiveCount: 3`, `SNS Publish` from a stream handler, an EventBridge bus with a pattern rule, +a `rate(2 minutes)` schedule, an S3 notification with a prefix filter and an OpenSearch Serverless +catalog — **every path fired, zero errors**. `localstack-free` added a REST v1 authorizer, an +httpApi v2 simple-response authorizer written in TypeScript, and a cross-service authorizer +resolved by ARN. Nothing the project supported on LocalStack needed LocalStack. + +### Removed +- **The LocalStack backend**: `src/server/engine/backends/localstack-backend.ts`, + `src/server/services/localstack-manager.ts`, `src/server/engine/aoss-sidecar.ts` and the + `EngineBackend` interface. `EngineManager` now owns the one engine. +- **Config keys**: `engine` (accepted only to reject a v1 `"localstack"` with a migration error), + `mode`, `localstackPort`, `localstackEndpoint`, `localstackEdition`, `localstackVersion`, + `localstackImage`, `localstackAuthToken`, `services`, `aossSidecar`. Editing any of them through + `PUT /api/config` now answers `unknown config key`. +- **Env vars**: `LSS_LOCALSTACK_*`, `LOCALSTACK_AUTH_TOKEN`, `LSS_SERVICES`. `LSS_ENGINE` survives + only to reject `localstack`. +- **CLI flags**: `--self-engine`, `--external`, `--pro`, `--localstack-token`. Each exits 1 naming + the migration guide — checked before the already-running short-circuit, so a stale script fails + visibly instead of looking like a successful no-op. +- **API fields**: `GET /api/health` → `localstack` (use `engineRunning`); `GET /api/config` → + the `localstack` block, `aossSidecar` and `services`. `LssClient`: `HealthStatus.localstack` and + `lifecycle.start({ external, pro, localstackToken })`. +- **Examples**: `examples/localstack-free` and `examples/localstack-ultimate` (760 MB). Their raw + `AWS::ApiGatewayV2::*` cross-stack topology was preserved at + `tests/integration/fixtures/apigw-raw/`, where its end-to-end test still runs. + +### Changed +- **The integration suite runs everywhere.** It boots an isolated orchestrator on the self engine + instead of a LocalStack container, so it needs no Docker and no secret: **19 end-to-end + assertions in ~20 s**, unconditional locally and in CI. Under v1 the same suite skipped itself + whenever the LocalStack auth token was absent — which was most of the time, meaning the project's + only end-to-end coverage usually did not run. +- OpenSearch Serverless is served natively by the engine on its own endpoint; the sidecar that + existed only because no LocalStack edition provides `aoss` is gone. +- `lambdaRuntime.invokeHost` defaults to `127.0.0.1` (nothing runs in a container). +- The dashboard, the CLI and every log line name the engine instead of LocalStack. + +### Fixed +- **The UI was never type-checked.** `src/ui/tsconfig.json` extends the root config, which excludes + `src/ui` — and `exclude` is inherited with paths resolved against the *root* file, so the + dashboard excluded itself from its own project and `vue-tsc --noEmit` silently checked nothing. + With that reset, 12 real pre-existing errors surfaced and were fixed: a TreeUI `TreeBadgeTone` → + `TBadgeTone` rename across 6 components, two unused imports, a `TableRow`/`Record` mismatch, an + `unknown` in a table slot, and a `ResourceOwnersResponse` fallback missing `collections`. + ## [0.17.0] - 2026-07-18 The raw `AWS::ApiGatewayV2::*` support that shipped in 0.16.0 met a real Serverless Framework project and lost: it reduced a hand-authored idiom only, so the shapes `serverless package` actually emits fell through as `no ::Integration for Target "(none)"` and the routes were skipped without ever answering a request. Every one of those shapes now reduces, proven against a committed real packaging snapshot rather than a hand-written fixture. Alongside it, SQS grows **queue-level redrive**: a poison message finally lands in its dead-letter queue instead of being redelivered until retention quietly eats it. diff --git a/README.md b/README.md index 73fb4a8..453272f 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,16 @@ [![npm version](https://img.shields.io/npm/v/local-serverless-stack.svg)](https://www.npmjs.com/package/local-serverless-stack) -**Local control plane for serverless development — with its own in-process AWS engine (no Docker) or LocalStack orchestration** +**Local control plane for serverless development — with its own in-process AWS engine. No Docker, no container, no auth token.** -LSS provides a unified local development environment for serverless microservices: one orchestrator provisions and serves every AWS resource your services declare, eliminating the need to run separate LocalStack instances (or, with the **self engine**, any LocalStack at all). It scales to monorepos with 15+ microservices sharing one stack. +LSS provides a unified local development environment for serverless microservices: one orchestrator provisions and serves every AWS resource your services declare, so a monorepo needs a single local stack instead of one emulator per service. Measured on a synthetic 40-service / 400-lambda / 400-table monorepo: **128 MB resident and a 2 s boot**. ```mermaid flowchart LR DEV[Developer] -->|npx lss start| CLI[CLI
bin/cli.js] CLI --> ORCH[Orchestrator
Express API + dashboard :3100] SVC[Your services
serverless.yml + serverless-lss] -->|sls package → register| ORCH - ORCH -->|provision + events| ENGINE{Engine} - ENGINE -->|"engine: self"| SELF[Self engine
in-process :14566] - ENGINE -->|"engine: localstack"| LS[LocalStack
Docker :4566] + ORCH -->|provision + events| SELF[Self engine
in-process :14566] ORCH --> RT[Lambda runtime + API Gateway emulation
your handlers, ports 30xx/130xx] ``` @@ -34,13 +32,14 @@ LSS features come in two layers: - **Platform** — the orchestrator, CLI, dashboard, plugin, programmatic client, Lambda/API runtime and seeds. **Engine-agnostic:** they behave the same whichever backend you choose. - **AWS engine** — the backend that actually serves the AWS wire protocols. You pick **one per - instance**: LocalStack Free, LocalStack Ultimate (Pro), or the in-process self engine. + instance**, served by the in-process self engine. ### 🧩 Platform (engine-agnostic) - **CLI (`npx lss …`)** - - `start` — runs the orchestrator detached (PID + log files), flags `--self-engine`, `--external`, `--pro`, `--localstack-token`, `--enable-dynamo-proxy`, `--config` - - `status` · `logs` · `stop` (also tears down the managed LocalStack) + - `start` — runs the orchestrator detached (PID + log files), flags `--enable-dynamo-proxy`, `--config` + - `status` · `logs` · `stop` + - `mcp` — serves the stack to an AI coding agent over MCP ([docs/MCP.md](docs/MCP.md)) - `seed [table]` / `seed:clear [table] -y` — apply / wipe DynamoDB fixtures (hard local-endpoint guard on clear) - `help` — every command, flag and a config template - **Orchestration & provisioning** @@ -82,39 +81,15 @@ LSS features come in two layers: - **DynamoDB seeds** — `seeds/{tableName}.json` fixtures auto-applied on table creation, re-applied via `lss seed` or the dashboard - **Secret seeds** — `seeds/secrets/{name}.json` fixtures (plus an optional `secrets:` config map) created on boot *before* services are reactivated, so a handler's first `GetSecretValue` finds an `AWSCURRENT` version with no bootstrap step; idempotent (an existing secret is never clobbered) and non-fatal -### 🆓 Engine: LocalStack Free (community image, Docker) - -LSS spins up and manages its own community LocalStack container (`lss-localstack-`) with -`dynamodb, sqs, sns, s3, lambda, events`, a persistence volume and the local Lambda executor. Events -reach your handlers through a generated proxy Lambda inside the container that calls the LSS invoke -listener. This is the default engine; the [localstack-free example](examples/localstack-free/) runs -community 4.0 with no token. - -- **Provisioned & wired**: DynamoDB tables (keys, GSI/LSI, streams, TTL), SQS queues (incl. FIFO), SNS topics, S3 buckets (versioning + `s3:ObjectCreated:*` notifications), EventBridge buses & rules (pattern or `rate()`/cron schedules), Lambda event source mappings -- **Not available on community**: OpenSearch Serverless (`aoss`) — provisioning fails with an explicit error pointing you at Pro or the self engine -- Community images `>= 2026.5` require `LOCALSTACK_AUTH_TOKEN`; `mode: external` / `--external` points at a LocalStack you already run - -### 💎 Engine: LocalStack Ultimate (Pro image, auth token) - -`npx lss start --pro` (optionally `--localstack-token ls-xxx`) runs the LocalStack **Pro** image — same -provisioning and wiring as Free, plus the Pro-only services (OpenSearch Serverless and more). The -[localstack-ultimate example](examples/localstack-ultimate/) keeps the serverless-offline path in -charge of the ports and exercises the full resource menu (custom bus + pattern rule with an audit -trail, `rate()` schedule, SQS DLQ redrive with `ReportBatchItemFailures`, DynamoDB GSI + streams → -SNS, S3 notifications, TTL from the UI). - -- Requires `LOCALSTACK_AUTH_TOKEN` (Ultimate plan) -- `localstackEdition` / `localstackVersion` / `localstackImage` select the exact image - -### ⚡ Engine: Self (in-process AWS emulator — no Docker, no token) — *the LSS differentiator* +### ⚡ The engine: an in-process AWS emulator The orchestrator serves the AWS wire protocols itself on one port (default `14566`); events are delivered **in-process** straight to the LSS Lambda runtime — no container, no proxy Lambdas, no polling. Data persists as JSONL snapshot + WAL / content-addressed blobs under `~/.lss/engine`, hydrated on first touch and dehydrated when idle. Anything unimplemented answers with an explicit -AWS-shaped error or is forwarded to `selfEngine.fallbackEndpoint`. See the [Self engine -section](#self-engine--no-docker-no-localstack-no-auth-token) below for boot-time numbers and the -migration story, and [docs/SELF_ENGINE.md](docs/SELF_ENGINE.md) for the full coverage matrix. +AWS-shaped error or is forwarded to `selfEngine.fallbackEndpoint`. See the [engine +section](#the-engine--no-docker-no-container-no-auth-token) below for boot-time numbers, and +[docs/SELF_ENGINE.md](docs/SELF_ENGINE.md) for the full coverage matrix. - **DynamoDB** - Full expression language: KeyCondition, Condition, Filter, Update, Projection — decimal-exact `N` arithmetic @@ -132,22 +107,25 @@ migration story, and [docs/SELF_ENGINE.md](docs/SELF_ENGINE.md) for the full cov - **STS** — GetCallerIdentity - **Lambda control plane** — proxy absorption as metadata (`INVOKE_URL` kept as HTTP fallback), event source mapping lifecycle (`Enabled` toggle = QueueInspector hold/release), Invoke passthrough - **In-process event delivery** — SQS→Lambda (batch size/window, visibility semantics), DynamoDB streams, S3 notifications (globs + prefix/suffix), EventBridge rule/schedule targets to Lambda (invoke) or SQS (enqueue; FIFO `MessageGroupId`) with `Input`/`InputPath`, schedules — no proxies, no polling -- **Wire front door & storage** — single-port routing (SigV4-scope / X-Amz-Target / path), per-protocol error shapes, `/_localstack/health` alias, `fallbackEndpoint` reverse proxy; JSONL snapshot + WAL (torn-tail-safe, compaction), atomic JSON catalogs, content-addressed S3 blobs, hydrate-on-touch + idle dehydrate + `memoryBudgetMb` LRU +- **Wire front door & storage** — single-port routing (SigV4-scope / X-Amz-Target / path), per-protocol error shapes, `fallbackEndpoint` reverse proxy; JSONL snapshot + WAL (torn-tail-safe, compaction), atomic JSON catalogs, content-addressed S3 blobs, hydrate-on-touch + idle dehydrate + `memoryBudgetMb` LRU For how each capability is tested (unit vs integration) see [docs/FEATURES.md](docs/FEATURES.md); the self-engine coverage matrix and known divergences from AWS live in [docs/SELF_ENGINE.md](docs/SELF_ENGINE.md). -## Self engine — no Docker, no LocalStack, no auth token +## The engine — no Docker, no container, no auth token + +Container-based emulators got heavy (1 GB+ of RAM each) and stopped being free by default. +The LSS engine replaces them for the serverless dev loop: the orchestrator itself serves +the real AWS wire protocols on one port, so your application code, the AWS SDK, the +dashboard and `lss seed` all work unchanged — there is simply no container underneath. -LocalStack got heavy (a container eating 1 GB+ of RAM) and stopped being free by default -(community images `>= 2026.5` require an auth token). The **self engine** replaces it for -the typical serverless dev loop: the orchestrator itself serves the real AWS wire -protocols on one port, so your application code, the AWS SDK, the dashboard and `lss seed` -all work unchanged — there is simply no container underneath. +> **Upgrading from v1?** v2 removed the LocalStack backend. See +> [docs/MIGRATION-v2.md](docs/MIGRATION-v2.md) — for a project already on `engine: "self"` +> it is a matter of deleting a few config keys. ```bash -npx lss start --self-engine # or "engine": "self" in lss.config.json +npx lss start ``` ``` @@ -188,9 +166,8 @@ engine boot **~10 ms**; a full pipeline crossing DynamoDB + SQS + S3 + EventBrid across the three pipeline services completes in **~170 ms** — with the whole stack being the orchestrator process plus one small worker per service. -Migration is gradual: LocalStack mode remains the default and fully supported; a running -instance picks one engine. Anything the self engine doesn't implement yet answers with an -explicit error naming the operation — or is forwarded verbatim to a LocalStack via +Anything the engine doesn't implement answers with an explicit error naming the +operation — or is forwarded verbatim to any AWS-compatible endpoint via `selfEngine.fallbackEndpoint`. Coverage matrix and storage model: [docs/SELF_ENGINE.md](docs/SELF_ENGINE.md) · design/PRD: [docs/PRD_SELF_ENGINE.md](docs/PRD_SELF_ENGINE.md) · runnable demo: @@ -198,14 +175,14 @@ explicit error naming the operation — or is forwarded verbatim to a LocalStack ## Quick Start -Prerequisites: Node.js >= 20 · [osls](https://github.com/oss-serverless/serverless) 4.x (open-source Serverless Framework fork; provides the `serverless`/`sls` CLI) · Docker (**only** for the LocalStack engine) +Prerequisites: Node.js >= 20 · [osls](https://github.com/oss-serverless/serverless) 4.x (open-source Serverless Framework fork; provides the `serverless`/`sls` CLI). **No Docker.** ```bash # 1. Install npm install -g local-serverless-stack -# 2. Start the orchestrator (self engine: no Docker needed) -npx lss start --self-engine # or plain `npx lss start` for LocalStack +# 2. Start the orchestrator (engine runs in-process — no Docker needed) +npx lss start # 3. In each microservice: install the plugin and add it to serverless.yml npm install --save-dev serverless-lss @@ -239,8 +216,6 @@ complete runnable projects live in [examples/](examples/) — one per engine fla | Example | Shows | | --- | --- | -| [localstack-free](examples/localstack-free/) | LocalStack community 4.0 (Docker, no token): 3 services + a shared EventBridge bus — authorizers, SQS, schedules, DynamoDB stream → SNS, S3 notifications, seeds | -| [localstack-ultimate](examples/localstack-ultimate/) | LocalStack Pro image (Ultimate plan, auth token) with the serverless-offline path preserved | | [self-hosted](examples/self-hosted/) | The no-Docker self engine end to end: orders → billing → notifications pipeline + an OpenSearch Serverless catalog | Each example ships an `index.html` validation console and its own dashboard @@ -250,18 +225,15 @@ shared conventions. ## CLI ```bash -npx lss start # start the orchestrator in background (managed LocalStack) +npx lss start # start the orchestrator + engine in background npx lss start --self-engine # …with the in-process self engine (no Docker) -npx lss start --external # …connecting to a LocalStack you already run -npx lss start --pro # …with the LocalStack Pro image (needs auth token) -npx lss start --pro --localstack-token ls-xxx # …passing the auth token inline npx lss start --enable-dynamo-proxy # …with the DynamoDB proxy on :8000 npx lss start --config ./e2e/lss.config.json # explicit config file (any command) npx lss status # is it running? which ports? npx lss logs # tail the orchestrator log npx lss seed [table] # apply DynamoDB seed files (all tables or one) npx lss seed:clear [table] -y # empty seeded tables (prompts unless --yes) -npx lss stop # stop the orchestrator (and managed LocalStack) +npx lss stop # stop the orchestrator npx lss help # all commands, flags and a config template ``` @@ -287,10 +259,7 @@ optional — [full reference](docs/CONFIGURATION.md)): ```jsonc { "serverPort": 3100, // dashboard + API - "engine": "localstack", // "localstack" (default) | "self" (no Docker) - "selfEngine": { "port": 14566 }, // engine "self" settings — docs/SELF_ENGINE.md - "localstackPort": 4566, - "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], + "selfEngine": { "port": 14566 }, // engine settings — docs/SELF_ENGINE.md "seedsDir": "./seeds", // DynamoDB fixtures ({tableName}.json) "autoPackage": false, // run `sls package` on register when template is missing "lambdaRuntime": { "enabled": true, "execution": "auto" }, @@ -303,29 +272,20 @@ optional — [full reference](docs/CONFIGURATION.md)): ``` The most common environment overrides (env always wins over the file): -`LSS_DASHBOARD_PORT`, `LSS_ENGINE` (`localstack`/`self`), `LOCALSTACK_AUTH_TOKEN`, +`LSS_DASHBOARD_PORT`, `LSS_ENGINE_PORT`, `LSS_ENGINE_DATA_DIR`, `AWS_REGION`, `LSS_ENABLE_DYNAMO_PROXY`. Complete list: [docs/CONFIGURATION.md](docs/CONFIGURATION.md#environment-variables). -The self engine's default port sits **outside 4566–4599** on purpose: a real LocalStack -install intercepts that whole range on some hosts (Docker Desktop/WSL2). `--self-engine` -cannot be combined with the LocalStack-only flags (`--external`, `--pro`, -`--localstack-token`). - -### LocalStack: managed, external, Pro - -By default LSS spins up its own container (`lss-localstack-`, services -`dynamodb,sqs,sns,s3,lambda,events`, persistence volume, local Lambda executor). To point -at an already-running instance set `mode: "external"` or pass `--external`. Recent -LocalStack images (`>= 2026.5` community, all `pro`) require an auth token: +Those three are all a second instance needs — no config file to write, nothing shared +with your dev stack: ```bash -export LOCALSTACK_AUTH_TOKEN=ls-xxxxxxxx -npx lss start # community image with token -npx lss start --pro # pro image (token required) +LSS_DASHBOARD_PORT=3250 LSS_ENGINE_PORT=14766 \ + LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start ``` -Details (`mode`, `localstackEdition`, `localstackVersion`, `localstackImage`): -[docs/CONFIGURATION.md](docs/CONFIGURATION.md). +The engine's default port sits **outside 4566–4599** on purpose: a real LocalStack +install intercepts that whole range on some hosts (Docker Desktop/WSL2), and your machine +may still have one. ## Dashboard @@ -363,7 +323,7 @@ sequenceDiagram participant Dev as Developer participant Plugin as serverless-lss
(plugin) participant Orch as Orchestrator - participant Eng as Engine
(self or LocalStack) + participant Eng as Self engine
(in-process) Dev->>Plugin: sls package Plugin->>Orch: POST /api/services/register @@ -391,7 +351,7 @@ sequenceDiagram App->>Eng: SendMessage (AWS SDK) Eng->>RT: Event batch {Records: [...]} - Note over Eng,RT: self engine: in-process dispatch
LocalStack: proxy Lambda → HTTP → invoke listener + Note over Eng,RT: in-process dispatch — no proxy Lambda, no polling RT->>H: handler(event, context) alt success H-->>RT: return @@ -402,9 +362,8 @@ sequenceDiagram end ``` -The same flow applies to DynamoDB streams, S3 notifications and EventBridge targets. -In LocalStack mode the hop goes through a generated proxy Lambda inside the container; -in self-engine mode the dispatcher calls the runtime directly — no proxy, no polling. +The same flow applies to DynamoDB streams, S3 notifications and EventBridge targets: +the dispatcher calls the runtime directly — no proxy Lambda, no polling. If you still want serverless-offline to own the ports for a service, disable the LSS runtime globally or per service with `lambdaRuntime.enabled`/`serviceRuntime`. @@ -431,7 +390,7 @@ local-serverless-stack/ - **CLI** (`bin/cli.js`): background process management (start/stop/status/logs/seed) - **Server** (`src/server/`): Express API + engine orchestration; serves the built UI -- **Engine** (`src/server/engine/`): the AWS provider behind everything — in-process **self engine** (:14566, no Docker) or managed/external **LocalStack** (:4566) +- **Engine** (`src/server/engine/`): the AWS provider behind everything — the in-process **self engine** (:14566, no Docker) - **Client** (`src/client/`): `LssClient` — the same API surface as the dashboard, from code - **Plugin** (`packages/serverless-plugin/`): auto-registration on `sls package` @@ -453,7 +412,7 @@ Granular builds: `server:build`, `ui:build`, `client:build`, `plugin:build`. npm test # unit suite (jest) npm run test:coverage # with coverage (CI gate) npm run test:watch # watch mode -npm run test:integration # boots a real orchestrator (Docker/LocalStack required) +npm run test:integration # boots a real orchestrator end to end (no Docker, no token) npm run lint # eslint npx jest tests/unit/services/config-manager.test.ts # a single suite ``` diff --git a/REVISAO-2026-07-29.md b/REVISAO-2026-07-29.md index 1bac052..1199cb4 100644 --- a/REVISAO-2026-07-29.md +++ b/REVISAO-2026-07-29.md @@ -558,6 +558,63 @@ container no meio). Lê como raio-dentro-de-chip a 16 px e como die com pinout a Também virou o favicon default do dashboard (`src/ui/public/favicon.svg`), que antes não tinha nenhum — `branding.favicon` continua sobrescrevendo em runtime. +--- + +## 5c. Terceira rodada — v2.0.0: LocalStack removido + +O critério que você definiu foi verificado com os dois exemplos rodando inteiros no self engine +(§5b), então a v2 foi executada. + +### O que saiu + +| Removido | Tamanho | +|---|---| +| `localstack-backend.ts`, `localstack-manager.ts`, `aoss-sidecar.ts`, `engine-backend.ts` | 4 módulos | +| Chaves de config | `engine`*, `mode`, `localstackPort/Endpoint/Edition/Version/Image/AuthToken`, `services`, `aossSidecar` | +| Env vars | `LSS_LOCALSTACK_*`, `LOCALSTACK_AUTH_TOKEN`, `LSS_SERVICES` | +| Flags de CLI | `--self-engine`, `--external`, `--pro`, `--localstack-token` | +| Campos de API | `health.localstack`, `config.localstack`, `config.aossSidecar`, `config.services` | +| Exemplos | `localstack-free` + `localstack-ultimate` — **760 MB** | + +\* `engine` sobrevive só para **rejeitar** um `"localstack"` herdado com uma mensagem de migração. +O mesmo vale para as flags: cada uma sai com exit 1 apontando o guia — e o guard roda **antes** do +short-circuit de "já rodando", senão uma flag velha parecia um no-op bem-sucedido. + +### O que entrou no lugar + +**A suíte de integração agora roda em qualquer lugar.** Ela sobe um orquestrador isolado no self +engine em vez de um container: **19 asserções ponta a ponta em ~20 s, sem Docker e sem token**, +incondicional local e no CI. Na v1 essa mesma suíte se pulava sempre que faltava o token do +LocalStack — ou seja, a única cobertura e2e do projeto quase nunca rodava. Foi o primeiro passo +que fiz, antes de apagar qualquer coisa. + +O `gateway-stack` (topologia raw `AWS::ApiGatewayV2::*` cross-stack) foi **preservado** em +`tests/integration/fixtures/apigw-raw/` junto com o `users-service` que ele fronteia, então essa +cobertura e2e não morreu com o exemplo. + +### Um achado que apareceu no caminho + +**A UI nunca foi type-checked.** O `src/ui/tsconfig.json` estende o tsconfig raiz, que tem +`"exclude": ["src/ui"]` — e `exclude` é **herdado**, com os caminhos resolvidos contra o arquivo +*raiz*. Resultado: o dashboard se excluía do próprio projeto e o `vue-tsc --noEmit` do gate +checava zero arquivo. Com o `exclude` resetado, apareceram **12 erros reais pré-existentes** +(renome `TreeBadgeTone` → `TBadgeTone` da TreeUI em 6 componentes, dois imports não usados, um +`TableRow` incompatível com `Record`, um `unknown` num slot de tabela e um +fallback de `ResourceOwnersResponse` sem `collections`). Todos corrigidos — o gate agora checa a +UI de verdade. + +### Estado final + +- `validate: pre-prod` completo: lint 0 erros, `tsc` nos **5** projetos (server, client, mcp, + plugin, UI), **2.422 testes com cobertura 100%**, build. +- Integração: 19 testes, sem Docker, sem token, ~20 s. +- Exemplo `self-hosted` revalidado ponta a ponta na v2: 60 recursos provisionados, pipeline + `POST /orders → DynamoDB → SQS → Lambda → S3 + EventBridge → regra → Lambda → DynamoDB` + completo, explorers respondendo sem `?region=`, **91 MB de RSS** com 4 serviços registrados. +- `GET /api/config` agora tem 22 chaves, nenhuma de LocalStack. +- Versão **2.0.0**; guia em [docs/MIGRATION-v2.md](docs/MIGRATION-v2.md); CHANGELOG com a entrada + completa. + ## 6. Respostas diretas às suas perguntas **"Todas as features estão documentadas?"** Quase. A enumeração está boa — os 47 endpoints, diff --git a/bin/cli.js b/bin/cli.js index 6d87dcd..cde2add 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -88,16 +88,12 @@ function loadConfig() { function getConfig(config) { return { serverPort: config.serverPort || 3100, - localstackPort: config.localstackPort || 4566, + enableDynamoProxy: config.enableDynamoProxy || false, dynamoProxyPort: config.dynamoProxyPort || 8000, mode: config.mode || 'managed', - localstackEdition: config.localstackEdition || 'community', - localstackVersion: config.localstackVersion || 'latest', - localstackImage: config.localstackImage, - localstackAuthToken: config.localstackAuthToken, stateDir: config.stateDir, - engine: config.engine || 'localstack', + engine: config.engine, selfEnginePort: (config.selfEngine && config.selfEngine.port) || 14566, }; } @@ -121,6 +117,22 @@ const EXPLICIT_CONFIG = (() => { return v ? path.resolve(v) : undefined; })(); +// v1 shipped a LocalStack backend selected by flags and config keys. v2 ships +// one engine, so anything left over from that world must fail loudly here +// rather than be quietly ignored. +function assertNoLocalStackFlags() { + const legacy = ['--external', '--pro', '--self-engine', '--localstack-token'] + .filter(flag => process.argv.includes(flag) || process.argv.some(a => a.startsWith(`${flag}=`))); + const cfg = loadConfig(); + if (String(cfg.engine || '').toLowerCase() === 'localstack') { + legacy.push('engine: "localstack"'); + } + if (legacy.length === 0) return; + console.error(`❌ ${legacy.join(', ')} — LSS v2 removed the LocalStack backend; the self engine is the only engine.`); + console.error(' Drop the flag and any localstack* keys from lss.config.json. See docs/MIGRATION-v2.md.'); + process.exit(1); +} + // Resolve orchestrator path - works both in development and when installed via npm function getOrchestratorPath() { // Try to find the orchestrator relative to this script @@ -143,6 +155,11 @@ function getOrchestratorPath() { } function startOrchestrator() { + // Before anything else — including the already-running short-circuit — so a + // stale v1 flag or config value always fails loudly instead of looking like + // a successful no-op. + assertNoLocalStackFlags(); + const { pidFile, logFile } = runtimePaths(); if (fs.existsSync(pidFile)) { @@ -153,11 +170,7 @@ function startOrchestrator() { const cfg = getConfig(config); console.log('✅ LSS Orchestrator already running (PID:', pid + ')'); console.log(`📊 Server: http://localhost:${cfg.serverPort}`); - if (cfg.engine === 'self') { - console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort}`); - } else { - console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort}`); - } + console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort}`); if (cfg.enableDynamoProxy) { console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`); } @@ -185,22 +198,7 @@ function startOrchestrator() { const config = loadConfig(); const cfg = getConfig(config); - // Check for flags const enableDynamoProxy = process.argv.includes('--enable-dynamo-proxy') || cfg.enableDynamoProxy; - const useExternal = process.argv.includes('--external'); - const usePro = process.argv.includes('--pro'); - const cliToken = getArgValue('--localstack-token'); - const useSelfEngine = process.argv.includes('--self-engine'); - - const engine = useSelfEngine ? 'self' : cfg.engine; - if (engine === 'self' && (useExternal || usePro || cliToken)) { - console.error('❌ --self-engine cannot be combined with --external, --pro or --localstack-token (those are LocalStack options).'); - process.exit(1); - } - - const mode = useExternal ? 'external' : cfg.mode; - const edition = usePro ? 'pro' : cfg.localstackEdition; - const authToken = cliToken || cfg.localstackAuthToken || process.env.LOCALSTACK_AUTH_TOKEN; // Build environment variables from config const env = { ...process.env }; @@ -215,40 +213,9 @@ function startOrchestrator() { if (cfg.dynamoProxyPort) { env.LSS_DYNAMO_PROXY_PORT = cfg.dynamoProxyPort; } - if (engine === 'self') { - // Self engine: not one LocalStack variable is exported. They would be dead - // weight in the child's environment, they leak "there is a LocalStack here" - // into a mode whose whole point is that there isn't, and every key exported - // this way is reported by GET /api/config as env-overridden — which greys - // it out in the dashboard's Settings tab for a value the user never set. - env.LSS_ENGINE = 'self'; - } else { - /* istanbul ignore else: getConfig() always defaults localstackPort to 4566, so the else is unreachable */ - if (cfg.localstackPort) { - env.LSS_LOCALSTACK_PORT = cfg.localstackPort; - } - /* istanbul ignore else: mode resolves to cfg.mode which getConfig() defaults to 'managed', so the else is unreachable */ - if (mode) { - env.LSS_LOCALSTACK_MODE = mode; - } - /* istanbul ignore else: edition resolves to localstackEdition which getConfig() defaults to 'community', so the else is unreachable */ - if (edition) { - env.LSS_LOCALSTACK_EDITION = edition; - } - /* istanbul ignore else: getConfig() always defaults localstackVersion to 'latest', so the else is unreachable */ - if (cfg.localstackVersion) { - env.LSS_LOCALSTACK_VERSION = cfg.localstackVersion; - } - if (cfg.localstackImage) { - env.LSS_LOCALSTACK_IMAGE = cfg.localstackImage; - } - if (authToken) { - env.LOCALSTACK_AUTH_TOKEN = authToken; - } - } // Hand the same config file to the server so its ConfigManager reads the - // identical serverPort/localstackPort/seedsDir/region/mode (not just the - // hand-translated subset above). Keeps the two config loaders in agreement. + // identical serverPort/seedsDir/region (not just the hand-translated subset + // above). Keeps the two config loaders in agreement. if (EXPLICIT_CONFIG) { env.LSS_CONFIG_PATH = EXPLICIT_CONFIG; } @@ -266,11 +233,7 @@ function startOrchestrator() { console.log('🚀 LSS Orchestrator started (PID:', child.pid + ')'); console.log(`📊 Server: http://localhost:${cfg.serverPort}`); - if (engine === 'self') { - console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort} (no Docker)`); - } else { - console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort} (mode: ${mode}, edition: ${edition})`); - } + console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort} (no Docker)`); if (enableDynamoProxy) { console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`); } @@ -365,7 +328,7 @@ function showStatus() { const cfg = getConfig(config); console.log('🟢 LSS Orchestrator: RUNNING (PID:', pid + ')'); console.log(`📊 Server: http://localhost:${cfg.serverPort}`); - console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort}`); + console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort}`); if (cfg.enableDynamoProxy) { console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`); } @@ -453,7 +416,7 @@ function printSeedRunResults(results) { for (const r of results) { if (r.skipped) { console.log(` ⚠ ${r.tableName}: skipped (${r.reason})`); - if (r.reason && r.reason.includes('does not exist in LocalStack')) { + if (r.reason && r.reason.includes('does not exist in the engine')) { missingTables++; } } else { @@ -464,7 +427,7 @@ function printSeedRunResults(results) { } // Show the user both sides of the comparison: the seed files we found, and -// the DynamoDB tables actually living in LocalStack. This is the difference +// the DynamoDB tables actually living in the engine. This is the difference // between "I didn't deploy yet" (no live tables at all) and "my seed file // name doesn't match the CFN TableName" (live tables exist, just not those). function printSeedMismatchDiagnostic({ entries, liveTables, focusTable }) { @@ -483,16 +446,16 @@ function printSeedMismatchDiagnostic({ entries, liveTables, focusTable }) { if (liveTables && liveTables.length > 0) { console.log(''); - console.log(`🗂️ Tabelas vivas no LocalStack (${liveTables.length}):`); + console.log(`🗂️ Tabelas vivas no engine (${liveTables.length}):`); for (const name of liveTables) console.log(` - ${name}`); console.log(''); console.log('💡 Os nomes dos arquivos de seed precisam bater EXATAMENTE com o `TableName` no CloudFormation.'); console.log(' Confira se há prefixo/sufixo divergente entre o arquivo e a tabela.'); } else { console.log(''); - console.log('🗂️ Nenhuma tabela viva no LocalStack ainda.'); + console.log('🗂️ Nenhuma tabela viva no engine ainda.'); console.log('💡 Provavelmente o stack ainda não foi provisionado. Tente:'); - console.log(' npx lss start # garante LocalStack rodando'); + console.log(' npx lss start # garante o orquestrador rodando'); console.log(' npx serverless deploy # cria as tabelas'); console.log(' E rode `npx lss seed` novamente.'); } @@ -584,8 +547,8 @@ async function clearSeed(tableName) { // Show the user exactly what's about to be wiped before they confirm. // Hitting the orchestrator's GET /api/seeds also implicitly proves we're - // talking to LocalStack and not AWS — the orchestrator only ever connects - // to the configured local LocalStack endpoint. + // talking to the local engine and not AWS — the orchestrator only ever + // connects to the configured local engine endpoint. let scopeDescription; try { const list = await getJson('/api/seeds'); @@ -596,11 +559,11 @@ async function clearSeed(tableName) { if (liveTargets.length === 0) { if (tableName) { - console.log(`⚠️ Nenhuma tabela "${tableName}" existente no LocalStack para limpar.`); + console.log(`⚠️ Nenhuma tabela "${tableName}" existente no engine para limpar.`); } else if (entries.length === 0) { console.log('⚠️ Nenhum arquivo de seed (*.json) encontrado no seedsDir — nada para limpar.'); } else { - console.log(`⚠️ ${entries.length} arquivo(s) de seed encontrados, mas NENHUMA das tabelas correspondentes existe no LocalStack.`); + console.log(`⚠️ ${entries.length} arquivo(s) de seed encontrados, mas NENHUMA das tabelas correspondentes existe no engine.`); } printSeedMismatchDiagnostic({ entries, liveTables, focusTable: tableName }); return; @@ -613,8 +576,8 @@ async function clearSeed(tableName) { console.log(''); console.log('⚠️ ATENÇÃO: operação destrutiva'); console.log(` Alvo: ${scopeDescription}`); - console.log(` LocalStack: http://localhost:${cfg.localstackPort}`); - console.log(' Esta ação NÃO toca em nenhuma conta AWS — apenas o LocalStack acima.'); + console.log(` Engine: http://localhost:${cfg.selfEnginePort}`); + console.log(' Esta ação NÃO toca em nenhuma conta AWS — apenas o engine local acima.'); console.log(''); } catch (e) { console.error('❌ Não consegui listar as tabelas antes de limpar:', formatError(e)); @@ -711,14 +674,13 @@ Options: Applies to start/stop/status/logs so an isolated instance can be addressed without cd-ing into its folder. --enable-dynamo-proxy Enable DynamoDB proxy on port 8000 (for start command) - --self-engine Use the in-process AWS engine instead of LocalStack (no Docker) - --external Connect to a LocalStack already running, do not spawn a container - --pro Use the LocalStack Pro image (requires LOCALSTACK_AUTH_TOKEN) - --localstack-token Pass a LOCALSTACK_AUTH_TOKEN to the container --yes, -y Skip interactive confirmation on seed:clear (use only in CI) Environment: - LOCALSTACK_AUTH_TOKEN Token forwarded to LocalStack (Pro and >=2026.5 community) + LSS_DASHBOARD_PORT Orchestrator port (overrides serverPort) + LSS_ENGINE_PORT Self engine port (overrides selfEngine.port) + LSS_ENGINE_DATA_DIR Self engine state directory (overrides selfEngine.dataDir) + AWS_REGION Default region for provisioning and the explorers Configuration: Create a lss.config.json or .lssrc file in your project root to customize: @@ -726,14 +688,10 @@ Configuration: Example lss.config.json: { "serverPort": 3100, - "localstackPort": 4566, - "mode": "managed", - "localstackEdition": "community", - "localstackVersion": "latest", + "selfEngine": { "port": 14566 }, "enableDynamoProxy": false, "dynamoProxyPort": 8000, "region": "us-east-1", - "services": ["dynamodb", "sqs", "sns", "lambda"], "persistence": true, "debug": false, "stateDir": ".lss" @@ -750,12 +708,9 @@ Configuration: orchestratorUrl: http://localhost:3100 Examples: - npx lss start # Start the orchestrator (managed LocalStack) - npx lss start --self-engine # Use the in-process engine (no Docker, port 14566) + npx lss start # Start the orchestrator + self engine (no Docker) npx lss start --enable-dynamo-proxy # Start with DynamoDB proxy enabled - npx lss start --external # Connect to an external LocalStack - npx lss start --pro # Use LocalStack Pro (token required) - LOCALSTACK_AUTH_TOKEN=xxx npx lss start # Inject a token via env var + npx lss mcp # Serve MCP tools to an AI agent on stdio npx lss stop # Stop the orchestrator npx lss status # Check status npx lss logs # View logs diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 9607938..75b414d 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -1,6 +1,6 @@ # Configuration Guide for LSS -LSS (Local Serverless Stack) supports configuration files to customize the behavior of the orchestrator, including server port, engine selection, LocalStack settings, DynamoDB proxy, and dashboard branding. +LSS (Local Serverless Stack) supports configuration files to customize the behavior of the orchestrator: ports, the in-process AWS engine, the Lambda runtime, seeds, packaging, the DynamoDB proxy and dashboard branding. ## Configuration Files @@ -17,7 +17,7 @@ The first file found will be used. Environment variables are always read afterwa ```mermaid flowchart LR A[Defaults
config-manager.ts] --> B[Config file
--config > cwd > home] - B --> C[Environment variables
LSS_*, LOCALSTACK_AUTH_TOKEN] + B --> C[Environment variables
LSS_*, AWS_REGION] C --> D[Effective config
printed on lss start] ``` @@ -30,15 +30,10 @@ Both files should contain valid JSON with the following optional properties: ```json { "serverPort": 3100, - "localstackPort": 4566, - "localstackEndpoint": "http://localhost:4566", - "mode": "managed", - "localstackEdition": "community", - "localstackVersion": "latest", + "selfEngine": { "port": 14566 }, "enableDynamoProxy": false, "dynamoProxyPort": 8000, "region": "us-east-1", - "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], "persistence": true, "debug": false, "autoPackage": false, @@ -48,7 +43,8 @@ Both files should contain valid JSON with the following optional properties: "enabled": true, "execution": "auto", "invokePortOffset": 10000, - "invokeHost": "host.docker.internal" + "lazy": true, + "idleTimeoutMs": 60000 } } ``` @@ -61,67 +57,15 @@ Both files should contain valid JSON with the following optional properties: - The Serverless Plugin connects to this server to register services - Example: `3100` -- **engine** (`"localstack"` | `"self"`, default: `"localstack"`) - - Which AWS provider backs the orchestrator: the LocalStack container, or the - in-process self engine (no Docker, no auth token). Env: `LSS_ENGINE`; CLI: - `lss start --self-engine`. The `localstack*` keys below are ignored in self - mode. See [SELF_ENGINE.md](SELF_ENGINE.md). - -- **selfEngine** (object, optional — only used when `engine` is `"self"`) +- **selfEngine** (object, optional) - `port` (default 14566, env `LSS_ENGINE_PORT`), `dataDir` (default `~/.lss/projects/-/engine`, or `/engine` when `stateDir` is set — the home fallback is scoped per project so two checkouts never share one set of tables), `account`, - `idleUnloadMs`, `memoryBudgetMb`, `fsync`, `fallbackEndpoint` (forward - unimplemented AWS calls to a LocalStack instance during migration). + `idleUnloadMs`, `memoryBudgetMb`, `fsync`, `fallbackEndpoint` (reverse-proxy + AWS operations the engine does not implement to any AWS-compatible endpoint). - Full reference: [SELF_ENGINE.md](SELF_ENGINE.md). -- **aossSidecar** (object, optional — only used on LocalStack engines) - - OpenSearch Serverless (aoss) sidecar. **No LocalStack edition provides - aoss**, so whenever the active engine is LocalStack, LSS serves the - self-engine OpenSearch emulator in-process on its own port — the aoss - control plane (CreateCollection, BatchGetCollection, ...) and the - OpenSearch data plane (`http://localhost:14567/_aoss/`) both - answer there. On the self engine the sidecar never runs: aoss is native. - - `enabled` (boolean, default `true` on LocalStack engines): set `false` to - opt out — aoss provisioning then fails with a hint pointing back here. - - `port` (number, default `14567` — one above the self engine's 14566): the - sidecar's endpoint is `http://localhost:`. - - Data persists under `~/.lss/projects/-/aoss` (or `/aoss` when `stateDir` is - set), independent of the LocalStack container's lifecycle. - - Example — move the sidecar off a busy port: - ```jsonc - "aossSidecar": { "port": 24567 } - ``` - -- **localstackPort** (number, default: 4566) - - Port where LocalStack container will expose its API - - Example: `4566` - -- **localstackEndpoint** (string, optional) - - Custom endpoint for LocalStack - - Example: `"http://localhost:4566"` or `"http://192.168.1.100:4566"` - -- **mode** (`"managed"` | `"external"`, default: `"managed"`) - - `managed`: LSS starts and stops a LocalStack container via Docker. - - `external`: LSS connects to a LocalStack instance you started yourself and never touches Docker. - -- **localstackEdition** (`"community"` | `"pro"`, default: `"community"`) - - Which LocalStack image to pull (community is free; pro requires a valid auth token). - - Ignored when `localstackImage` is set. - -- **localstackVersion** (string, default: `"latest"`) - - Tag appended to the resolved image (e.g. `4.0`, `stable`, `2026.4`). - - Ignored when `localstackImage` is set. - -- **localstackImage** (string, optional) - - Full image override (e.g. `"my-registry/localstack:custom"`). Takes precedence over edition + version. - -- **localstackAuthToken** (string, optional) - - Forwarded as `LOCALSTACK_AUTH_TOKEN` inside the container. - - Required for `pro` edition and for community images `>= 2026.5`. - - Prefer the `LOCALSTACK_AUTH_TOKEN` env var over writing the token to a config file. - - **enableDynamoProxy** (boolean, default: false) - Enable a proxy for DynamoDB on a separate port - Useful for tools that expect DynamoDB on port 8000 @@ -138,17 +82,9 @@ Both files should contain valid JSON with the following optional properties: trailing `region` argument) to inspect resources provisioned elsewhere - Example: `"us-east-1"` -- **services** (array, default: ["dynamodb", "sqs", "sns", "s3", "lambda", "events"]) - - AWS services to enable in LocalStack (`SERVICES` env of the container). - Ignored by the self engine, which always serves its full set — including - OpenSearch Serverless (`aoss`), which community LocalStack images don't - provide. - - Example: `["dynamodb", "sqs", "sns", "lambda", "s3", "secretsmanager"]` - - **persistence** (boolean, default: true) - Whether engine data survives a restart. - - LocalStack engine: sets `PERSISTENCE` on the container. - - Self engine: `false` swaps the file-backed store for an **in-memory** one — no + - `false` swaps the file-backed store for an **in-memory** one — no `dataDir` is created, no catalog, WAL or blob is written, and every boot starts from an empty engine. That is the mode to use for an automated test run that needs a guaranteed clean slate and no leftover files. (The residency knobs — @@ -157,7 +93,7 @@ Both files should contain valid JSON with the following optional properties: - Example: `true` - **debug** (boolean, default: false) - - Enable debug mode for LocalStack + - Verbose orchestrator logging. - Example: `false` - **seedsDir** (string, default: `"./seeds"`) @@ -177,7 +113,7 @@ Both files should contain valid JSON with the following optional properties: instance needs: ```bash LSS_DASHBOARD_PORT=3250 LSS_ENGINE_PORT=14766 \ - LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start --self-engine + LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start ``` - Reported as an env override by `GET /api/config`, like every other `LSS_*` var. @@ -186,7 +122,7 @@ Both files should contain valid JSON with the following optional properties: relative to the working directory. Setting it isolates an instance so `lss stop --config ` targets it and not your dev instance — useful for e2e stacks running next to a normal one. - - It is also where the engine's `dataDir` and the aoss sidecar's data dir land. + - It is also where the engine's `dataDir` lands. Without it they fall back to a **per-project** directory under `~/.lss/projects/-/`, derived from the absolute project root — so two checkouts of the same repo, or two examples, never share state. @@ -240,7 +176,7 @@ Both files should contain valid JSON with the following optional properties: } ``` -- **lambdaRuntime** (object, default: `{ "enabled": true, "execution": "auto", "invokePortOffset": 10000, "invokeHost": "host.docker.internal" }`) +- **lambdaRuntime** (object, default: `{ "enabled": true, "execution": "auto", "invokePortOffset": 10000, "invokeHost": "127.0.0.1", "lazy": true, "idleTimeoutMs": 60000 }`) - Controls the Lambda runtime + API emulation (the serverless-offline replacement). When a service registers, LSS starts a runtime worker for its functions, binds an API Gateway emulator on the service's `apiPort` (30xx) and an AWS Lambda Invoke API @@ -257,14 +193,10 @@ Both files should contain valid JSON with the following optional properties: - `invokePortOffset` (number, default `10000`): when a service declares only an `apiPort`, its invoke port is derived as `apiPort + invokePortOffset` (e.g. 3010 → 13010). - - `invokeHost` (string, default: `"host.docker.internal"` on the LocalStack - engine, `"127.0.0.1"` on the self engine — nothing runs in Docker there): - hostname the LocalStack Lambda proxy functions use when calling back into the - service invoke listener (`http://{invokeHost}:{invokePort}`). In - Docker-in-Docker/devcontainer setups, `host.docker.internal` may point at - Docker Desktop instead of the devcontainer; set this to the Docker network - gateway reachable from the LocalStack container (for example `"172.19.0.1"`). - Only relevant on the LocalStack engine. + - `invokeHost` (string, default `"127.0.0.1"` — everything runs in this process): + hostname used to build the invoke URL a service's event proxies call back on + (`http://{invokeHost}:{invokePort}`). Override only when the orchestrator must + be reachable under another name. - `lazy` (boolean, default `true`): fork a service's runtime worker on its **first invocation** instead of at registration. A worker is a Node process costing ~48 MB resident, so a 40-service monorepo paid ~1.9 GB before a single handler ran; @@ -423,7 +355,7 @@ Custom ports — remember to point the plugin at the new server port too: ```jsonc // lss.config.json -{ "serverPort": 3200, "localstackPort": 4600, "localstackEndpoint": "http://localhost:4600" } +{ "serverPort": 3200, "selfEngine": { "port": 14766 } } ``` ```yaml @@ -444,17 +376,9 @@ Environment variables can be used instead of — or to override — a configurat - `LSS_CONFIG` - Explicit config file path for the CLI (equivalent to `--config `; also honored by `LssClient`) - `LSS_CONFIG_PATH` - Explicit config file path for the server (the CLI sets it from `--config` when spawning) - `PORT` or `LSS_DASHBOARD_PORT` - Server port -- `LSS_LOCALSTACK_PORT` - LocalStack port -- `LSS_LOCALSTACK_ENDPOINT` - LocalStack endpoint -- `LSS_LOCALSTACK_MODE` - `managed` or `external` -- `LSS_LOCALSTACK_EDITION` - `community` or `pro` -- `LSS_LOCALSTACK_VERSION` - Image tag (e.g. `latest`, `4.0`) -- `LSS_LOCALSTACK_IMAGE` - Full image override -- `LOCALSTACK_AUTH_TOKEN` - Forwarded into the container - `LSS_ENABLE_DYNAMO_PROXY` - Enable DynamoDB proxy (true/false or 1/0; the legacy unprefixed `ENABLE_DYNAMO_PROXY` is still honored as a fallback, deprecated) - `LSS_DYNAMO_PROXY_PORT` - DynamoDB proxy port - `AWS_REGION` - AWS region -- `LSS_SERVICES` - Services (comma-separated) - `LSS_PERSISTENCE` - Persistence (true/false or 1/0) - `LSS_DEBUG` - Debug mode (true/false or 1/0) - `LSS_AUTO_PACKAGE` - Run package command when template is missing (true/false or 1/0) @@ -463,11 +387,10 @@ Environment variables can be used instead of — or to override — a configurat - `LSS_LAMBDA_RUNTIME` - Enable/disable Lambda runtime + API emulation (true/false or 1/0) - `LSS_LAMBDA_EXECUTION` - `auto`, `artifact`, or `source` - `LSS_LAMBDA_WATCH` - Enable/disable runtime source watching (true/false or 1/0) -- `LSS_INVOKE_HOST` - Override `lambdaRuntime.invokeHost` for LocalStack proxy callbacks +- `LSS_INVOKE_HOST` - Override `lambdaRuntime.invokeHost` - `LSS_SEEDS_DIR` - Directory with DynamoDB seed files -- `LSS_ENGINE` - AWS engine: `localstack` or `self` - `LSS_ENGINE_PORT` - Self engine port (default: 14566) -- `LOCALSTACK_ACCESS_KEY_ID` / `LOCALSTACK_SECRET_ACCESS_KEY` - Credentials the orchestrator's SDK clients present to the engine (default: `test`/`test`); set them when an external LocalStack validates credentials +- `LSS_ENGINE_DATA_DIR` - Self engine state directory (overrides `selfEngine.dataDir`) ### LssClient environment variables @@ -488,8 +411,8 @@ export LSS_DASHBOARD_PORT=3200 # Enable DynamoDB proxy export LSS_ENABLE_DYNAMO_PROXY=true -# Set LocalStack port -export LSS_LOCALSTACK_PORT=4600 +# Move the engine off its default port +export LSS_ENGINE_PORT=14766 # Start the orchestrator npx lss start @@ -501,39 +424,7 @@ Configuration is resolved in this order (later values override earlier ones): 1. Default values 2. Configuration file (`lss.config.json` or `.lssrc`) -3. Environment variables (so secrets like `LOCALSTACK_AUTH_TOKEN` can be injected without touching the file) - -## LocalStack: managed vs external - -`mode: "managed"` is the default and works for most setups — LSS will `docker run` and `docker stop` the container for you. - -Use `mode: "external"` when you want to keep an already-running LocalStack across multiple `lss start` invocations, or when LocalStack is running in another container/host you own: - -```json -{ - "mode": "external", - "localstackEndpoint": "http://localhost:4566" -} -``` - -In external mode, `lss start` only health-checks the endpoint and `lss stop` leaves the container running. - -## LocalStack Pro and auth tokens - -The `localstack/localstack-pro` image and recent `localstack/localstack` images (`>= 2026.5`) require `LOCALSTACK_AUTH_TOKEN`. - -Two ways to provide it: - -```bash -# 1. Environment variable (preferred — never commit the token) -export LOCALSTACK_AUTH_TOKEN=ls-xxxxxxxx -npx lss start --pro - -# 2. CLI flag (handy for one-off runs) -npx lss start --pro --localstack-token ls-xxxxxxxx -``` - -If `localstackEdition` is `pro` and no token is found, the orchestrator fails fast with a clear message. For `community`, it just warns and tries anyway (older images still work without a token). +3. Environment variables (so an instance can be retargeted — ports, engine data dir, region — without touching the file) ## Getting Started @@ -568,21 +459,20 @@ The HTTP surface behind it: | Endpoint | What it does | |---|---| -| `GET /api/config` | Full public-safe snapshot: engine kind + endpoint, LocalStack block, self-engine block, aoss sidecar, lambda runtime, packaging, branding, `configPath`/`projectRoot`, and `envOverrides` (keys currently masked by env vars). Secret **values** never appear: the auth token collapses to `hasAuthToken`, `packageEnv` maps collapse to key names, the `secrets` seed map collapses to a count. | +| `GET /api/config` | Full public-safe snapshot: engine kind + endpoint, self-engine block, lambda runtime (with the resolved residency policy), packaging, branding, `configPath`/`projectRoot`, and `envOverrides` (keys currently masked by env vars). Secret **values** never appear: `packageEnv` maps collapse to key names and the `secrets` seed map collapses to a count. | | `PUT /api/config` | Persist a partial patch. Scalar/array keys replace; `null` deletes the key (the default returns). Object blocks (`lambdaRuntime`, `selfEngine`, `aossSidecar`, `branding`, …) merge **one level deep** — a partial edit never drops sibling settings like `branding.logo` — and a `null` subkey deletes just that subkey. Nested keys are validated too (`selfEngine.port` must be a port, `lambdaRuntime.execution` must be a known mode, unknown subkeys are rejected). Invalid patches answer `400` with every problem listed in `details` and nothing touches the file. | | `POST /api/config/reload` | Re-read the config file from disk after a hand edit, without restarting the orchestrator. A file that no longer parses answers `400` and the working in-memory config stays untouched. | -| `GET /api/config/ports` | Every local port the stack exposes: orchestrator, active engine (LocalStack edge or self engine), aoss sidecar, DynamoDB proxy, plus each registered service's HTTP API and Lambda invoke listeners. Shown on the dashboard Overview. | +| `GET /api/config/ports` | Every local port the stack exposes: orchestrator, engine, DynamoDB proxy, plus each registered service's HTTP API and Lambda invoke listeners. Shown on the dashboard Overview. | -Two keys are **never editable via the API**: `localstackAuthToken` (use the -`LOCALSTACK_AUTH_TOKEN` env var — the token must not transit the dashboard) and `secrets` -(seed material — edit the file directly). +One key is **never editable via the API**: `secrets` (seed material — edit the file +directly). Both `PUT` and `reload` classify what changed: - **Lazily-consumed keys** (`seedsDir`, `autoPackage`, packaging settings, `branding`, `lambdaRuntime`/`serviceRuntime` for the *next* registration) take effect immediately. -- **Boot-materialized keys** (ports, `engine`, LocalStack mode/image, `persistence`, - `region`, `stateDir`, `selfEngine`, `aossSidecar`) come back in `restartRequired` — the +- **Boot-materialized keys** (ports, `persistence`, `region`, `stateDir`, `selfEngine`) + come back in `restartRequired` — the running process keeps the old value until `lss stop && lss start` (the `restart (rebuild local)` VSCode tasks chain build + stop + start for the examples). - Patch keys currently masked by an env var come back in `envOverridden`: the file was @@ -615,7 +505,7 @@ If a port is already in use, change it in the configuration file: ```json { "serverPort": 3200, - "localstackPort": 4600 + "selfEngine": { "port": 14766 } } ``` diff --git a/docs/FEATURES.md b/docs/FEATURES.md index aeae644..3e37d15 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -2,7 +2,7 @@ This is the canonical inventory of what `local-serverless-stack` (LSS) promises. It doubles as the checklist for the integration suite (`tests/integration/features.test.ts`), which boots a real isolated -LSS + LocalStack and asserts each capability against the live HTTP API. +LSS instance on the self engine — no Docker, no auth token — and asserts each capability against the live HTTP API. > **⚠️ Keep this document current.** Every new capability MUST be recorded here as part of shipping > the change — never after the fact. Keep it in sync with the **Features** section of @@ -19,7 +19,7 @@ by the live integration suite (`npm run test:integration`). | Feature | Promise | Asserted by | |---|---|---| -| `lss start` | Starts the orchestrator (managed LocalStack by default) in the background; writes a PID file and logs. | integration (`features.test.ts` boots via `lss start --config`) + unit (`cli`) | +| `lss start` | Starts the orchestrator + engine in the background; writes a PID file and logs. | integration (`features.test.ts` boots via `lss start --config`) + unit (`cli`) | | `lss stop` | Gracefully stops the orchestrator addressed by the active config. | integration (`features.test.ts` teardown) + unit (`cli`) | | `lss status` | Reports RUNNING/NOT RUNNING + ports for the addressed instance. | unit (`cli`) | | `lss logs` | Prints the tail of the instance log. | unit (`cli`) | @@ -27,7 +27,7 @@ by the live integration suite (`npm run test:integration`). | `lss seed [table]` | Applies `{table}.json` seed files from `seedsDir` into DynamoDB (all matching tables, or one). | unit (`cli-seed`) + integration | | `lss seed:clear [table]` | Deletes seeded items after an interactive `confirmar` prompt (or `--yes`); refuses any non-local endpoint. | unit (`cli-seed`, `seed-manager-guard`) | | `--config ` | Loads config from an explicit file, taking precedence over the cwd/home search; also via `LSS_CONFIG`. | unit (`cli`) + integration | -| `--external` / `--pro` / `--localstack-token` | Connect to an external LocalStack / use the Pro image / pass an auth token. | unit (`cli`) | +| v1 flag guard | `--self-engine` / `--external` / `--pro` / `--localstack-token`, and `engine: "localstack"` in a config file, exit 1 naming `docs/MIGRATION-v2.md` — a stale script fails visibly instead of quietly starting the wrong thing. | unit (`cli`, `config-manager`) | ## 2. Configuration & instance isolation @@ -38,18 +38,17 @@ by the live integration suite (`npm run test:integration`). | `LSS_ENGINE_DATA_DIR` | Points the self engine's state at an explicit directory from the environment. With `LSS_DASHBOARD_PORT` and `LSS_ENGINE_PORT` it is everything a second instance needs — no config file to write, nothing shared with the dev stack. | unit (`config-manager`) | | `LSS_CONFIG_PATH` passthrough | The CLI hands the chosen config to the spawned server so both loaders agree on ports/seedsDir/region/mode. | unit (`config-manager`) + integration | | Per-project state, no `stateDir` | With no `stateDir`, the engine `dataDir`, the aoss sidecar data dir and the artifact-extraction dir all fall back to `~/.lss/projects/-/…` instead of one shared path — two checkouts (or two examples) never read each other's tables, and re-registering in one no longer `rm -rf`s the code another instance's worker is running from. | unit (`config-manager`, `cache-manager`) | -| No LocalStack env in self mode | `lss start` with `engine: "self"` exports **no** `LSS_LOCALSTACK_*` / `LOCALSTACK_AUTH_TOKEN` to the orchestrator (and therefore to every forked worker). Besides the leak, each exported key was reported by `GET /api/config` as env-overridden, greying it out in the Settings tab for a value the user never set. | unit (`cli`) | -| Managed vs external mode | `mode: managed` runs a LocalStack container; `external` connects to a running one. | unit (`config-manager`) | +| No LocalStack env | `lss start` exports **no** `LSS_LOCALSTACK_*` / `LOCALSTACK_AUTH_TOKEN` to the orchestrator (and therefore to every forked worker). Each key exported this way was also reported by `GET /api/config` as env-overridden, greying out a Settings field for a value the user never set. | unit (`cli`) | | Edition / version / image / services / persistence / region | All configurable; sensible defaults (community/latest, us-east-1, dynamodb+sqs+sns+s3+lambda+events). | unit (`config-manager`) | | `GET /api/config` | Public-safe full config snapshot for the UI: engine kind/endpoint, self-engine + aoss sidecar + lambda-runtime blocks, packaging, `envOverrides` (keys masked by env vars). Secret values never appear — auth token → `hasAuthToken`, `packageEnv` → key names, `secrets` → count. | unit (`routes/config`) + integration | -| `PUT /api/config` | Edit the config from the dashboard Settings tab: writes only the patched keys into the loaded config file (creating `lss.config.json` when none is loaded), `null` deletes, object blocks merge one level deep; hot-reloads and reports `restartRequired` (boot-materialized keys) + `envOverridden` (file value masked by env). `localstackAuthToken`/`secrets` are rejected. | unit (`config-manager`, `routes/config`) | +| `PUT /api/config` | Edit the config from the dashboard Settings tab: writes only the patched keys into the loaded config file (creating `lss.config.json` when none is loaded), `null` deletes, object blocks merge one level deep; hot-reloads and reports `restartRequired` (boot-materialized keys) + `envOverridden` (file value masked by env). `secrets` is rejected. | unit (`config-manager`, `routes/config`) | | `POST /api/config/reload` | Re-read the config file from disk after a hand edit, without restarting; same `restartRequired` classification. | unit (`config-manager`, `routes/config`) | | `GET /api/config/ports` | Every local port the stack exposes (orchestrator, active engine, aoss sidecar, DynamoDB proxy, per-service HTTP API + invoke listeners) — backs the Overview "Exposed ports" card. | unit (`routes/config`) | ## 3. Resource provisioning (from CloudFormation) LSS parses the CloudFormation template produced by `serverless package` and provisions the resources in -LocalStack. `autoPackage` can run the packaging command on demand when the template is missing. +the engine. `autoPackage` can run the packaging command on demand when the template is missing. | Resource | Promise | Asserted by | |---|---|---| @@ -57,9 +56,9 @@ LocalStack. `autoPackage` can run the packaging command on demand when the templ | SQS queues | Created (incl. FIFO), with visibility timeout / retention, and `RedrivePolicy` (dead-letter queue + `maxReceiveCount`) — the `deadLetterTargetArn` intrinsic is resolved from the template, so the DLQ may be declared after the queue that points at it; a policy added to an existing queue is applied with `SetQueueAttributes`. | unit (`cloudformation-parser`, `resource-provisioner`) + integration | | SNS topics | Created and discoverable. | unit + integration | | S3 buckets | Created with versioning, `s3:ObjectCreated:*` notifications (prefix/suffix filters) and `CorsConfiguration` — `CorsRules[]` (`AllowedOrigins`/`AllowedMethods`/`AllowedHeaders`, `ExposedHeaders` or the wire spelling `ExposeHeaders`, `MaxAge` or `MaxAgeSeconds` with a literal `0` preserved, `Id`; a rule declaring no origins or no methods is skipped, as AWS requires both) applied with `PutBucketCors` when the bucket is created, so a browser preflight succeeds on the first boot with no bootstrap step. | unit (`cloudformation-parser`, `resource-provisioner`, `engine/wire-s3-cors-cfn`) + integration | -| Lambda event source mappings | SQS→Lambda and DynamoDB Stream→Lambda wired via LocalStack. | unit (`resource-provisioner`) + integration | -| EventBridge buses & rules | `AWS::Events::EventBus` created in LocalStack; `AWS::Events::Rule` (pattern or schedule) wired to Lambda targets through the same proxy → invoke-API model; `AWS::Events::Archive` skipped with a warning (LocalStack mocks it). | unit (`cloudformation-parser`, `resource-provisioner`) | -| OpenSearch Serverless collections | `AWS::OpenSearchServerless::Collection` created via the `aoss` control plane (idempotent on `ConflictException`); `SecurityPolicy`/`AccessPolicy`/`VpcEndpoint` accepted and skipped with a warning (nothing enforces them locally); on engines without an aoss provider (community LocalStack) the failure names the self engine as the fix. | unit (`cloudformation-parser`, `resource-provisioner`) | +| Lambda event source mappings | SQS→Lambda and DynamoDB Stream→Lambda wired through the engine's in-process dispatch. | unit (`resource-provisioner`) + integration | +| EventBridge buses & rules | `AWS::Events::EventBus` created on the engine; `AWS::Events::Rule` (pattern or schedule) wired to Lambda targets; `AWS::Events::Archive` skipped with a warning (never listed or replayable). | unit (`cloudformation-parser`, `resource-provisioner`) | +| OpenSearch Serverless collections | `AWS::OpenSearchServerless::Collection` created via the `aoss` control plane (idempotent on `ConflictException`); `SecurityPolicy`/`AccessPolicy`/`VpcEndpoint` accepted and skipped with a warning (nothing enforces them locally). | unit (`cloudformation-parser`, `resource-provisioner`) | | Secrets Manager secrets | `AWS::SecretsManager::Secret` created at registration — `SecretString` verbatim, or `GenerateSecretString` expanded through the engine's `GetRandomPassword` with the AWS defaults (`PasswordLength` 32, `RequireEachIncludedType` true) and injected into `SecretStringTemplate` at `GenerateStringKey` when both are present — carrying `Description`/`KmsKeyId`/`Tags`. Idempotent (an existing active secret is skipped, never clobbered) and non-fatal. | unit (`cloudformation-parser`, `resource-provisioner`, `secret-value`) | | Lambda proxies | Generated proxy functions forward events to the service's Lambda Invoke API endpoint (the LSS invoke listener, contract-compatible with serverless-offline's `lambdaPort`). | unit (`resource-provisioner`) | | `GET /api/resources` / `…/owners` | List provisioned resources (tables/queues/topics/buckets/collections) and map them to owning services. | unit (`routes/resources`) + integration | @@ -123,15 +122,14 @@ non-fatally (a failure warns, boot continues). Asserted by: unit (`seed-manager` ## 9. DynamoDB proxy (dev) Optional reverse proxy (`enableDynamoProxy` / `dynamoProxyPort`, default 8000) forwarding to the active AWS -engine (LocalStack, or the self engine when `engine: "self"`), for tools that expect DynamoDB on the standard +engine, for tools that expect DynamoDB on the standard port. Asserted by: unit (`dev/dynamo-proxy`). ## 10. Health & dashboard `GET /api/health` reports orchestrator + engine + dynamo-proxy status. Liveness of the **active** engine -(LocalStack or self) is `engineRunning`; the older `localstack` field is a deprecated alias for it, kept for -existing clients — it says "localstack" even when the self engine is what is running. `engine.kind` tells the -two apart, and the dashboard reads it so no screen says "LocalStack" on a self-engine stack. +is `engineRunning`; `engine.kind` is always `"self"`, and `engine.services` lists what the engine answers for. +(v1's `localstack` boolean is gone — see [MIGRATION-v2.md](MIGRATION-v2.md).) Any `/api/*` path no router claims answers **404 with a JSON body**, not the SPA's `200 text/html` — a mistyped API path used to read as success to curl, to the `LssClient` and to any test asserting on the response. The Vue dashboard @@ -160,7 +158,7 @@ Everything the CLI/orchestrator exposes, importable for Jest e2e at runtime inst `import { LssClient } from 'local-serverless-stack'`. The data-plane (`seeds`, `queues`, `dynamo`, `buckets`, `resources`, `services`, `lambdas`, `apis`, `config`, `health`) is HTTP against the running orchestrator; `lifecycle` (`start`/`stop`/`status`/`logs`) shells out to `bin/cli.js`, and `lifecycle.waitUntilReady()` polls `/api/health` -until LocalStack is up. The constructor resolves the target from options → env (`LSS_CONFIG`, `LSS_BASE_URL`, +until the engine is serving. The constructor resolves the target from options → env (`LSS_CONFIG`, `LSS_BASE_URL`, `LSS_SERVER_PORT`, `AWS_REGION`) → config file, so `new LssClient()` works purely from the environment; options also include `timeoutMs` (HTTP timeout per request, default 15000 — raise it for long `awaitIdle` waits). Shipped as a self-contained CommonJS build (`dist/client`, package `main`/`exports`). Asserted by: unit (`client/*`) + @@ -179,7 +177,7 @@ LSS registers every function and HTTP route from the `sls package` artifacts (`cloudformation-template-update-stack.json` + `serverless-state.json`), runs handlers in per-service worker processes, and binds two listeners per service: an API Gateway emulator on the service's `apiPort` (30xx) and an AWS Lambda Invoke API on its `invokePort` (130xx) — -so monorepo callers and the LocalStack event proxies keep their ports and contracts with no +so monorepo callers keep their ports and contracts with no serverless-offline process running. See `docs/PRD_API_LAMBDA_EMULATION.md` for the full design. | Feature | Promise | Asserted by | @@ -188,7 +186,7 @@ serverless-offline process running. See `docs/PRD_API_LAMBDA_EMULATION.md` for t | Lambda runtime workers | One worker per service loads handlers lazily (warm starts), applies function env/timeout/context, captures per-invocation logs, restarts on crash. | unit (`api-gateway-events` helpers) + integration | | Lazy workers, idle unload and a warm ceiling | A worker is a Node process costing ~48 MB resident, and LSS is a development stack — a handler only needs to be resident while it is being used. `lambdaRuntime.lazy` (default **true**) forks on the first invocation instead of at registration; `idleTimeoutMs` (default **60000**) unloads a worker that has served nothing for a minute; `maxWarmWorkers` (default: one per GB of RAM, clamped 2..12) caps how many may be resident at once, evicting the least-recently-invoked. Together they make host memory a function of the services *in flight*, not the services *registered*. Handler resolution (and artifact extraction) still runs at registration, so broken packaging still fails there, and an in-flight invocation is never interrupted. Measured on 40 services / 400 lambdas / 400 tables: **2.0 GB → 128 MB** at rest, 329 MB right after invoking all 40 with a ceiling of 4, back to 132 MB once idle — next request still 23 ms. `GET /api/services` reports `runtimeWarm`, `GET /api/lambdas` reports `warm`; `status` stays `online` either way, because the service serves an invoke regardless. | unit (`config-manager`, `routes/lambdas`, `routes/services`) | | Execution modes | `artifact` (extracted `sls package` zip — TS/JS uniform), `source` (direct require/import; TS uses Node native type stripping when available, then `esbuild-register`/`tsx`/`ts-node`), `auto` picks artifact when present. | unit (`config-manager`) + integration | -| Invoke API (130xx) | `POST /2015-03-31/functions/{name}/invocations` with `X-Amz-Invocation-Type` (RequestResponse 200 / Event 202 / DryRun 204) and `X-Amz-Function-Error` — same contract the LocalStack event proxies already call. | integration | +| Invoke API (130xx) | `POST /2015-03-31/functions/{name}/invocations` with `X-Amz-Invocation-Type` (RequestResponse 200 / Event 202 / DryRun 204) and `X-Amz-Function-Error` — the same contract a monorepo's existing callers already use. | integration | | Gateway proxy (30xx) | Multi-port routing (literal > `{param}` > `{proxy+}` > `$default`; exact method > ANY), API Gateway payload v1/v2 events, v1 malformed → 502, v2 inferred responses, CORS preflight, `port-conflict` status instead of failing registration. | unit (`api-gateway-events`) + integration | | Lambda authorizers | REST `token`/`request` (payload 1.0) and HTTP API `request` (payload 1.0/2.0, `enableSimpleResponses`), identity-source extraction (missing → 401), TTL cache + `POST /api/apis/authorizer-cache/clear`, cross-service resolution by ARN through the global registry. | unit (`authorizer-service`) + integration | | Raw `AWS::ApiGatewayV2::*` routes | `::Api`/`::Route`/`::Integration`/`::Authorizer` (+ the advisory `AWS::Lambda::Permission` grant) declared under CFN `resources:` register into the same route registry `httpApi:` events feed, whether they hang off their own `::Api` or the framework's `HttpApi`. `Target` (`integrations/`, `Fn::Join`, `!Sub 'integrations/${Id}'`), `IntegrationUri`/`AuthorizerUri` (literal ARN, `Fn::GetAtt`, `Fn::Sub` incl. `${Id.Arn}`, `Fn::Join`, `Fn::ImportValue`, and the API Gateway *invocation-URI* wrapper `arn:aws:apigateway:…:lambda:path/2015-03-31/functions//invocations`), pseudo-parameters via `Ref` **and** `Fn::Sub`, and `Permission.FunctionName` as `{Ref}`/ARN/bare name (matched by name **or** ARN) all reduce. De-duplicated against serverless-state by `(METHOD, normalized path)` — state wins. | unit (`cloudformation-parser`, `raw-api-assembler`, `raw-api-serverless-idiom`, `raw-api-cross-stack`) + integration | @@ -214,19 +212,19 @@ their description so a client can surface that before a human approves. Failures configured; `.mcp.json` (project-scoped) plus the client's own toggle are the on/off switch. Full guide: [MCP.md](MCP.md). Asserted by: unit (`mcp/protocol`, `mcp/tools`, `mcp/http`, `mcp/server`, `cli`). -## 13. Self engine (in-process AWS emulator — LocalStack replacement) +## 13. Self engine (the in-process AWS emulator) Opt-in via `engine: "self"` / `lss start --self-engine`: the orchestrator serves the AWS wire API itself on one port (default 14566) — no Docker, no auth token. The provisioner, explorers, seeds and application SDKs work unchanged (the endpoint is the seam); events are delivered in-process to the LSS Lambda runtime. Coverage matrix and storage model: `docs/SELF_ENGINE.md`; design: -`docs/PRD_SELF_ENGINE.md`. Status: v1 — the differential (self vs LocalStack) integration suite is +`docs/PRD_SELF_ENGINE.md`. Status: the only engine as of v2 — the integration suite is the next milestone and rows below will gain integration assertions with it. | Feature | Promise | Asserted by | |---|---|---| -| Engine selection | `engine`/`selfEngine` config keys, `LSS_ENGINE`/`LSS_ENGINE_PORT` env, `--self-engine` CLI (rejected combined with `--external`/`--pro`/`--localstack-token`); LocalStack remains the default. | unit (`config-manager`, `cli`) | -| Wire front door | SigV4-scope/X-Amz-Target/path routing on one port; per-protocol error shapes (`__type`, Query XML, S3 XML with body-less HEAD, Lambda + `x-amzn-ErrorType`); `x-amzn-query-error` SQS compat header; aws-chunked PutObject decoding; `/_localstack/health` alias; `fallbackEndpoint` verbatim reverse proxy for anything unimplemented. | unit (`engine/http`) | +| Engine configuration | `selfEngine` config block; `LSS_ENGINE_PORT` / `LSS_ENGINE_DATA_DIR` env overrides — with `LSS_DASHBOARD_PORT`, everything a second instance needs without writing a config file. | unit (`config-manager`, `cli`) | +| Wire front door | SigV4-scope/X-Amz-Target/path routing on one port; per-protocol error shapes (`__type`, Query XML, S3 XML with body-less HEAD, Lambda + `x-amzn-ErrorType`); `x-amzn-query-error` SQS compat header; aws-chunked PutObject decoding; `fallbackEndpoint` verbatim reverse proxy for anything unimplemented. | unit (`engine/http`) | | Storage & footprint | JSONL snapshot + WAL per table (torn-tail-safe replay, compaction), atomic JSON catalogs, content-addressed S3 blobs (never in heap), hydrate-on-first-touch + idle dehydrate + `memoryBudgetMb` LRU, debounced flushes with opt-in fsync. | unit (`engine/store`) | | DynamoDB emulation | Full expression language (KeyCondition/Condition/Filter/Update/Projection, decimal-exact `N` arithmetic), GSI/LSI with projection + sparse semantics, Limit-before-filter parity, LEK paging, streams records, lazy TTL, `TransactWriteItems`/`TransactGetItems` (all-or-nothing, `CancellationReasons`, `ClientRequestToken` idempotency, stream records for committed writes only), AWS error names the provisioner relies on. | unit (`engine/dynamodb`, `engine/dynamodb/transactions`) | | SQS emulation | Queues (FIFO groups/dedup), event-driven long poll, visibility redelivery, **queue-level redrive** (`RedrivePolicy` → DLQ once `ApproximateReceiveCount` exceeds `maxReceiveCount`, preserving `MessageId`/body/MD5s and releasing the FIFO `MessageGroupId`), live counters for QueueInspector, MD5 digests, CreateQueue idempotency duality. | unit (`engine/sqs`, `wire-sqs-redrive`) | @@ -243,8 +241,9 @@ the next milestone and rows below will gain integration assertions with it. ### How the integration suite boots `tests/integration/features.test.ts` uses an isolated config fixture -(`tests/integration/fixtures/lss.integration.config.json`: distinct ports, its own `stateDir`, managed mode, -`autoPackage`, token from `LOCALSTACK_AUTH_TOKEN`), runs `npx lss start --config `, registers -the `tests/integration/fixtures/sample-microservice` rig, asserts the rows above via the HTTP API, then `npx lss stop --config ` -and removes the scoped LocalStack container/volume. It runs locally and in a CI job gated on the -`LOCALSTACK_AUTH_TOKEN` secret (community LocalStack images ≥ 2026.5 require a token). +(`tests/integration/fixtures/lss.integration.config.json`: distinct ports, its own `stateDir`, +`persistence: false`, `autoPackage`), runs `npx lss start --config `, registers +the `tests/integration/fixtures/sample-microservice` rig, asserts the rows above via the HTTP API, then +`npx lss stop --config ` and removes the state dir — there is no container or volume to reap. +It runs **unconditionally**, locally and in CI: no Docker, no secret, ~20 seconds. (Under v1 the same +suite skipped itself whenever the LocalStack auth token was absent, which was most of the time.) diff --git a/docs/MIGRATION-v2.md b/docs/MIGRATION-v2.md new file mode 100644 index 0000000..2d30ce6 --- /dev/null +++ b/docs/MIGRATION-v2.md @@ -0,0 +1,157 @@ +# Migrating to LSS v2 + +**v2 removes the LocalStack backend.** The self engine — the in-process AWS +emulator LSS has shipped since v0.10 — is now the only engine. No Docker, no +container image, no `LOCALSTACK_AUTH_TOKEN`, no Pro plan. + +This is not a deprecation: the code is gone. A configuration that still asks for +LocalStack fails at boot with a message pointing here, rather than silently +running against something you did not ask for. + +--- + +## Why + +The self engine was already the default recommendation and, as of v0.18, it ran +**every capability both shipped LocalStack examples exercised** — REST and HTTP +API routes, Lambda authorizers (including cross-service ones), DynamoDB with +composite keys / GSIs / streams / seeds, SQS with DLQ redrive, EventBridge buses +and pattern rules, `rate()` schedules, S3 notifications with prefix filters, +Secrets Manager and OpenSearch Serverless. Keeping a second backend meant: + +- a Docker + auth-token dependency on the critical path of a tool whose reason + for existing is running large stacks on small machines; +- an integration suite that **skipped itself** unless you had a LocalStack Pro + token, so the only end-to-end coverage the project had usually did not run; +- two code paths for every explorer, every config key and every dashboard + screen — and the dashboard told self-engine users they were running LocalStack. + +v2's integration suite runs **on every machine and in every CI job**: no Docker, +no token, ~20 seconds. + +--- + +## What to change + +### 1. Configuration + +Delete these keys — they are rejected as unknown on `PUT /api/config`, and +`engine: "localstack"` aborts the boot: + +| Removed | Replacement | +|---|---| +| `engine` | none — there is one engine (drop the key; `"self"` is tolerated) | +| `mode` (`managed` / `external`) | none | +| `localstackPort`, `localstackEndpoint` | `selfEngine.port` (default `14566`) | +| `localstackEdition`, `localstackVersion`, `localstackImage` | none | +| `localstackAuthToken` | none | +| `services` | none — the engine serves its full set; see `GET /api/health` → `engine.services` | +| `aossSidecar` | none — OpenSearch Serverless is native to the engine | + +Before: + +```jsonc +{ + "serverPort": 3100, + "engine": "self", + "mode": "managed", + "localstackPort": 4566, + "localstackEdition": "community", + "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], + "selfEngine": { "port": 14566 } +} +``` + +After: + +```jsonc +{ + "serverPort": 3100, + "selfEngine": { "port": 14566 } +} +``` + +### 2. Environment variables + +Removed: `LSS_LOCALSTACK_PORT`, `LSS_LOCALSTACK_ENDPOINT`, `LSS_LOCALSTACK_MODE`, +`LSS_LOCALSTACK_EDITION`, `LSS_LOCALSTACK_VERSION`, `LSS_LOCALSTACK_IMAGE`, +`LOCALSTACK_AUTH_TOKEN`, `LSS_SERVICES`. `LSS_ENGINE` is accepted only as `self`. + +Still there, and now the fastest way to run a second instance: + +```bash +LSS_DASHBOARD_PORT=3250 LSS_ENGINE_PORT=14766 \ + LSS_ENGINE_DATA_DIR=/tmp/lss-run-7/engine npx lss start +``` + +### 3. CLI + +| Removed flag | What to do | +|---|---| +| `--self-engine` | drop it — it is the only mode | +| `--external` | drop it | +| `--pro` | drop it | +| `--localstack-token ` | drop it | + +Each one now exits 1 with a message naming this file, so a stale script fails +visibly instead of quietly starting the wrong thing. + +### 4. Service endpoints + +Point your handlers' AWS endpoint at the engine port (default `14566`) instead of +`4566`: + +```yaml +provider: + environment: + AWS_ENDPOINT: http://localhost:14566 +``` + +The engine's default port sits outside `4566–4599` on purpose: a real LocalStack +install intercepts that whole range on some hosts, and your machine may still +have one. + +### 5. API and client + +| Field | Change | +|---|---| +| `GET /api/health` → `localstack` | removed — use `engineRunning` (`engine.kind` is always `"self"`) | +| `GET /api/config` → `localstack` block | removed — `engine.endpoint` is the AWS endpoint | +| `GET /api/config` → `aossSidecar` | removed | +| `GET /api/config` → `services` | removed — `GET /api/health` → `engine.services` | +| `LssClient` `HealthStatus.localstack` | removed — use `engineRunning` | +| `LssClient` `lifecycle.start({ external, pro, localstackToken })` | removed | + +### 6. Examples + +`examples/localstack-free` and `examples/localstack-ultimate` are gone. +[`examples/self-hosted`](../examples/self-hosted/) is the example: four +microservices exercising DynamoDB, SQS with DLQ redrive, S3, EventBridge, +OpenSearch Serverless and Secrets Manager. + +The raw `AWS::ApiGatewayV2::*` cross-stack topology that lived in +`localstack-free/gateway-stack` moved to +`tests/integration/fixtures/apigw-raw/`, where its end-to-end test still runs. + +--- + +## What did *not* change + +Everything else. The wire API is the seam, so the provisioner, explorers, seeds, +the `serverless-lss` plugin, the Lambda runtime, the gateway emulation, the +dashboard, the `LssClient` and the MCP server all behave exactly as they did. +A project that already ran on `engine: "self"` needs only the config keys +trimmed. + +--- + +## If you still need LocalStack + +Pin `local-serverless-stack@^0.18` — the last line that ships both engines. + +If a specific AWS operation is missing from the self engine, prefer +`selfEngine.fallbackEndpoint`: it reverse-proxies the operations the engine does +not implement to any AWS-compatible endpoint you point it at, including a +LocalStack container you run yourself. That keeps the gap narrow instead of +bringing back a second backend. The coverage matrix and every known divergence +are in [SELF_ENGINE.md](SELF_ENGINE.md). diff --git a/docs/README.md b/docs/README.md index af07a7b..cdc162a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ LSS (Local Serverless Stack) is a local control plane for serverless development: one orchestrator provisions every AWS resource your services declare and emulates the Lambda runtime + API Gateway — backed either by the in-process **self engine** -(no Docker) or by a single shared **LocalStack** container. A CLI (`npx lss`), a +(no Docker, no container). A CLI (`npx lss`), a Vue 3 dashboard, a Serverless Framework plugin (`serverless-lss`) and a programmatic client (`LssClient`) sit on top. diff --git a/docs/SELF_ENGINE.md b/docs/SELF_ENGINE.md index db02ed3..d30a40c 100644 --- a/docs/SELF_ENGINE.md +++ b/docs/SELF_ENGINE.md @@ -1,41 +1,40 @@ # Self Engine -The self engine is an in-process AWS emulator that replaces LocalStack for the +The self engine is the in-process AWS emulator LSS runs on. It replaces a container-based emulator for the typical serverless dev loop: DynamoDB, SQS, S3, EventBridge, OpenSearch Serverless, Secrets Manager, SNS (minimal), Lambda control plane and STS served from a single `node:http` listener inside the orchestrator — no Docker, no container, no auth token. Design rationale and phased roadmap: [PRD_SELF_ENGINE.md](PRD_SELF_ENGINE.md) (PT-BR). -## Enabling it +## Configuring it ```jsonc // lss.config.json { - "engine": "self", // default: "localstack" "selfEngine": { "port": 14566, // default — outside 4566–4599 on purpose* - "dataDir": "~/.lss/engine", // default; /engine when stateDir is set + "dataDir": null, // default: /engine, else ~/.lss/projects//engine "account": "000000000000", "idleUnloadMs": 300000, // dehydrate idle data stores after 5 min "memoryBudgetMb": 128, // LRU budget for hydrated data "fsync": false, // true = fsync every WAL flush (paranoid) - "fallbackEndpoint": null // e.g. "http://localhost:4566" during migration + "fallbackEndpoint": null // reverse-proxy unimplemented operations here } } ``` -CLI: `npx lss start --self-engine` (equivalent to `LSS_ENGINE=self`). Env -overrides: `LSS_ENGINE`, `LSS_ENGINE_PORT`. `--self-engine` cannot be combined -with `--external`, `--pro` or `--localstack-token`. +Env overrides: `LSS_ENGINE_PORT`, `LSS_ENGINE_DATA_DIR` — together with +`LSS_DASHBOARD_PORT` they are everything a second instance needs. The engine +starts with the orchestrator; there is nothing to enable. -Point your application at the engine exactly like LocalStack: +Point your application at the engine like any AWS endpoint: ``` AWS_ENDPOINT=http://localhost:14566 ``` -\* A real LocalStack install intercepts ports 4566–4599 on some hosts (Docker +\* A real LocalStack install (if your machine has one) intercepts ports 4566–4599 on some hosts (Docker Desktop/WSL2), silently hijacking traffic. If you need the engine on 4566 for drop-in compatibility, set `selfEngine.port` explicitly. @@ -52,7 +51,7 @@ The wire API is the seam: the provisioner, the dashboards/explorers, seeds, all speak AWS SDK against the engine endpoint, unchanged. The `serverless-lss` plugin is unaffected too — it only POSTs JSON to the orchestrator REST API and never talks to the engine directly. Event delivery to your handlers happens **in-process** through the -LSS Lambda runtime — the LocalStack-era proxy Lambdas are absorbed as metadata +LSS Lambda runtime — proxy Lambdas are absorbed as metadata (their `INVOKE_URL` doubles as an HTTP fallback for services still running serverless-offline). @@ -74,7 +73,7 @@ object ACL/policy sub-resources (treated as plain object operations) — see | OpenSearch Serverless | Control plane (`aoss`): CreateCollection (deterministic ids, ACTIVE immediately), BatchGetCollection (hands out the local `collectionEndpoint`), ListCollections, DeleteCollection (id or name). Data plane under `/_aoss/`: index create/get/delete/HEAD, `_mapping` get/merge, `_doc`/`_create`/`_update` (deep merge, `doc_as_upsert`/`upsert`) with versioning, auto-create on first write, `_bulk` NDJSON with per-item results, `_search`/`_count` (`match`, `match_phrase`, `multi_match`, `term`, `terms`, `range`, `prefix`, `wildcard`, `exists`, `ids`, `bool` + `minimum_should_match`; `sort`, `from`/`size`, `_source` filtering, `?q=`), aggregations (`terms`, `avg`, `sum`, `min`, `max`, `value_count`), `_refresh`, `_cat/indices` | Security/access/lifecycle policy APIs, VPC endpoints, scripted updates, `_mget`, scroll/PIT, sub-aggregations, relevance scoring (`_score` is a constant 1), analyzers/k-NN — all rejected with an explicit OpenSearch-shaped error | | SNS | CreateTopic, ListTopics, DeleteTopic, GetTopicAttributes, Publish (logged + counted, no fan-out) | Subscriptions and delivery | | STS | GetCallerIdentity | Everything else | -| Secrets Manager | CreateSecret, GetSecretValue, PutSecretValue, UpdateSecret, DescribeSecret, DeleteSecret (recovery window + `ForceDeleteWithoutRecovery`), RestoreSecret, ListSecrets, TagResource/UntagResource, GetRandomPassword — real `AWSCURRENT`/`AWSPREVIOUS` version staging, `SecretString`/`SecretBinary`, `ClientRequestToken` idempotency, per-region scoping. Values persist in a catalog (not encrypted locally). Browsable in the dashboard's **Secrets** tab (list, version stages, reveal value). Retires the LocalStack Secrets Manager the engine used to proxy through `fallbackEndpoint`. Secrets are populated before the first read by two boot paths — CloudFormation `AWS::SecretsManager::Secret` provisioned at registration, and **boot seeds** (see below) | Rotation scheduling/Lambda, replication, KMS encryption (`KmsKeyId` accepted and ignored), resource policies | +| Secrets Manager | CreateSecret, GetSecretValue, PutSecretValue, UpdateSecret, DescribeSecret, DeleteSecret (recovery window + `ForceDeleteWithoutRecovery`), RestoreSecret, ListSecrets, TagResource/UntagResource, GetRandomPassword — real `AWSCURRENT`/`AWSPREVIOUS` version staging, `SecretString`/`SecretBinary`, `ClientRequestToken` idempotency, per-region scoping. Values persist in a catalog (not encrypted locally). Browsable in the dashboard's **Secrets** tab (list, version stages, reveal value). Secrets are populated before the first read by two boot paths — CloudFormation `AWS::SecretsManager::Secret` provisioned at registration, and **boot seeds** (see below) | Rotation scheduling/Lambda, replication, KMS encryption (`KmsKeyId` accepted and ignored), resource policies | ### Eventing (delivered in-process to the LSS Lambda runtime) @@ -141,6 +140,17 @@ Both paths share one value resolver, are idempotent (an existing active secret is skipped, never clobbered; one scheduled for deletion is warned and skipped) and non-fatal (a failure warns and boot continues). +## Health endpoints + +- `GET /_lss/health` — native: `{ "status": "ok", "engine": "self" }`. +- `GET /_localstack/health` — **compatibility alias**, not a dependency. Third-party + tooling (wait-for scripts, IDE plugins, compose healthchecks) probes this path to + decide whether a local AWS is up; the engine answers in the shape they expect, with + `edition: "self"` so nothing pretends to be something it is not. + +The orchestrator's own `GET /api/health` (port 3100) is the one the dashboard and the +`LssClient` use — it reports the engine plus the Lambda runtime and the DynamoDB proxy. + ## Storage & footprint Data lives under `dataDir` (default `/engine`, or @@ -194,4 +204,4 @@ run `lss seed`. Worst case, delete `dataDir` and start clean. are skipped with a registration warning). Unsigned data-plane requests (plain `curl`) resolve to the engine's default region — SigV4-signed clients carry their own region, like every other service. -- LocalStack volume data does not migrate; re-register + `lss seed`. +- Container-volume data from another emulator does not migrate; re-register + `lss seed`. diff --git a/examples/README.md b/examples/README.md index f593c4e..f155025 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,14 +1,12 @@ # LSS Examples -Three complete runnable projects — one per engine flavor. Each is a self-contained -monorepo slice: its own `lss.config.json`, AWS region, npm scripts, DynamoDB seeds, -dashboard branding and a browser validation console. +One complete runnable project: a self-contained monorepo slice with its own +`lss.config.json`, AWS region, npm scripts, DynamoDB seeds, dashboard branding and +a browser validation console. -| Example | Engine | Region | Docker? | Auth token? | Dashboard / engine ports | Services (API / invoke) | What it demonstrates | -| --- | --- | --- | --- | --- | --- | --- | --- | -| [localstack-free](localstack-free/) | LocalStack community 4.0 (managed) | `sa-east-1` | Yes | No | 3120 / LocalStack 4572 | users-service 3610/13610 · auth-service 3611/13611 · orders-service 3612/13612 · events-stack (portless) | httpApi v2 + REST v1, Lambda authorizers, shared EventBridge bus (`domain-events`), SQS consumer, schedule, DynamoDB stream → SNS, S3 uploads bucket + notification, seeds | -| [localstack-ultimate](localstack-ultimate/) | LocalStack Pro image (Ultimate plan) | `eu-west-1` | Yes | Yes (`LOCALSTACK_AUTH_TOKEN`) | 3111 / LocalStack 4571 | one service on serverless-offline: HTTP 3002 / invoke 3003 | The `--pro` path: Pro image + serverless-offline in charge of the ports, exercising the full resource menu — EventBridge custom bus + pattern rule with a queryable audit trail (`GET /audit`), `rate(2 minutes)` schedule, SQS DLQ redrive (`ReportBatchItemFailures`), DynamoDB GSI + streams → SNS, S3 notifications, TTL-from-the-UI story (resources named `localstack-ultimate-*`) | -| [self-hosted](self-hosted/) | LSS self engine (in-process) | `us-west-2` | No | No | 3140 / engine 14566 | orders 3631 · billing 3632 · notifications 3633 · catalog 3634 (invoke 13631–13634) | The no-Docker engine end to end: DynamoDB, SQS, S3, EventBridge pipeline plus an OpenSearch Serverless catalog (full-text search, filters, aggregations) | +| Example | Region | Docker? | Dashboard / engine ports | Services (API / invoke) | What it demonstrates | +| --- | --- | --- | --- | --- | --- | +| [self-hosted](self-hosted/) | `us-west-2` | No | 3140 / engine 14566 | orders 3631 · billing 3632 · notifications 3633 · catalog 3634 (invoke 13631–13634) | The engine end to end: DynamoDB, SQS with DLQ redrive, S3 (incl. presigned POST), EventBridge, Secrets Manager, and an OpenSearch Serverless catalog (full-text search, filters, aggregations) | ## Shared conventions @@ -17,23 +15,17 @@ Every example follows the same workflow: ```bash cd examples/ npm run setup # npm install in each service -npm run lss:start # start the orchestrator (self engine or managed LocalStack) +npm run lss:start # start the orchestrator + engine (no Docker) npm run register:all # sls package each service → auto-register + provision npm run lss:stop # tear everything down ``` -> localstack-ultimate is a single service on serverless-offline, so it has no -> `register:all`: after `npm run setup` + `npm run lss:start`, run -> `npm run offline` — packaging registers the service and offline serves the HTTP -> ports (see its [README](localstack-ultimate/README.md)). - - **Validation console**: each example ships an `index.html` you can open directly - in a browser — or serve with `npm run console` (localstack-free on **8620**, - localstack-ultimate on **8621**, self-hosted on **8622**) — to exercise every - endpoint and event flow from one page. -- **Dashboard branding**: each `lss.config.json` carries a `branding` block with a - logo made of the folder's initials — **LF** (purple), **LU** (amber), **SH** - (teal) — a live demo of the [branding config](../docs/CONFIGURATION.md#configuration-properties). + in a browser — or serve with `npm run console` (self-hosted on **8622**) — to + exercise every endpoint and event flow from one page. +- **Dashboard branding**: `lss.config.json` carries a `branding` block (teal **SH** + logo, per-theme brand tokens) — a live demo of the + [branding config](../docs/CONFIGURATION.md#configuration-properties). - **Seeds**: DynamoDB fixtures under `seeds/{tableName}.json`, auto-applied on table creation and re-applied via `npx lss seed` or the dashboard. - **.gitignore**: `node_modules/`, `.serverless/`, `.lss/`, `.env` are ignored in @@ -46,12 +38,9 @@ places to look): | Old example | Now covered by | | --- | --- | -| sample-microservice | [localstack-free](localstack-free/) (single-service DynamoDB/SQS/SNS/S3/stream/seed coverage folded into orders-service) | -| multi-service-sample | [localstack-free](localstack-free/) (users/auth/orders trio, cross-service events, schedules) | -| eventbridge-sample | [localstack-free](localstack-free/) (events-stack owns the `domain-events` bus; auth-service consumes `UserSignedUp` — `GET /signups`) | -| pro-sample-microservice | [localstack-ultimate](localstack-ultimate/) (resources renamed `localstack-ultimate-*`) | | self-engine-sample | [self-hosted](self-hosted/) (orders → billing → notifications pipeline) | | opensearch-sample | [self-hosted](self-hosted/) (catalog-service) | +| localstack-free, localstack-ultimate | removed in v2 with the LocalStack backend — see [MIGRATION-v2.md](../docs/MIGRATION-v2.md). Their raw `AWS::ApiGatewayV2::*` cross-stack topology moved to `tests/integration/fixtures/apigw-raw/`, where its end-to-end test still runs. | The integration suite no longer boots from `examples/`: the old sample-microservice test rig now lives at `tests/integration/fixtures/sample-microservice`. diff --git a/examples/localstack-free/.env.example b/examples/localstack-free/.env.example deleted file mode 100644 index b8ab083..0000000 --- a/examples/localstack-free/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -# Copy to `.env` (which is gitignored) and fill in. -# -# Optional for LocalStack community images >= 2026.5 — they prompt for a token -# even when running in free mode. Provide one to silence the warning and unlock -# the latest images. Get a free token at https://app.localstack.cloud -# (Personal access tokens). -LOCALSTACK_AUTH_TOKEN= diff --git a/examples/localstack-free/.gitignore b/examples/localstack-free/.gitignore deleted file mode 100644 index 3bab243..0000000 --- a/examples/localstack-free/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules/ -.serverless/ -.lss/ -.env -.env.local -*.log diff --git a/examples/localstack-free/README.md b/examples/localstack-free/README.md deleted file mode 100644 index 8e3c689..0000000 --- a/examples/localstack-free/README.md +++ /dev/null @@ -1,254 +0,0 @@ -# localstack-free - -The single **LocalStack community (free)** example: five services that exercise **LSS's API + Lambda emulation** end to end — API Gateway proxy, per-service Lambda runtime workers, Lambda authorizers (local **and** cross-service), raw **CloudFormation API Gateway v2** topologies, a shared **EventBridge bus**, **DynamoDB streams → SNS**, and **S3 bucket notifications**. There is **no `serverless-offline` anywhere** and no `serverless deploy`: each service ships only the `serverless-lss` plugin, and LSS itself serves the HTTP APIs and the AWS Lambda Invoke API. - -| Service | Language | API flavor | Authorizer | API port | Invoke port | -|---|---|---|---|---|---| -| `users-service` | TypeScript | HTTP API (payload **v2**) + **raw CFN** routes on its *own* framework `HttpApi` | local v2 **simple response** (×2) | `3610` | `13610` | -| `auth-service` | JavaScript | REST API (payload **v1**) | local v1 **REQUEST** (IAM policy) | `3611` | `13611` | -| `orders-service` | JavaScript | REST API (payload **v1**) | **cross-service** by ARN → auth-service | `3612` | `13612` | -| `gateway-stack` | — | **raw CFN** HTTP API v2 (`AWS::ApiGatewayV2::*`) — **no functions of its own** | **cross-stack** by ARN → users-service | `3613` | `13613` | -| `events-stack` | — | **resources-only** — owns the `domain-events` bus (+ an Archive, which LSS skips with a warning). No functions, no ports. | — | — | — | - -## What this exercises - -- **Authorizers, three flavors** — a local v1 REQUEST authorizer (IAM policy) in `auth-service`, a local v2 simple-response authorizer in `users-service`, and a **cross-service** authorizer in `orders-service` that references auth-service's Lambda **by ARN** (LSS resolves it against its global function registry). -- **TypeScript from source** — `users-service` handlers are `.ts` files run through `esbuild-register` (`lambdaRuntime.execution: "source"`), no build script. -- **Hot reload** — `lambdaRuntime.watch: true`; edit a handler and re-curl. -- **SQS consumer** — `orders-OrderQueue` with a Lambda consumer (`processOrderQueue`), running without serverless-offline. -- **Schedule** — `cleanupExpiredOrders` (`rate(1 hour)`), provisioned as an EventBridge rule that fires on schedule (`"events"` is enabled in `lss.config.json`); the function is also invocable via the Invoke API — every Lambda is, even without API events. -- **Raw `AWS::ApiGatewayV2::*` routes, cross-stack** — `gateway-stack` has **no `functions:` block and no `httpApi:` event at all**. It declares an `::Api` + `::Route` + `::Integration` + `::Authorizer` (plus the `AWS::Lambda::Permission` invoke grant) directly under `resources:`, all pointing at **users-service's** Lambdas by ARN. LSS parses those resource types, reduces `IntegrationUri`/`AuthorizerUri` (literal ARN, `Fn::GetAtt`, `Fn::Sub`, `Fn::ImportValue`, `Fn::Join`) to concrete ARNs, and registers them into the *same* route registry the `httpApi:` events feed — resolving the cross-stack target through the global function registry at request time, so **registration order does not matter**. A raw `::Route` that mirrors an existing `httpApi:` event is de-duplicated (the state route wins), which is why registering `users-service` yields its three `httpApi:` routes once, not twice. There is **no `/api/{proxy+}` or `$default` catch-all anywhere** in this example. -- **Raw `AWS::ApiGatewayV2::*` routes on the framework's OWN `HttpApi`** — the *other* half of the raw story, and the shape a real `serverless.yml` produces far more often than a dedicated gateway stack: `users-service` keeps its normal `httpApi:` events **and** hand-writes `GET`/`POST /api/identity/spaces` under `resources:`, with `ApiId: !Ref HttpApi` (no second `::Api`). Every reference uses the `!Sub` idiom the Serverless Framework passes straight through into the compiled template — `Target: !Sub 'integrations/${SpacesIntegration}'`, an `AuthorizerUri`/`IntegrationUri` that is the API Gateway **invocation-URI wrapper** (`arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LogicalId.Arn}/invocations`, *not* a bare Lambda ARN), `FunctionName: !Ref ListUsersLambdaFunction` (which CloudFormation resolves to a **name**, never an ARN) and `SourceArn: !Sub '…:${HttpApi}/*'`. Because that one template carries both the framework's compiled `::Route` mirrors and the genuinely-raw routes, it is also where the `(METHOD, path)` de-dup earns its keep. -- **`AWS::Lambda::Permission` as an advisory grant** — present, its `SourceArn` is recorded on the route; absent, the route still registers and LSS logs one warning naming the ungranted function (in AWS the call would 500, but locally the in-process runtime performs the invoke). -- **`AWS::Events::EventBus` in `resources:`** — registering `events-stack` (just `sls package`, never `deploy`) creates the `domain-events` bus in LocalStack. A service with zero functions and no ports registers fine. -- **`AWS::Events::Archive`** — accepted and skipped with a registration warning (LocalStack mocks Archives: CFN says `CREATE_COMPLETE`, `ListArchives` stays empty). -- **`events: eventBridge` trigger + pattern filtering** — `users-service`'s `createUser` publishes `UserSignedUp` (`source: users`) with a plain SDK `PutEvents`; `auth-service`'s `onUserSignedUp` rule (pattern `source: users`, `detail-type: UserSignedUp`) stores each event in `auth-SignupAudit`. Events with a non-matching source/detail-type are not delivered. -- **Real event envelope** — the EventBridge target receives the event exactly as AWS delivers it (`source`, `detail-type`, `detail`), *not* wrapped in `Records`. -- **DynamoDB stream → SNS** — `orders-Orders` streams `NEW_AND_OLD_IMAGES`; `onOrderStream` publishes every INSERT/MODIFY/REMOVE as an `order.*` message to the `orders-OrderEvents` SNS topic. -- **S3 bucket notification** — `POST /uploads` writes to `s3://orders-uploads/incoming/`; the bucket's `NotificationConfiguration` fires `onUpload`, which indexes the object back into `orders-Orders`. -- **Seeds** — `auth-Sessions`, `users-Users`, and `orders-Orders` are seeded from `./seeds` (a ready-made session `code-admin` included). -- **Dashboard branding** — see [Branding](#branding) below. - -> **Ports used by this example** — LSS server `3120`, LocalStack `4572`, service APIs `3610`–`3613`, Lambda invoke `13610`–`13613`, validation console `8620`. The non-default LocalStack port keeps this example out of the way of an external LocalStack you might have on `4566`, and clear of the other examples in this repo. (Caveat: a real LocalStack install commonly publishes the whole `4566–4599` range — in that case `4572` will still conflict.) - -## Prerequisites - -- Docker (LocalStack **community** runs in a container managed by LSS — no pro features needed) -- Node.js ≥ 20 - -## Run - -```bash -cd examples/localstack-free - -# Install the four services' dependencies -npm run setup - -# (Optional) LocalStack auth token — community images from 2026.5 onward -# prompt for one even in free mode: -cp .env.example .env # then fill LOCALSTACK_AUTH_TOKEN in your editor - -# 1. Start LSS (boots LocalStack via Docker; first run pulls the image, ~30s). -npm run lss:start - -# 2. Register all four services. `serverless package` triggers the LSS plugin, -# which POSTs the service to the orchestrator: resources are provisioned in -# LocalStack, routes + authorizers are registered, a runtime worker starts, -# and the API/invoke listeners bind on the ports above. events-stack goes -# FIRST so the domain-events bus exists before auth-service's rule lands. -npm run register:all -``` - -Open the dashboard at — **Services** lists all four, with their routes, authorizers, declared resources, and listener status. - -## Curl walkthrough - -**1. Log in against auth-service** (public route) — password is `lss-demo`: - -```bash -curl -X POST http://localhost:3611/login \ - -H 'Content-Type: application/json' \ - -d '{"user":"jane","password":"lss-demo"}' -# → 201 {"code":"code-jane"} -``` - -Or skip this step: the seed in `seeds/auth-Sessions.json` ships a ready-made session `code-admin`. - -**2. Call a v1-protected route** — the local REQUEST authorizer looks the `code` header up in DynamoDB and allows/denies with an IAM policy: - -```bash -curl http://localhost:3611/whoami -H 'code: code-admin' -# → 200 {"user":"admin"} - -curl http://localhost:3611/whoami -H 'code: nope' -# → 403 (Deny policy) -``` - -**3. Create a user and watch EventBridge deliver it cross-service** — `createUser` (TypeScript, HTTP API v2) writes to DynamoDB and publishes `UserSignedUp` onto the shared `domain-events` bus; auth-service's `eventBridge`-triggered `onUserSignedUp` stores the real envelope in `auth-SignupAudit`: - -```bash -curl -X POST http://localhost:3610/users \ - -H 'Authorization: Bearer lss-secret' \ - -H 'Content-Type: application/json' \ - -d '{"name":"Dora","email":"dora@example.com"}' -# → 201 {"id":"...","name":"Dora",...} - -# First delivery cold-starts the proxy Lambda in LocalStack — give it ~10s: -curl http://localhost:3611/signups -# → 200 {"count":1,"signups":[{"eventId":"...","source":"users","detailType":"UserSignedUp","detail":{"userId":"..."}}]} -``` - -`GET /users` and `GET /users/{id}` work the same way (`Authorization: Bearer lss-secret`). - -**3b. A raw CloudFormation route on the service's OWN framework `HttpApi`** — `users-service` declares `GET`/`POST /api/identity/spaces` under `resources:` with `ApiId: !Ref HttpApi`, `Target: !Sub 'integrations/${SpacesIntegration}'` and an `AuthorizerUri`/`IntegrationUri` in the API Gateway *invocation-URI* form. No second `::Api`, no `httpApi:` event — yet they are served on the same port as the compiled routes, behind their own raw authorizer: - -```bash -curl http://localhost:3610/api/identity/spaces -H 'authorization: Bearer lss-secret' -# → 200 {"items":[...]} (the raw route lands on listUsers) - -curl -i http://localhost:3610/api/identity/spaces -# → 401 (identity source header absent — the raw ::Authorizer is enforced) -``` - -`GET /users` is still registered **once**: the framework compiles a mirror `::Route` for every `httpApi:` event into the very same template, and LSS de-duplicates it by `(METHOD, normalized path)` in favor of the serverless-state route. - -**3c. A raw cross-stack CloudFormation route** — `gateway-stack` owns **no Lambdas**. Its `GET /gw/users` exists only as an `AWS::ApiGatewayV2::Route` under `resources:`, wired by ARN to users-service's `listUsers`, and guarded by an `AWS::ApiGatewayV2::Authorizer` pointing at users-service's v2 authorizer. LSS resolves both across the stack boundary at request time: - -```bash -# Same body as :3610/users — but served by the gateway stack's raw route, -# invoking a Lambda that belongs to another service entirely. -curl http://localhost:3613/gw/users -H 'authorization: Bearer lss-secret' -# → 200 {"items":[...]} - -# The cross-stack authorizer is enforced, not bypassed: -curl -i http://localhost:3613/gw/users -# → 401 (identity source header absent — authorizer never invoked, as in AWS) -curl -i http://localhost:3613/gw/users -H 'authorization: Bearer wrong' -# → 403 (authorizer returned {isAuthorized:false}) -``` - -Confirm the topology resolved on its own — the route reports the cross-service `functionArn`, and nothing anywhere falls back to a catch-all: - -```bash -curl -s http://localhost:3120/api/apis | grep -o '"path":"[^"]*"' | sort -u -# → …"path":"/gw/users"… and NO "/api/{proxy+}" and NO "$default" -``` - -**4. Cross-service authorizer + SQS + stream → SNS** — `orders-service` declares its authorizer by **ARN**; the Lambda behind it lives in `auth-service`. The order flows through SQS → `processOrderQueue` → DynamoDB, and the table's stream fans the write out to the `orders-OrderEvents` SNS topic via `onOrderStream`: - -```bash -curl -X POST http://localhost:3612/orders \ - -H 'Content-Type: application/json' \ - -H 'code: code-admin' \ - -d '{"item":"coffee"}' -# → 202 {"queued":true,"id":"..."} - -curl http://localhost:3612/orders -H 'code: code-admin' -# → 200 {"count":4,"items":[...,{"item":"coffee","user":"admin","status":"processed",...}]} -``` - -**5. S3 notification round-trip** — `POST /uploads` puts the payload under `incoming/` in `orders-uploads`; the bucket notification fires `onUpload`, which reads the object back and indexes it into `orders-Orders` (status `uploaded`): - -```bash -curl -X POST http://localhost:3612/uploads \ - -H 'Content-Type: application/json' \ - -d '{"filename":"hello.txt","content":"hello LSS"}' -# → 201 {"uploaded":true,"bucket":"orders-uploads","key":"incoming/hello.txt"} - -curl http://localhost:3612/uploads -# → 200 {"bucket":"orders-uploads","count":1,"objects":[{"key":"incoming/hello.txt",...}]} - -# ~10s later the indexed row appears: -curl http://localhost:3612/orders -H 'code: code-admin' -# → ...{"id":"upload:orders-uploads/incoming/hello.txt","status":"uploaded",...} -``` - -**6. Invoke any Lambda directly** — every function is reachable through the AWS Lambda Invoke API on the service's invoke port, even ones with no API event (like the scheduled `cleanupExpiredOrders`): - -```bash -AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test aws lambda invoke \ - --endpoint-url http://localhost:13612 \ - --region sa-east-1 \ - --function-name orders-service-dev-cleanupExpiredOrders \ - --cli-binary-format raw-in-base64-out \ - --payload '{}' /dev/stdout -# → {"scanned":4,"deleted":0} -``` - -Short names work too (`--function-name cleanupExpiredOrders`), and the same API is what SDK-based tests (or the programmatic `LssClient`) hit. - -## Validation console - -A one-page console at [`index.html`](./index.html) runs every flow above from the browser — status dots for each port, one-click request chains (login → whoami, create user → signup audit, order → SQS, upload → S3 notification), editable request bodies, and a request log. - -```bash -npm run console # serves it on http://localhost:8620 -``` - -…or just open `index.html` straight from the file system (`file://` works — the LSS gateway answers CORS preflights itself for routes declared with `cors: true`). - -## Branding - -The example also showcases [dashboard branding](../../docs/CONFIGURATION.md#configuration-properties): `lss.config.json` sets a custom `title`/`subtitle`, points `logo`/`favicon` at [`assets/logo.svg`](./assets/logo.svg), defaults the UI to the **dark** theme, and overrides the TreeUI brand tokens (`brand-primary`/`brand-hover`/`brand-soft`) with purple tones — so the dashboard at `http://localhost:3120` opens with this example's identity. Each example in this repo uses a different branding mechanism; this one is the simple top-level `colors` form. - -## Hot reload - -`lambdaRuntime.watch` is on. Change a handler — say, make `whoami.js` also return a timestamp — save, and re-run the curl. The runtime worker reloads the module from source (TypeScript included, via `esbuild-register`); no re-register, no restart. - -## Reset - -```bash -npm run lss:seed # re-apply seed fixtures -npm run lss:stop # stops orchestrator + LocalStack (persistence is off) -``` - -## File map - -``` -lss.config.json ← LSS config: managed community LocalStack on 4572, - lambdaRuntime {execution: source, watch: true}, branding -index.html ← validation console (npm run console → :8620) -assets/logo.svg ← dashboard logo/favicon (referenced from lss.config.json) -seeds/ - auth-Sessions.json ← seeded session code-admin (name must match table) - users-Users.json ← two seeded users - orders-Orders.json ← three seeded orders (writes also flow through the stream) -events-stack/ ← resources-only: domain-events bus + Archive (skipped) - serverless.yml -gateway-stack/ ← raw CFN HTTP API v2, no functions, ports 3613/13613 - serverless.yml ← ::Api + ::Route + ::Integration + ::Authorizer - + Lambda::Permission, all targeting users-service - Lambdas by cross-stack ARN. No httpApi: event. -auth-service/ ← JS, REST v1, ports 3611/13611 - serverless.yml ← + eventBridge rule on the shared bus (by ARN) - src/handlers/ - aws.js ← shared AWS SDK clients (point at LocalStack) - login.js ← POST /login (public) → writes session - session-authorizer.js ← v1 REQUEST authorizer (IAM policy), no events; - used locally by whoami and by ARN from orders - whoami.js ← GET /whoami (protected) - onUserSignedUp.js ← eventBridge target → auth-SignupAudit - listSignups.js ← GET /signups (public) → lists the audit table -users-service/ ← TS, HTTP API v2, ports 3610/13610 - serverless.yml ← provider.httpApi.authorizers (simple responses) - tsconfig.json ← noEmit; LSS runs .ts from source - src/handlers/ - aws.ts ← + EventBridge client - session-authorizer-v2.ts ← {isAuthorized, context} - listUsers.ts ← bare-object return (v2 inferred response) - createUser.ts ← explicit {statusCode: 201} + PutEvents UserSignedUp - getUser.ts ← path parameters -orders-service/ ← JS, REST v1, ports 3612/13612 - serverless.yml ← cross-service authorizer by ARN + SQS + schedule - + stream + SNS topic + S3 bucket notification - src/handlers/ - aws.js ← + SNS and S3 clients - createOrder.js ← POST /orders → SQS - listOrders.js ← GET /orders - processOrderQueue.js ← SQS consumer → DynamoDB (status: processed) - cleanupExpiredOrders.js ← schedule rate(1 hour); invoke on 13612 - onOrderStream.js ← DynamoDB stream → SNS orders-OrderEvents - uploadFile.js ← POST /uploads → s3://orders-uploads/incoming/ - listUploads.js ← GET /uploads - onUpload.js ← S3 notification target → indexes into orders-Orders -``` diff --git a/examples/localstack-free/assets/logo.svg b/examples/localstack-free/assets/logo.svg deleted file mode 100644 index 2a7ca4d..0000000 --- a/examples/localstack-free/assets/logo.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - LF - diff --git a/examples/localstack-free/auth-service/package-lock.json b/examples/localstack-free/auth-service/package-lock.json deleted file mode 100644 index b1e080d..0000000 --- a/examples/localstack-free/auth-service/package-lock.json +++ /dev/null @@ -1,2745 +0,0 @@ -{ - "name": "auth-service-example", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "auth-service-example", - "version": "0.0.0", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.0.0", - "@aws-sdk/lib-dynamodb": "^3.0.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } - }, - "../../../packages/serverless-plugin": { - "name": "serverless-lss", - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "devDependencies": { - "@types/node": "^22.10.5", - "typescript": "^5.7.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "osls": "4.0.0" - }, - "peerDependenciesMeta": { - "osls": { - "optional": true - } - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.5.0.tgz", - "integrity": "sha512-Ps4w0FwrDoeVK6hfYxWkVbkmxm+zN+6xoXF2ZfEhfiox0ZNbcSAiUWO6iAIvP5bc3DB270r+EaKcoT1IUyzfxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@types/json-schema": "^7.0.15" - } - }, - "node_modules/@aws-sdk/checksums": { - "version": "3.1000.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.16.tgz", - "integrity": "sha512-EKnvkXSmz3IpA99tCNuI+dLFXyZyClSm8zns9sB/elvkU+MTuomAs6toJMPMBf98/fICG/urXDkzGz0/c3yyAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-api-gateway": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.1081.0.tgz", - "integrity": "sha512-uKUrTUNc0VaVMslK/vJ6qg4LBnynHnvb9pu7gLtFe06+g4rT2IseJWed6xrdfa0t8iSW00rrLoTVbHNEukjETg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/middleware-sdk-api-gateway": "^3.972.21", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-apigatewayv2": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewayv2/-/client-apigatewayv2-3.1085.0.tgz", - "integrity": "sha512-IeDwKOit9IndGVNOcEAAIxwj5z+YhX4aGVNXU+C0sZvALnSOI83rGMekPGxGrZf6tDxpmwtIrSm6qYWPbFkNXA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.1081.0.tgz", - "integrity": "sha512-i+lK0BnbX8JdFI/7HV/JY6XmrZsEmmLffuJRyn+J+gP9zzAiNOdraOnMi0eVcJE8CraTt5fixyxBO8AalFW8rw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.1085.0.tgz", - "integrity": "sha512-2WyjUH6zdRvPSvL/8JJYo6BJfK4hNn9RA3+3XEfPczQ/uYxhFfIR8hbNIrRQe7ffb9X8CCxN6YpSQtw8iXQboA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/middleware-compression": "^4.5.7", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1085.0.tgz", - "integrity": "sha512-jNMt5zMsnJ6X0fZJKKNU5/qTQ98OIsUSFLqDh+FTXQTiEI3NTq95gAdsaAwXVWO9hTaT5gY7fbwF5Ally69bwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1081.0.tgz", - "integrity": "sha512-ipDgvZ3Hy8kaFrkwj62yuoghKkZi5WrWTiJnaqGc/ntbuAuijIkRWhzSb8d1MGEE+qb+vFFTrWVFwGSqt76TCA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity-provider": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.1081.0.tgz", - "integrity": "sha512-uBvMQ2gLiNphTjmZKHz0WAq4mESC9OCngmzE4FJSVnm6bjUZMWSBU4rJCEjYh/gzZ5BLRk1TV1BzTdMuU78kFQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1081.0.tgz", - "integrity": "sha512-gQ2XvMVY+5Co6znCODeCuLVaGRPKTeRQ+lATsw4Cm4/v+HHVQ3OJacE3wwO5FRg7shgYswOTusPM5icLEzsv9w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/dynamodb-codec": "^3.973.29", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.22", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ecr": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.1085.0.tgz", - "integrity": "sha512-I1MWQNb01MlfC2MENTll+GrRV2RSGmkQSyB289CEY2QGf4ImqeEsySWFtpau/39zqTxqOyx/jfXrT5vdr3hOyQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-eventbridge": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-eventbridge/-/client-eventbridge-3.1081.0.tgz", - "integrity": "sha512-yfApvz19TIF27sZqnhYr/jGbMF2sg4r0L2HEbKzM+KqLFdqE8um/IDBgbEL++WDr4qtGIRL9OodoyFKbhAfNyg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/signature-v4-multi-region": "^3.996.38", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-iam": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.1081.0.tgz", - "integrity": "sha512-PR9jz6r6+inwSHrdwI9O4Vgolkd6+lTQ+H+YS2s4uyC2J8FGUDMCJO40ycszcvy8o8EWwFS/ACA/HotY+OAHLQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1081.0.tgz", - "integrity": "sha512-DlFiHPVHQsGz+2Zyli25tA4SQW1xPggko/lZMCsFwxzXeTyoW4X+EHkcRul1K7Z/Rf2zpGnwZWS+PWZYTFRaSw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1085.0.tgz", - "integrity": "sha512-O0xe8sR50AYkwxlvRRsV0qytEO2dtXQTQ1CF3YBBdE5xtVkbu27H0vGa1mjQi1/+fbYM80AWEIPai5jZmXyubw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/checksums": "^3.1000.16", - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/middleware-sdk-s3": "^3.972.62", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1085.0.tgz", - "integrity": "sha512-vFYFncOReqEtOj110hdTQK/4JzNEHdVR90Ob6FjdEeb8cNer+HShI64Nuw9J4gTUQAWJ0eErHZqqxQPTViplew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1081.0.tgz", - "integrity": "sha512-URSoqhxMGf4Mv6MMyR6pcerTjbVKKqKLU7GGpZddxiOJ/Ca1qeUz3hvjuF2m/AMaw3e28bUdMvo7ZDh3aMX/ig==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/signature-v4-multi-region": "^3.996.38", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.975.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.975.1.tgz", - "integrity": "sha512-8qh/6EYb7hl/ZwVfQufhbMEZs1gQIc7GbdrIf4eprQJ7cv042+74nE6l3YDfyWNzb9iPXb8fRyYSHkNIk5eE6Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@aws-sdk/xml-builder": "^3.972.34", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.29.2", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.56", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.56.tgz", - "integrity": "sha512-nedaZz6Wz2FGUBMsWhlvBPGIkTMfRuMJ99YDHJI4CaC31JS8WPyTavEAio74cfd5nGhi0A8XASB4fZA5VqTdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.57.tgz", - "integrity": "sha512-1RfJaF7SW1TOnvNGU7kaYjwUf5H3sfm+synGH1bHhRlqcnxCt3szebH3dmKEyY4tuGcbQ6ffzUT89cRitBV8OQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.59", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.59.tgz", - "integrity": "sha512-sRCkpTiFnCdQvuaRVjQ6SVoHu6i7RUpurVo1c4F81HWhPvUJ7Wdp5MNtSdX1O29CNXc8em3O5m52hCjVtAD9SA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.1.tgz", - "integrity": "sha512-6d8H6ZAh3ZPKZ6fe1nG2OWeZEZPtt9ravoD1dezPdPtsSkJRoxGAnFSHwKT3E/Te6fHE30zRzjV6TD12rvF6yQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-login": "^3.972.63", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.63.tgz", - "integrity": "sha512-GREWRrMj0XnNKMaVa/Mauoaui26qBEHu71WWqXbwZOu/jFQOnPZjTf7u0KtGKC8VGa6VUs9kDWGgocrKNLS9vw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.66", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.66.tgz", - "integrity": "sha512-f+qjRXZpz7sgzbc4QB+6nLKfyKFgRRXzWdXbsKPv/VhVRyHsDyq4yBWC/B75BAJpFIcUeI2XR/3gdWJ677zB4A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-ini": "^3.973.1", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.57.tgz", - "integrity": "sha512-TiVQhuU0pbhIZAUZacbPHMyzrIdiH+lnx+PMY/Pu/b93dJrq3wdZwzUJ0TPpvNxaqbHsxJvQZW3/h/beLiKq7Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.1.tgz", - "integrity": "sha512-3foTZUJ4821Ij60X7K3NJroygiZLnbBmarN+T//O2cjkISan90zElN3NBmgSlDrTQ7Gs6z/yO8V7h60QNcDZHQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/token-providers": "3.1083.0", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.63.tgz", - "integrity": "sha512-8qZLFhM69eKcS37m459ctPR05Qimycm/74OPVioe6wNZabMT54GYhwBju0+J656RkMasNSawWQu+c8CmBe3TUQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1081.0.tgz", - "integrity": "sha512-UHWvxd1F5nfBXBRXtQaXWoNT8CYKXZovLQOyz6XZlgFTGc2mWzzPGspOfnh49jwvB2qzsdH046i9jnnmND+64w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.1081.0", - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.54", - "@aws-sdk/credential-provider-env": "^3.972.55", - "@aws-sdk/credential-provider-http": "^3.972.57", - "@aws-sdk/credential-provider-ini": "^3.972.62", - "@aws-sdk/credential-provider-login": "^3.972.61", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/credential-provider-process": "^3.972.55", - "@aws-sdk/credential-provider-sso": "^3.972.61", - "@aws-sdk/credential-provider-web-identity": "^3.972.61", - "@aws-sdk/nested-clients": "^3.997.29", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/credential-provider-imds": "^4.4.5", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.29", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.29.tgz", - "integrity": "sha512-1Eprv8BD2cOsVccCpEGm+hyZzj3LjthLoDOXHuvH6Vz8GJPZWknrmn05kICyZpx7srfe/KOm4GQXrJgXkPUJuA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.8.tgz", - "integrity": "sha512-bBmkG0Dnhfq0/T4Z0PpUr7HkncBVaWvvCbvafeaUM+yC9wa8GGjLJmonq0QL17REB9WivgGeYgWQ5A80Uw5UnQ==", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.1081.0.tgz", - "integrity": "sha512-o9hjLKJBhjspX52P9vIngEsr12YNyBzfiVbmPHQhrgOEN3BGZjd0wa9ufRzHF2jygFZak66dlPx5AeK+4qI/eg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/util-dynamodb": "^3.996.5", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1081.0" - } - }, - "node_modules/@aws-sdk/lib-storage": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1085.0.tgz", - "integrity": "sha512-S+yCGIMxQ5Zs2A5ZDdYfXwOxu5kKjBaCQVOxp6+mnwCQYXUNkBD/aKCnW1eniMTavzz3YidhD5eTFpDlcUv2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.1085.0" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.22", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.22.tgz", - "integrity": "sha512-GMoLg4XAnkiwevqcOfgz0lOTYmIdM7MJK/BL9EAvsoMFqKIGRpyNIvuSNg5gdFzP57yB+EklMlK0+TwBqj1tCg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.8", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-api-gateway": { - "version": "3.972.21", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-api-gateway/-/middleware-sdk-api-gateway-3.972.21.tgz", - "integrity": "sha512-tlu8JAcbrhh4jnoQXczWQ2QIOaev3ZdVBdU4RRaNBfJmVyuBbMKdh6mdrunEdSFgm2GlJW1lIhE4BHTL0A55dw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.62", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.62.tgz", - "integrity": "sha512-k8JJwYXVYlOOjWnPZDThQS1xDFJgi5Dokt73qFlDtrZAbdcint5aIdjB9XgJAAQVP5OoqcefQmh1FYXiPpvsvw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.31.tgz", - "integrity": "sha512-BDHTpwcsZHEBNEJzOg/B1BkFYJxAXY50dau/NyVWs3d51F0WgIUGSWZot/Os+N3KpDhXeaXnz37mWffAvduREw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.39.tgz", - "integrity": "sha512-8+srXqYIF8KYMLC4FxMLEM5Ek7kUNibJu1R4m8/fUhhNYIZZz26oGtKkCr8I/HiG2fFQxBvaGgQZT4/mqRCSnA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1083.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1083.0.tgz", - "integrity": "sha512-s0woKnxuHrExLc5L2ArIH5BMkbonHPtt+5hSBM8oknp9M6QTuUmmAmJ2E0EdzCGONrO+8+ADPqvv6UX0nNcc7A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.0.tgz", - "integrity": "sha512-QIBrw90CDm4O0UaIIzkU6DrFdeJzEb2Va5EPEVpyldj6sHJxB6cshhStJuhZxk3wR3PmjJlYsjPmY1kNb+KGBg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.996.5.tgz", - "integrity": "sha512-m9bdmYq3WtbMHAKGALw9XWiMBfKu5T8ukgdJT7Mc/d2oOwDGNFmhsnnkQ18xomoXo/ZHxAuIDi3Y6slsblW1Mg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1069.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.34.tgz", - "integrity": "sha512-wHhWL1y7sN3enBA8POrPpQM5jCcmu2ozyhbRei4c8OjVcEaEs6yLucLa/pla457ggS/ysuy7bosagz3HaJkZXA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@smithy/core": { - "version": "3.29.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.3.tgz", - "integrity": "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.7.tgz", - "integrity": "sha512-UEMLOoA0Fl4uYBxh6l0uN0H6EJe/A89OGeDNTteQeXpJ20BcpfIr4wlCY9pel1jEAUHAxaYwuqrYlrKdXE1GKQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.4.tgz", - "integrity": "sha512-psnst7NZWdAEvJvyW8YZEE7xNVMyLrQFfHtyrVFrxNyy+dKWkQ+rqC6oI5ZhxThpUy9RSfEshgm34zqbOxzsRw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-compression": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-compression/-/middleware-compression-4.5.8.tgz", - "integrity": "sha512-ODHXD5tDW3+25pfiLjJ2ZTIHRfWWxqVGPqIMz1NjmiV4bG4i1S0kuibHxik6WXibR03nmDGMiI1/hF6647F/Zg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "fflate": "0.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.4.tgz", - "integrity": "sha512-BNTop/fSOptmoVk8g+efwHCofFh37g70OWGAFES1TeAAJja1K5aAI8rTE26ETSc5k8IQuWY2kAIoPla01NgYrA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.3.tgz", - "integrity": "sha512-8qVKKzqh7naF27ePmx0SkUfnGP/wBI9dyaeAmhHvopnbIlItUAmB/e6PkPCU3rRb2v9BY8D4EZXSoydSibatvw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", - "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-sprintf-format/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-sprintf-format/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-cli": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.4.4.tgz", - "integrity": "sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "dotenv": "^16.3.0", - "dotenv-expand": "^10.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", - "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-cycle": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", - "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/log": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.2.tgz", - "integrity": "sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "duration": "^0.2.2", - "es5-ext": "^0.10.64", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.2", - "type": "^2.7.3", - "uni-global": "^1.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "peerDependencies": { - "log": "^6.0.0" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mnemonist": { - "version": "0.38.3", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", - "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", - "license": "MIT", - "dependencies": { - "obliterator": "^1.6.1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/obliterator": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", - "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", - "license": "MIT" - }, - "node_modules/osls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/osls/-/osls-4.0.0.tgz", - "integrity": "sha512-ti1s4IhJLfpdWtgyb3gj8slDs1KoucRU0jNyqGIaEGPGCODiJtFXXVM3cs52pQLi3Ig2RBeqHzhD84vWOLvSeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", - "@aws-sdk/client-api-gateway": "^3.1034.0", - "@aws-sdk/client-apigatewayv2": "^3.1034.0", - "@aws-sdk/client-cloudformation": "^3.1034.0", - "@aws-sdk/client-cloudwatch": "^3.1034.0", - "@aws-sdk/client-cloudwatch-logs": "^3.1034.0", - "@aws-sdk/client-cognito-identity-provider": "^3.1034.0", - "@aws-sdk/client-ecr": "^3.1034.0", - "@aws-sdk/client-eventbridge": "^3.1034.0", - "@aws-sdk/client-iam": "^3.1034.0", - "@aws-sdk/client-lambda": "^3.1034.0", - "@aws-sdk/client-s3": "^3.1034.0", - "@aws-sdk/client-ssm": "^3.1034.0", - "@aws-sdk/client-sts": "^3.1034.0", - "@aws-sdk/credential-providers": "^3.1034.0", - "@aws-sdk/lib-storage": "^3.1034.0", - "@smithy/core": "^3.23.16", - "@smithy/node-http-handler": "^4.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "content-disposition": "^2.0.1", - "cross-spawn": "^7.0.6", - "dotenv": "^17.4.2", - "dotenv-expand": "^13.0.0", - "ext": "^1.7.0", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "filenamify": "^7.0.1", - "https-proxy-agent": "^9.0.0", - "js-yaml": "^4.3.0", - "json-cycle": "^1.5.0", - "log": "^6.3.1", - "log-node": "^8.0.3", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "mime-types": "^3.0.2", - "semver": "^7.5.3", - "signal-exit": "^4.1.0", - "tsx": "^4.20.3", - "type": "^2.7.2", - "undici": "^7.25.0", - "write-file-atomic": "^7.0.1", - "yauzl": "^3.3.0", - "yazl": "^3.3.1" - }, - "bin": { - "osls": "bin/serverless.js", - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/osls/node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/osls/node_modules/content-disposition": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", - "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/dotenv-expand": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", - "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^17.4.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/filename-reserved-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", - "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/filenamify": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.2.tgz", - "integrity": "sha512-fz10TUqSZ1lG7ftW1KnRotJzMD8YRb6kaAQKpZJBLvqXXfFgIEpuazy1w2lK3zhMiBSdH/uF9LFlv5smJ2Jl1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "filename-reserved-regex": "^4.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/https-proxy-agent": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", - "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "proxy-agent-negotiate": "1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/osls/node_modules/write-file-atomic": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", - "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", - "dev": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/osls/node_modules/yauzl": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", - "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proxy-agent-negotiate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", - "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "kerberos": "^2.0.0" - }, - "peerDependenciesMeta": { - "kerberos": { - "optional": true - } - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serverless-lss": { - "resolved": "../../../packages/serverless-plugin", - "link": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-kit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz", - "integrity": "sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", - "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/yazl": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-3.3.1.tgz", - "integrity": "sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "^1.0.0" - } - }, - "node_modules/yazl/node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - } - } -} diff --git a/examples/localstack-free/auth-service/package.json b/examples/localstack-free/auth-service/package.json deleted file mode 100644 index 25e08a1..0000000 --- a/examples/localstack-free/auth-service/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "auth-service-example", - "version": "0.0.0", - "private": true, - "description": "JavaScript REST API (payload v1) with a local REQUEST authorizer, plus an eventBridge-triggered signup audit fed by users-service through the shared domain-events bus. Served by LSS on port 3611 (invoke 13611).", - "scripts": { - "package": "serverless package", - "register": "serverless package" - }, - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.0.0", - "@aws-sdk/lib-dynamodb": "^3.0.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } -} diff --git a/examples/localstack-free/auth-service/serverless.yml b/examples/localstack-free/auth-service/serverless.yml deleted file mode 100644 index 1aa469e..0000000 --- a/examples/localstack-free/auth-service/serverless.yml +++ /dev/null @@ -1,112 +0,0 @@ -service: auth-service - -frameworkVersion: '>=3' - -provider: - name: aws - runtime: nodejs20.x - region: sa-east-1 - stage: dev - environment: - SESSIONS_TABLE: auth-Sessions - SIGNUP_AUDIT_TABLE: auth-SignupAudit - AWS_ENDPOINT: http://localhost:4572 - -plugins: - - serverless-lss - -custom: - accountId: '000000000000' - orchestrator: - enabled: true - orchestratorUrl: http://localhost:3120 - lss: - apiPort: 3611 - invokePort: 13611 - -functions: - # POST /login — public route (no authorizer). password "lss-demo" mints a - # session code and stores it in DynamoDB. - login: - handler: src/handlers/login.handler - events: - - http: - path: /login - method: post - cors: true - - # v1 REQUEST authorizer. No events on purpose: it is referenced inline by - # `whoami` below AND cross-service (by ARN) from orders-service. - sessionAuthorizer: - handler: src/handlers/session-authorizer.handler - - # GET /whoami — protected by the local v1 REQUEST authorizer above. - whoami: - handler: src/handlers/whoami.handler - events: - - http: - path: /whoami - method: get - cors: true - authorizer: - name: sessionAuthorizer - type: request - identitySource: method.request.header.code - resultTtlInSeconds: 3600 - - # eventBridge trigger against the SHARED domain-events bus (owned by - # events-stack, referenced here by ARN so Serverless does not create a - # second bus). users-service publishes UserSignedUp with PutEvents; - # Serverless compiles this trigger to a native AWS::Events::Rule, LSS puts - # the rule on the bus in LocalStack and wires the target to this function - # through its proxy → Invoke API model. The handler receives the REAL - # EventBridge envelope (source, detail-type, detail) — no Records wrapper. - onUserSignedUp: - handler: src/handlers/onUserSignedUp.handler - events: - - eventBridge: - eventBus: arn:aws:events:${self:provider.region}:${self:custom.accountId}:event-bus/domain-events - pattern: - source: - - users - detail-type: - - UserSignedUp - - # GET /signups — public; lists the audit rows written by onUserSignedUp so - # the cross-service EventBridge flow is observable over plain HTTP. - listSignups: - handler: src/handlers/listSignups.handler - events: - - http: - path: /signups - method: get - cors: true - -resources: - Resources: - SessionsTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: auth-Sessions - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: code - AttributeType: S - KeySchema: - - AttributeName: code - KeyType: HASH - - SignupAuditTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: auth-SignupAudit - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: eventId - AttributeType: S - KeySchema: - - AttributeName: eventId - KeyType: HASH - -package: - individually: false diff --git a/examples/localstack-free/auth-service/src/handlers/aws.js b/examples/localstack-free/auth-service/src/handlers/aws.js deleted file mode 100644 index e8fe4d3..0000000 --- a/examples/localstack-free/auth-service/src/handlers/aws.js +++ /dev/null @@ -1,15 +0,0 @@ -const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); -const { DynamoDBDocumentClient } = require('@aws-sdk/lib-dynamodb'); - -const baseConfig = { - region: process.env.AWS_REGION || 'sa-east-1', - endpoint: process.env.AWS_ENDPOINT || 'http://localhost:4572', - credentials: { accessKeyId: 'test', secretAccessKey: 'test' }, -}; - -const dynamo = new DynamoDBClient(baseConfig); - -module.exports = { - dynamo, - doc: DynamoDBDocumentClient.from(dynamo), -}; diff --git a/examples/localstack-free/auth-service/src/handlers/listSignups.js b/examples/localstack-free/auth-service/src/handlers/listSignups.js deleted file mode 100644 index 18caa95..0000000 --- a/examples/localstack-free/auth-service/src/handlers/listSignups.js +++ /dev/null @@ -1,14 +0,0 @@ -const { ScanCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// GET /signups — makes the async cross-service flow observable: whatever the -// eventBridge trigger (onUserSignedUp) stored shows up here. -exports.handler = async () => { - const res = await doc.send(new ScanCommand({ TableName: process.env.SIGNUP_AUDIT_TABLE })); - const items = res.Items || []; - return { - statusCode: 200, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ count: items.length, signups: items }), - }; -}; diff --git a/examples/localstack-free/auth-service/src/handlers/login.js b/examples/localstack-free/auth-service/src/handlers/login.js deleted file mode 100644 index 50ed4e9..0000000 --- a/examples/localstack-free/auth-service/src/handlers/login.js +++ /dev/null @@ -1,40 +0,0 @@ -const { PutCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// POST /login — body {user, password}. The demo password is "lss-demo": on a -// match we mint a deterministic session code and persist it so the REQUEST -// authorizer (and the seeded "code-admin") can validate it later. -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return { statusCode: 400, body: JSON.stringify({ error: 'invalid json' }) }; - } - - const { user, password } = payload; - if (!user || !password) { - return { statusCode: 400, body: JSON.stringify({ error: 'user and password are required' }) }; - } - - if (password !== 'lss-demo') { - return { statusCode: 401, body: JSON.stringify({ error: 'invalid credentials' }) }; - } - - const session = { - code: `code-${user}`, - user, - createdAt: new Date().toISOString(), - }; - - await doc.send(new PutCommand({ - TableName: process.env.SESSIONS_TABLE, - Item: session, - })); - - return { - statusCode: 201, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ code: session.code }), - }; -}; diff --git a/examples/localstack-free/auth-service/src/handlers/onUserSignedUp.js b/examples/localstack-free/auth-service/src/handlers/onUserSignedUp.js deleted file mode 100644 index b0f5fe9..0000000 --- a/examples/localstack-free/auth-service/src/handlers/onUserSignedUp.js +++ /dev/null @@ -1,24 +0,0 @@ -const { PutCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// EventBridge target — receives the event exactly as AWS delivers it: -// { version, id, source, "detail-type", detail, ... }. No Records wrapper. -// The event was published by users-service (createUser → PutEvents) onto the -// shared domain-events bus; the rule pattern (source: users, detail-type: -// UserSignedUp) filtered it here. -exports.handler = async (event) => { - console.log(`[onUserSignedUp] ${event.source} → ${event['detail-type']} (${event.id})`); - - await doc.send(new PutCommand({ - TableName: process.env.SIGNUP_AUDIT_TABLE, - Item: { - eventId: event.id, - source: event.source, - detailType: event['detail-type'], - detail: event.detail, - receivedAt: new Date().toISOString(), - }, - })); - - return { stored: event.id }; -}; diff --git a/examples/localstack-free/auth-service/src/handlers/session-authorizer.js b/examples/localstack-free/auth-service/src/handlers/session-authorizer.js deleted file mode 100644 index 024781c..0000000 --- a/examples/localstack-free/auth-service/src/handlers/session-authorizer.js +++ /dev/null @@ -1,47 +0,0 @@ -const { GetCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// v1 REQUEST authorizer (classic IAM-policy response). It has no HTTP events of -// its own: `whoami` references it locally by name, and orders-service references -// it cross-service by ARN. It reads the `code` header, looks the session up in -// DynamoDB, and Allows (with the user in context) or Denies. -exports.handler = async (event) => { - const code = headerValue(event.headers, 'code'); - - if (code) { - const res = await doc.send(new GetCommand({ - TableName: process.env.SESSIONS_TABLE, - Key: { code }, - })); - - if (res.Item) { - return policy(res.Item.user, 'Allow', event.methodArn, { user: res.Item.user }); - } - } - - return policy('anonymous', 'Deny', event.methodArn); -}; - -// Header names may arrive in any casing depending on the client. -function headerValue(headers, name) { - if (!headers) return undefined; - const key = Object.keys(headers).find((k) => k.toLowerCase() === name.toLowerCase()); - return key ? headers[key] : undefined; -} - -function policy(principalId, effect, methodArn, context) { - return { - principalId, - policyDocument: { - Version: '2012-10-17', - Statement: [ - { - Action: 'execute-api:Invoke', - Effect: effect, - Resource: methodArn, - }, - ], - }, - ...(context && { context }), - }; -} diff --git a/examples/localstack-free/auth-service/src/handlers/whoami.js b/examples/localstack-free/auth-service/src/handlers/whoami.js deleted file mode 100644 index 42882bf..0000000 --- a/examples/localstack-free/auth-service/src/handlers/whoami.js +++ /dev/null @@ -1,10 +0,0 @@ -// GET /whoami — protected route. The authorizer's context is surfaced on -// event.requestContext.authorizer, exactly as API Gateway v1 does. -exports.handler = async (event) => { - const authorizer = (event.requestContext && event.requestContext.authorizer) || {}; - return { - statusCode: 200, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ user: authorizer.user }), - }; -}; diff --git a/examples/localstack-free/events-stack/package-lock.json b/examples/localstack-free/events-stack/package-lock.json deleted file mode 100644 index 3c63cf7..0000000 --- a/examples/localstack-free/events-stack/package-lock.json +++ /dev/null @@ -1,2600 +0,0 @@ -{ - "name": "events-stack-example", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "events-stack-example", - "version": "0.0.0", - "devDependencies": { - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } - }, - "../../../packages/serverless-plugin": { - "name": "serverless-lss", - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "devDependencies": { - "@types/node": "^22.10.5", - "typescript": "^5.7.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "osls": "4.0.0" - }, - "peerDependenciesMeta": { - "osls": { - "optional": true - } - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.5.0.tgz", - "integrity": "sha512-Ps4w0FwrDoeVK6hfYxWkVbkmxm+zN+6xoXF2ZfEhfiox0ZNbcSAiUWO6iAIvP5bc3DB270r+EaKcoT1IUyzfxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@types/json-schema": "^7.0.15" - } - }, - "node_modules/@aws-sdk/checksums": { - "version": "3.1000.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.16.tgz", - "integrity": "sha512-EKnvkXSmz3IpA99tCNuI+dLFXyZyClSm8zns9sB/elvkU+MTuomAs6toJMPMBf98/fICG/urXDkzGz0/c3yyAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-api-gateway": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.1084.0.tgz", - "integrity": "sha512-s1mobnnLqhOBdfvzyzj4U0DFY1QXFIPL0fmp3nOvD1EQHO6MQ8uNLS8T0Gu0T4XSIYAaViVNf3dmw+MdsmZSxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/middleware-sdk-api-gateway": "^3.972.22", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-apigatewayv2": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewayv2/-/client-apigatewayv2-3.1085.0.tgz", - "integrity": "sha512-IeDwKOit9IndGVNOcEAAIxwj5z+YhX4aGVNXU+C0sZvALnSOI83rGMekPGxGrZf6tDxpmwtIrSm6qYWPbFkNXA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.1084.0.tgz", - "integrity": "sha512-fqDbUG9CLSXmsLT3rRSQbOfFKf1XjP8AQklal5kCT0knvaYOer/rQZsFCRAdOknTIbn6diL5ezl4VCxLCirV5g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.1085.0.tgz", - "integrity": "sha512-2WyjUH6zdRvPSvL/8JJYo6BJfK4hNn9RA3+3XEfPczQ/uYxhFfIR8hbNIrRQe7ffb9X8CCxN6YpSQtw8iXQboA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/middleware-compression": "^4.5.7", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1085.0.tgz", - "integrity": "sha512-jNMt5zMsnJ6X0fZJKKNU5/qTQ98OIsUSFLqDh+FTXQTiEI3NTq95gAdsaAwXVWO9hTaT5gY7fbwF5Ally69bwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1081.0.tgz", - "integrity": "sha512-ipDgvZ3Hy8kaFrkwj62yuoghKkZi5WrWTiJnaqGc/ntbuAuijIkRWhzSb8d1MGEE+qb+vFFTrWVFwGSqt76TCA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity-provider": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.1084.0.tgz", - "integrity": "sha512-AvXtywh7kuZ6S5ChXz1BZNZDrlQLCEWGTVGdy+EZN6iXCT4LImoMR2JY+6ZB2LSSuQhbhTMGnv5d3Mp3Zm3ArQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ecr": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.1085.0.tgz", - "integrity": "sha512-I1MWQNb01MlfC2MENTll+GrRV2RSGmkQSyB289CEY2QGf4ImqeEsySWFtpau/39zqTxqOyx/jfXrT5vdr3hOyQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-eventbridge": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-eventbridge/-/client-eventbridge-3.1084.0.tgz", - "integrity": "sha512-DjUKojU5G+HGGrS5GhmVfKvfESb6xfSuch77Sn0kemcWtUNG7vXr5FCmCXAxSYTws5pEWkIWb7e056RKCGRvig==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-iam": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.1084.0.tgz", - "integrity": "sha512-ztGhGwyTT6Mn4EeRKJ1k0Zy1kcvW/aNAmaIMME7DokfK8WSL7pOt5gUQlbT7N44/66I1doXpyCtib3i9oiQ3rA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1084.0.tgz", - "integrity": "sha512-4sc5dyO/nItSnsrTj2tE2LE8X2zG6UjYvNmiin+oSR8AcIouazAcH5sIJYS9Mv2vjOGL2w2g7LbvT3R3ZH69zg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1085.0.tgz", - "integrity": "sha512-O0xe8sR50AYkwxlvRRsV0qytEO2dtXQTQ1CF3YBBdE5xtVkbu27H0vGa1mjQi1/+fbYM80AWEIPai5jZmXyubw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/checksums": "^3.1000.16", - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/middleware-sdk-s3": "^3.972.62", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1085.0.tgz", - "integrity": "sha512-vFYFncOReqEtOj110hdTQK/4JzNEHdVR90Ob6FjdEeb8cNer+HShI64Nuw9J4gTUQAWJ0eErHZqqxQPTViplew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.1084.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1084.0.tgz", - "integrity": "sha512-Mr3MPmvARQxa7NjUtCeRasFEk4tzHaKn7MIMXr9enzye9kNXArnfd5pxE+2kbq16E+gKEWe1ohBFUFGaeKvtcA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.975.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.975.1.tgz", - "integrity": "sha512-8qh/6EYb7hl/ZwVfQufhbMEZs1gQIc7GbdrIf4eprQJ7cv042+74nE6l3YDfyWNzb9iPXb8fRyYSHkNIk5eE6Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@aws-sdk/xml-builder": "^3.972.34", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.29.2", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.56", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.56.tgz", - "integrity": "sha512-nedaZz6Wz2FGUBMsWhlvBPGIkTMfRuMJ99YDHJI4CaC31JS8WPyTavEAio74cfd5nGhi0A8XASB4fZA5VqTdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.57.tgz", - "integrity": "sha512-1RfJaF7SW1TOnvNGU7kaYjwUf5H3sfm+synGH1bHhRlqcnxCt3szebH3dmKEyY4tuGcbQ6ffzUT89cRitBV8OQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.59", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.59.tgz", - "integrity": "sha512-sRCkpTiFnCdQvuaRVjQ6SVoHu6i7RUpurVo1c4F81HWhPvUJ7Wdp5MNtSdX1O29CNXc8em3O5m52hCjVtAD9SA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.1.tgz", - "integrity": "sha512-6d8H6ZAh3ZPKZ6fe1nG2OWeZEZPtt9ravoD1dezPdPtsSkJRoxGAnFSHwKT3E/Te6fHE30zRzjV6TD12rvF6yQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-login": "^3.972.63", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.63.tgz", - "integrity": "sha512-GREWRrMj0XnNKMaVa/Mauoaui26qBEHu71WWqXbwZOu/jFQOnPZjTf7u0KtGKC8VGa6VUs9kDWGgocrKNLS9vw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.66", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.66.tgz", - "integrity": "sha512-f+qjRXZpz7sgzbc4QB+6nLKfyKFgRRXzWdXbsKPv/VhVRyHsDyq4yBWC/B75BAJpFIcUeI2XR/3gdWJ677zB4A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-ini": "^3.973.1", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.57.tgz", - "integrity": "sha512-TiVQhuU0pbhIZAUZacbPHMyzrIdiH+lnx+PMY/Pu/b93dJrq3wdZwzUJ0TPpvNxaqbHsxJvQZW3/h/beLiKq7Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.1.tgz", - "integrity": "sha512-3foTZUJ4821Ij60X7K3NJroygiZLnbBmarN+T//O2cjkISan90zElN3NBmgSlDrTQ7Gs6z/yO8V7h60QNcDZHQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/token-providers": "3.1083.0", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.63.tgz", - "integrity": "sha512-8qZLFhM69eKcS37m459ctPR05Qimycm/74OPVioe6wNZabMT54GYhwBju0+J656RkMasNSawWQu+c8CmBe3TUQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1081.0.tgz", - "integrity": "sha512-UHWvxd1F5nfBXBRXtQaXWoNT8CYKXZovLQOyz6XZlgFTGc2mWzzPGspOfnh49jwvB2qzsdH046i9jnnmND+64w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.1081.0", - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.54", - "@aws-sdk/credential-provider-env": "^3.972.55", - "@aws-sdk/credential-provider-http": "^3.972.57", - "@aws-sdk/credential-provider-ini": "^3.972.62", - "@aws-sdk/credential-provider-login": "^3.972.61", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/credential-provider-process": "^3.972.55", - "@aws-sdk/credential-provider-sso": "^3.972.61", - "@aws-sdk/credential-provider-web-identity": "^3.972.61", - "@aws-sdk/nested-clients": "^3.997.29", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/credential-provider-imds": "^4.4.5", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/lib-storage": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1085.0.tgz", - "integrity": "sha512-S+yCGIMxQ5Zs2A5ZDdYfXwOxu5kKjBaCQVOxp6+mnwCQYXUNkBD/aKCnW1eniMTavzz3YidhD5eTFpDlcUv2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.1085.0" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/@aws-sdk/middleware-sdk-api-gateway": { - "version": "3.972.22", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-api-gateway/-/middleware-sdk-api-gateway-3.972.22.tgz", - "integrity": "sha512-syOvziZ3GmBN2bbxQV8xPIobZu9s4rbg2BF+I8nf84pmWc8hy04FquqvIS91qto4v2ywdoiFx7COyzfRWAh0MA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.62", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.62.tgz", - "integrity": "sha512-k8JJwYXVYlOOjWnPZDThQS1xDFJgi5Dokt73qFlDtrZAbdcint5aIdjB9XgJAAQVP5OoqcefQmh1FYXiPpvsvw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.31.tgz", - "integrity": "sha512-BDHTpwcsZHEBNEJzOg/B1BkFYJxAXY50dau/NyVWs3d51F0WgIUGSWZot/Os+N3KpDhXeaXnz37mWffAvduREw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.39.tgz", - "integrity": "sha512-8+srXqYIF8KYMLC4FxMLEM5Ek7kUNibJu1R4m8/fUhhNYIZZz26oGtKkCr8I/HiG2fFQxBvaGgQZT4/mqRCSnA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1083.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1083.0.tgz", - "integrity": "sha512-s0woKnxuHrExLc5L2ArIH5BMkbonHPtt+5hSBM8oknp9M6QTuUmmAmJ2E0EdzCGONrO+8+ADPqvv6UX0nNcc7A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.0.tgz", - "integrity": "sha512-QIBrw90CDm4O0UaIIzkU6DrFdeJzEb2Va5EPEVpyldj6sHJxB6cshhStJuhZxk3wR3PmjJlYsjPmY1kNb+KGBg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.34.tgz", - "integrity": "sha512-wHhWL1y7sN3enBA8POrPpQM5jCcmu2ozyhbRei4c8OjVcEaEs6yLucLa/pla457ggS/ysuy7bosagz3HaJkZXA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@smithy/core": { - "version": "3.29.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.3.tgz", - "integrity": "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.7.tgz", - "integrity": "sha512-UEMLOoA0Fl4uYBxh6l0uN0H6EJe/A89OGeDNTteQeXpJ20BcpfIr4wlCY9pel1jEAUHAxaYwuqrYlrKdXE1GKQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.4.tgz", - "integrity": "sha512-psnst7NZWdAEvJvyW8YZEE7xNVMyLrQFfHtyrVFrxNyy+dKWkQ+rqC6oI5ZhxThpUy9RSfEshgm34zqbOxzsRw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-compression": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-compression/-/middleware-compression-4.5.8.tgz", - "integrity": "sha512-ODHXD5tDW3+25pfiLjJ2ZTIHRfWWxqVGPqIMz1NjmiV4bG4i1S0kuibHxik6WXibR03nmDGMiI1/hF6647F/Zg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "fflate": "0.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.4.tgz", - "integrity": "sha512-BNTop/fSOptmoVk8g+efwHCofFh37g70OWGAFES1TeAAJja1K5aAI8rTE26ETSc5k8IQuWY2kAIoPla01NgYrA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.3.tgz", - "integrity": "sha512-8qVKKzqh7naF27ePmx0SkUfnGP/wBI9dyaeAmhHvopnbIlItUAmB/e6PkPCU3rRb2v9BY8D4EZXSoydSibatvw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", - "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-sprintf-format/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-sprintf-format/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", - "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-cycle": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", - "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/log": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.2.tgz", - "integrity": "sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "duration": "^0.2.2", - "es5-ext": "^0.10.64", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.2", - "type": "^2.7.3", - "uni-global": "^1.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "peerDependencies": { - "log": "^6.0.0" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/osls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/osls/-/osls-4.0.0.tgz", - "integrity": "sha512-ti1s4IhJLfpdWtgyb3gj8slDs1KoucRU0jNyqGIaEGPGCODiJtFXXVM3cs52pQLi3Ig2RBeqHzhD84vWOLvSeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", - "@aws-sdk/client-api-gateway": "^3.1034.0", - "@aws-sdk/client-apigatewayv2": "^3.1034.0", - "@aws-sdk/client-cloudformation": "^3.1034.0", - "@aws-sdk/client-cloudwatch": "^3.1034.0", - "@aws-sdk/client-cloudwatch-logs": "^3.1034.0", - "@aws-sdk/client-cognito-identity-provider": "^3.1034.0", - "@aws-sdk/client-ecr": "^3.1034.0", - "@aws-sdk/client-eventbridge": "^3.1034.0", - "@aws-sdk/client-iam": "^3.1034.0", - "@aws-sdk/client-lambda": "^3.1034.0", - "@aws-sdk/client-s3": "^3.1034.0", - "@aws-sdk/client-ssm": "^3.1034.0", - "@aws-sdk/client-sts": "^3.1034.0", - "@aws-sdk/credential-providers": "^3.1034.0", - "@aws-sdk/lib-storage": "^3.1034.0", - "@smithy/core": "^3.23.16", - "@smithy/node-http-handler": "^4.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "content-disposition": "^2.0.1", - "cross-spawn": "^7.0.6", - "dotenv": "^17.4.2", - "dotenv-expand": "^13.0.0", - "ext": "^1.7.0", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "filenamify": "^7.0.1", - "https-proxy-agent": "^9.0.0", - "js-yaml": "^4.3.0", - "json-cycle": "^1.5.0", - "log": "^6.3.1", - "log-node": "^8.0.3", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "mime-types": "^3.0.2", - "semver": "^7.5.3", - "signal-exit": "^4.1.0", - "tsx": "^4.20.3", - "type": "^2.7.2", - "undici": "^7.25.0", - "write-file-atomic": "^7.0.1", - "yauzl": "^3.3.0", - "yazl": "^3.3.1" - }, - "bin": { - "osls": "bin/serverless.js", - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/osls/node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/osls/node_modules/content-disposition": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", - "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/osls/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/dotenv-expand": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", - "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^17.4.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/filename-reserved-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", - "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/filenamify": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.2.tgz", - "integrity": "sha512-fz10TUqSZ1lG7ftW1KnRotJzMD8YRb6kaAQKpZJBLvqXXfFgIEpuazy1w2lK3zhMiBSdH/uF9LFlv5smJ2Jl1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "filename-reserved-regex": "^4.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/https-proxy-agent": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", - "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "proxy-agent-negotiate": "1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/osls/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/osls/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/osls/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/osls/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/osls/node_modules/write-file-atomic": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", - "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", - "dev": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/osls/node_modules/yauzl": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", - "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proxy-agent-negotiate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", - "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "kerberos": "^2.0.0" - }, - "peerDependenciesMeta": { - "kerberos": { - "optional": true - } - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serverless-lss": { - "resolved": "../../../packages/serverless-plugin", - "link": true - }, - "node_modules/sprintf-kit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz", - "integrity": "sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", - "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/yazl": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-3.3.1.tgz", - "integrity": "sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "^1.0.0" - } - }, - "node_modules/yazl/node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - } - } -} diff --git a/examples/localstack-free/events-stack/package.json b/examples/localstack-free/events-stack/package.json deleted file mode 100644 index 7a8ac9d..0000000 --- a/examples/localstack-free/events-stack/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "events-stack-example", - "version": "0.0.0", - "private": true, - "description": "Resources-only stack owning the shared EventBridge bus (domain-events). No functions, no ports — registering it just provisions the bus in LocalStack.", - "scripts": { - "package": "serverless package", - "register": "serverless package" - }, - "devDependencies": { - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } -} diff --git a/examples/localstack-free/events-stack/serverless.yml b/examples/localstack-free/events-stack/serverless.yml deleted file mode 100644 index 4bc74e3..0000000 --- a/examples/localstack-free/events-stack/serverless.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Resources-only stack: no functions, no ports. It exists purely to own the -# shared EventBridge bus — the piece that previously forced a real -# `serverless deploy` (CloudFormation) before LSS could cover the rest. -service: events-stack - -frameworkVersion: '>=3' - -provider: - name: aws - runtime: nodejs20.x - region: sa-east-1 - stage: dev - -plugins: - - serverless-lss - -custom: - orchestrator: - enabled: true - orchestratorUrl: http://localhost:3120 - -resources: - Resources: - DomainEventsBus: - Type: AWS::Events::EventBus - Properties: - Name: domain-events - - # LSS accepts Archives but skips them with a registration warning: - # LocalStack mocks the API (CREATE_COMPLETE, yet ListArchives stays empty), - # so provisioning one locally would only fake success. - DomainEventsArchive: - Type: AWS::Events::Archive - Properties: - ArchiveName: domain-events-archive - SourceArn: !GetAtt DomainEventsBus.Arn - RetentionDays: 1 diff --git a/examples/localstack-free/index.html b/examples/localstack-free/index.html deleted file mode 100644 index ccc74eb..0000000 --- a/examples/localstack-free/index.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - - -localstack-free · validation console - - - -
- -
-

localstack-free

-

LocalStack Community on LSS — authorizers, EventBridge bus, DynamoDB streams → SNS, S3 notifications

-
- -
-
-
-

Status

-
-
-
-

Flows

-
-
-
-

Request log

-
-
-
-
Generated for the LSS example "localstack-free" — open this file directly or via npm run console.
- - - diff --git a/examples/localstack-free/lss.config.json b/examples/localstack-free/lss.config.json deleted file mode 100644 index 6c042fe..0000000 --- a/examples/localstack-free/lss.config.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "serverPort": 3120, - "localstackPort": 4572, - "localstackEndpoint": "http://localhost:4572", - "mode": "managed", - "localstackEdition": "community", - "localstackVersion": "4.0", - "region": "sa-east-1", - "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], - "persistence": false, - "debug": false, - "seedsDir": "./seeds", - "stateDir": ".lss", - "autoPackage": true, - "lambdaRuntime": { - "enabled": true, - "execution": "source", - "watch": true - }, - "branding": { - "title": "LocalStack Free Sandbox", - "subtitle": "LSS + LocalStack Community — full event-driven stack", - "logo": "./assets/logo.svg", - "favicon": "./assets/logo.svg", - "defaultTheme": "dark", - "colors": { - "brand-primary": "#7c3aed", - "brand-hover": "#6d28d9", - "brand-soft": "#ede9fe" - } - } -} diff --git a/examples/localstack-free/orders-service/package-lock.json b/examples/localstack-free/orders-service/package-lock.json deleted file mode 100644 index 96789d7..0000000 --- a/examples/localstack-free/orders-service/package-lock.json +++ /dev/null @@ -1,2800 +0,0 @@ -{ - "name": "orders-service-example", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "orders-service-example", - "version": "0.0.0", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.0.0", - "@aws-sdk/client-s3": "^3.0.0", - "@aws-sdk/client-sns": "^3.0.0", - "@aws-sdk/client-sqs": "^3.0.0", - "@aws-sdk/lib-dynamodb": "^3.0.0", - "@aws-sdk/util-dynamodb": "^3.0.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } - }, - "../../../packages/serverless-plugin": { - "name": "serverless-lss", - "version": "0.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "devDependencies": { - "@types/node": "^22.10.5", - "typescript": "^5.7.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "osls": "4.0.0" - }, - "peerDependenciesMeta": { - "osls": { - "optional": true - } - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.5.0.tgz", - "integrity": "sha512-Ps4w0FwrDoeVK6hfYxWkVbkmxm+zN+6xoXF2ZfEhfiox0ZNbcSAiUWO6iAIvP5bc3DB270r+EaKcoT1IUyzfxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@types/json-schema": "^7.0.15" - } - }, - "node_modules/@aws-sdk/checksums": { - "version": "3.1000.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.16.tgz", - "integrity": "sha512-EKnvkXSmz3IpA99tCNuI+dLFXyZyClSm8zns9sB/elvkU+MTuomAs6toJMPMBf98/fICG/urXDkzGz0/c3yyAQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-api-gateway": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.1081.0.tgz", - "integrity": "sha512-uKUrTUNc0VaVMslK/vJ6qg4LBnynHnvb9pu7gLtFe06+g4rT2IseJWed6xrdfa0t8iSW00rrLoTVbHNEukjETg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/middleware-sdk-api-gateway": "^3.972.21", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-apigatewayv2": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewayv2/-/client-apigatewayv2-3.1085.0.tgz", - "integrity": "sha512-IeDwKOit9IndGVNOcEAAIxwj5z+YhX4aGVNXU+C0sZvALnSOI83rGMekPGxGrZf6tDxpmwtIrSm6qYWPbFkNXA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.1081.0.tgz", - "integrity": "sha512-i+lK0BnbX8JdFI/7HV/JY6XmrZsEmmLffuJRyn+J+gP9zzAiNOdraOnMi0eVcJE8CraTt5fixyxBO8AalFW8rw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.1085.0.tgz", - "integrity": "sha512-2WyjUH6zdRvPSvL/8JJYo6BJfK4hNn9RA3+3XEfPczQ/uYxhFfIR8hbNIrRQe7ffb9X8CCxN6YpSQtw8iXQboA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/middleware-compression": "^4.5.7", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1085.0.tgz", - "integrity": "sha512-jNMt5zMsnJ6X0fZJKKNU5/qTQ98OIsUSFLqDh+FTXQTiEI3NTq95gAdsaAwXVWO9hTaT5gY7fbwF5Ally69bwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1081.0.tgz", - "integrity": "sha512-ipDgvZ3Hy8kaFrkwj62yuoghKkZi5WrWTiJnaqGc/ntbuAuijIkRWhzSb8d1MGEE+qb+vFFTrWVFwGSqt76TCA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity-provider": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.1081.0.tgz", - "integrity": "sha512-uBvMQ2gLiNphTjmZKHz0WAq4mESC9OCngmzE4FJSVnm6bjUZMWSBU4rJCEjYh/gzZ5BLRk1TV1BzTdMuU78kFQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1081.0.tgz", - "integrity": "sha512-gQ2XvMVY+5Co6znCODeCuLVaGRPKTeRQ+lATsw4Cm4/v+HHVQ3OJacE3wwO5FRg7shgYswOTusPM5icLEzsv9w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/dynamodb-codec": "^3.973.29", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.22", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ecr": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.1085.0.tgz", - "integrity": "sha512-I1MWQNb01MlfC2MENTll+GrRV2RSGmkQSyB289CEY2QGf4ImqeEsySWFtpau/39zqTxqOyx/jfXrT5vdr3hOyQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-eventbridge": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-eventbridge/-/client-eventbridge-3.1081.0.tgz", - "integrity": "sha512-yfApvz19TIF27sZqnhYr/jGbMF2sg4r0L2HEbKzM+KqLFdqE8um/IDBgbEL++WDr4qtGIRL9OodoyFKbhAfNyg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/signature-v4-multi-region": "^3.996.38", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-iam": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.1081.0.tgz", - "integrity": "sha512-PR9jz6r6+inwSHrdwI9O4Vgolkd6+lTQ+H+YS2s4uyC2J8FGUDMCJO40ycszcvy8o8EWwFS/ACA/HotY+OAHLQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1081.0.tgz", - "integrity": "sha512-DlFiHPVHQsGz+2Zyli25tA4SQW1xPggko/lZMCsFwxzXeTyoW4X+EHkcRul1K7Z/Rf2zpGnwZWS+PWZYTFRaSw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1085.0.tgz", - "integrity": "sha512-O0xe8sR50AYkwxlvRRsV0qytEO2dtXQTQ1CF3YBBdE5xtVkbu27H0vGa1mjQi1/+fbYM80AWEIPai5jZmXyubw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/checksums": "^3.1000.16", - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/middleware-sdk-s3": "^3.972.62", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sns": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.1085.0.tgz", - "integrity": "sha512-F9AOKvav/zv8uukLXSgqG/EQErB/UMEahadT47iWqAWa0FahvxcchnzthN8kECoBCTsUn16N/1+wSvGTgJ9hWQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sqs": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.1081.0.tgz", - "integrity": "sha512-mfUL0RBECAesJTA8JfXcFUg3ve/E6ztSEsewBC3tfuFR3aFAgXOiIqDUmntzQoLxf5LabdAyXv5Uu6seC0jjYQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/middleware-sdk-sqs": "^3.972.34", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1085.0.tgz", - "integrity": "sha512-vFYFncOReqEtOj110hdTQK/4JzNEHdVR90Ob6FjdEeb8cNer+HShI64Nuw9J4gTUQAWJ0eErHZqqxQPTViplew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1081.0.tgz", - "integrity": "sha512-URSoqhxMGf4Mv6MMyR6pcerTjbVKKqKLU7GGpZddxiOJ/Ca1qeUz3hvjuF2m/AMaw3e28bUdMvo7ZDh3aMX/ig==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/signature-v4-multi-region": "^3.996.38", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.975.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.975.1.tgz", - "integrity": "sha512-8qh/6EYb7hl/ZwVfQufhbMEZs1gQIc7GbdrIf4eprQJ7cv042+74nE6l3YDfyWNzb9iPXb8fRyYSHkNIk5eE6Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@aws-sdk/xml-builder": "^3.972.34", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.29.2", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.56", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.56.tgz", - "integrity": "sha512-nedaZz6Wz2FGUBMsWhlvBPGIkTMfRuMJ99YDHJI4CaC31JS8WPyTavEAio74cfd5nGhi0A8XASB4fZA5VqTdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.57.tgz", - "integrity": "sha512-1RfJaF7SW1TOnvNGU7kaYjwUf5H3sfm+synGH1bHhRlqcnxCt3szebH3dmKEyY4tuGcbQ6ffzUT89cRitBV8OQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.59", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.59.tgz", - "integrity": "sha512-sRCkpTiFnCdQvuaRVjQ6SVoHu6i7RUpurVo1c4F81HWhPvUJ7Wdp5MNtSdX1O29CNXc8em3O5m52hCjVtAD9SA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.1.tgz", - "integrity": "sha512-6d8H6ZAh3ZPKZ6fe1nG2OWeZEZPtt9ravoD1dezPdPtsSkJRoxGAnFSHwKT3E/Te6fHE30zRzjV6TD12rvF6yQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-login": "^3.972.63", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.63.tgz", - "integrity": "sha512-GREWRrMj0XnNKMaVa/Mauoaui26qBEHu71WWqXbwZOu/jFQOnPZjTf7u0KtGKC8VGa6VUs9kDWGgocrKNLS9vw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.66", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.66.tgz", - "integrity": "sha512-f+qjRXZpz7sgzbc4QB+6nLKfyKFgRRXzWdXbsKPv/VhVRyHsDyq4yBWC/B75BAJpFIcUeI2XR/3gdWJ677zB4A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-ini": "^3.973.1", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.57.tgz", - "integrity": "sha512-TiVQhuU0pbhIZAUZacbPHMyzrIdiH+lnx+PMY/Pu/b93dJrq3wdZwzUJ0TPpvNxaqbHsxJvQZW3/h/beLiKq7Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.1.tgz", - "integrity": "sha512-3foTZUJ4821Ij60X7K3NJroygiZLnbBmarN+T//O2cjkISan90zElN3NBmgSlDrTQ7Gs6z/yO8V7h60QNcDZHQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/token-providers": "3.1083.0", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.63.tgz", - "integrity": "sha512-8qZLFhM69eKcS37m459ctPR05Qimycm/74OPVioe6wNZabMT54GYhwBju0+J656RkMasNSawWQu+c8CmBe3TUQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1081.0.tgz", - "integrity": "sha512-UHWvxd1F5nfBXBRXtQaXWoNT8CYKXZovLQOyz6XZlgFTGc2mWzzPGspOfnh49jwvB2qzsdH046i9jnnmND+64w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.1081.0", - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.54", - "@aws-sdk/credential-provider-env": "^3.972.55", - "@aws-sdk/credential-provider-http": "^3.972.57", - "@aws-sdk/credential-provider-ini": "^3.972.62", - "@aws-sdk/credential-provider-login": "^3.972.61", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/credential-provider-process": "^3.972.55", - "@aws-sdk/credential-provider-sso": "^3.972.61", - "@aws-sdk/credential-provider-web-identity": "^3.972.61", - "@aws-sdk/nested-clients": "^3.997.29", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/credential-provider-imds": "^4.4.5", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.29", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.29.tgz", - "integrity": "sha512-1Eprv8BD2cOsVccCpEGm+hyZzj3LjthLoDOXHuvH6Vz8GJPZWknrmn05kICyZpx7srfe/KOm4GQXrJgXkPUJuA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.8.tgz", - "integrity": "sha512-bBmkG0Dnhfq0/T4Z0PpUr7HkncBVaWvvCbvafeaUM+yC9wa8GGjLJmonq0QL17REB9WivgGeYgWQ5A80Uw5UnQ==", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.1081.0.tgz", - "integrity": "sha512-o9hjLKJBhjspX52P9vIngEsr12YNyBzfiVbmPHQhrgOEN3BGZjd0wa9ufRzHF2jygFZak66dlPx5AeK+4qI/eg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/util-dynamodb": "^3.996.5", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1081.0" - } - }, - "node_modules/@aws-sdk/lib-storage": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1085.0.tgz", - "integrity": "sha512-S+yCGIMxQ5Zs2A5ZDdYfXwOxu5kKjBaCQVOxp6+mnwCQYXUNkBD/aKCnW1eniMTavzz3YidhD5eTFpDlcUv2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.1085.0" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.22", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.22.tgz", - "integrity": "sha512-GMoLg4XAnkiwevqcOfgz0lOTYmIdM7MJK/BL9EAvsoMFqKIGRpyNIvuSNg5gdFzP57yB+EklMlK0+TwBqj1tCg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.8", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-api-gateway": { - "version": "3.972.21", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-api-gateway/-/middleware-sdk-api-gateway-3.972.21.tgz", - "integrity": "sha512-tlu8JAcbrhh4jnoQXczWQ2QIOaev3ZdVBdU4RRaNBfJmVyuBbMKdh6mdrunEdSFgm2GlJW1lIhE4BHTL0A55dw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.62", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.62.tgz", - "integrity": "sha512-k8JJwYXVYlOOjWnPZDThQS1xDFJgi5Dokt73qFlDtrZAbdcint5aIdjB9XgJAAQVP5OoqcefQmh1FYXiPpvsvw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-sqs": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.972.34.tgz", - "integrity": "sha512-BgCMs873RWtMe8LlNY5hxJjVbZtaHR6nY3BtQZk14drRJb3Iqecp5VADpw3eF5cnBvlZLWblAjCjJFU1mTjoeQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.31.tgz", - "integrity": "sha512-BDHTpwcsZHEBNEJzOg/B1BkFYJxAXY50dau/NyVWs3d51F0WgIUGSWZot/Os+N3KpDhXeaXnz37mWffAvduREw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.39.tgz", - "integrity": "sha512-8+srXqYIF8KYMLC4FxMLEM5Ek7kUNibJu1R4m8/fUhhNYIZZz26oGtKkCr8I/HiG2fFQxBvaGgQZT4/mqRCSnA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1083.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1083.0.tgz", - "integrity": "sha512-s0woKnxuHrExLc5L2ArIH5BMkbonHPtt+5hSBM8oknp9M6QTuUmmAmJ2E0EdzCGONrO+8+ADPqvv6UX0nNcc7A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.0.tgz", - "integrity": "sha512-QIBrw90CDm4O0UaIIzkU6DrFdeJzEb2Va5EPEVpyldj6sHJxB6cshhStJuhZxk3wR3PmjJlYsjPmY1kNb+KGBg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.996.5.tgz", - "integrity": "sha512-m9bdmYq3WtbMHAKGALw9XWiMBfKu5T8ukgdJT7Mc/d2oOwDGNFmhsnnkQ18xomoXo/ZHxAuIDi3Y6slsblW1Mg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1069.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.34.tgz", - "integrity": "sha512-wHhWL1y7sN3enBA8POrPpQM5jCcmu2ozyhbRei4c8OjVcEaEs6yLucLa/pla457ggS/ysuy7bosagz3HaJkZXA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@smithy/core": { - "version": "3.29.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.3.tgz", - "integrity": "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.7.tgz", - "integrity": "sha512-UEMLOoA0Fl4uYBxh6l0uN0H6EJe/A89OGeDNTteQeXpJ20BcpfIr4wlCY9pel1jEAUHAxaYwuqrYlrKdXE1GKQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.4.tgz", - "integrity": "sha512-psnst7NZWdAEvJvyW8YZEE7xNVMyLrQFfHtyrVFrxNyy+dKWkQ+rqC6oI5ZhxThpUy9RSfEshgm34zqbOxzsRw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-compression": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-compression/-/middleware-compression-4.5.8.tgz", - "integrity": "sha512-ODHXD5tDW3+25pfiLjJ2ZTIHRfWWxqVGPqIMz1NjmiV4bG4i1S0kuibHxik6WXibR03nmDGMiI1/hF6647F/Zg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "fflate": "0.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.4.tgz", - "integrity": "sha512-BNTop/fSOptmoVk8g+efwHCofFh37g70OWGAFES1TeAAJja1K5aAI8rTE26ETSc5k8IQuWY2kAIoPla01NgYrA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.3.tgz", - "integrity": "sha512-8qVKKzqh7naF27ePmx0SkUfnGP/wBI9dyaeAmhHvopnbIlItUAmB/e6PkPCU3rRb2v9BY8D4EZXSoydSibatvw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", - "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-sprintf-format/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-sprintf-format/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-cli": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.4.4.tgz", - "integrity": "sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "dotenv": "^16.3.0", - "dotenv-expand": "^10.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", - "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-cycle": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", - "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/log": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.2.tgz", - "integrity": "sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "duration": "^0.2.2", - "es5-ext": "^0.10.64", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.2", - "type": "^2.7.3", - "uni-global": "^1.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "peerDependencies": { - "log": "^6.0.0" - } - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mnemonist": { - "version": "0.38.3", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", - "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", - "license": "MIT", - "dependencies": { - "obliterator": "^1.6.1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/obliterator": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", - "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", - "license": "MIT" - }, - "node_modules/osls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/osls/-/osls-4.0.0.tgz", - "integrity": "sha512-ti1s4IhJLfpdWtgyb3gj8slDs1KoucRU0jNyqGIaEGPGCODiJtFXXVM3cs52pQLi3Ig2RBeqHzhD84vWOLvSeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", - "@aws-sdk/client-api-gateway": "^3.1034.0", - "@aws-sdk/client-apigatewayv2": "^3.1034.0", - "@aws-sdk/client-cloudformation": "^3.1034.0", - "@aws-sdk/client-cloudwatch": "^3.1034.0", - "@aws-sdk/client-cloudwatch-logs": "^3.1034.0", - "@aws-sdk/client-cognito-identity-provider": "^3.1034.0", - "@aws-sdk/client-ecr": "^3.1034.0", - "@aws-sdk/client-eventbridge": "^3.1034.0", - "@aws-sdk/client-iam": "^3.1034.0", - "@aws-sdk/client-lambda": "^3.1034.0", - "@aws-sdk/client-s3": "^3.1034.0", - "@aws-sdk/client-ssm": "^3.1034.0", - "@aws-sdk/client-sts": "^3.1034.0", - "@aws-sdk/credential-providers": "^3.1034.0", - "@aws-sdk/lib-storage": "^3.1034.0", - "@smithy/core": "^3.23.16", - "@smithy/node-http-handler": "^4.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "content-disposition": "^2.0.1", - "cross-spawn": "^7.0.6", - "dotenv": "^17.4.2", - "dotenv-expand": "^13.0.0", - "ext": "^1.7.0", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "filenamify": "^7.0.1", - "https-proxy-agent": "^9.0.0", - "js-yaml": "^4.3.0", - "json-cycle": "^1.5.0", - "log": "^6.3.1", - "log-node": "^8.0.3", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "mime-types": "^3.0.2", - "semver": "^7.5.3", - "signal-exit": "^4.1.0", - "tsx": "^4.20.3", - "type": "^2.7.2", - "undici": "^7.25.0", - "write-file-atomic": "^7.0.1", - "yauzl": "^3.3.0", - "yazl": "^3.3.1" - }, - "bin": { - "osls": "bin/serverless.js", - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/osls/node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/osls/node_modules/content-disposition": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", - "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/dotenv-expand": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", - "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^17.4.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/filename-reserved-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", - "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/filenamify": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.2.tgz", - "integrity": "sha512-fz10TUqSZ1lG7ftW1KnRotJzMD8YRb6kaAQKpZJBLvqXXfFgIEpuazy1w2lK3zhMiBSdH/uF9LFlv5smJ2Jl1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "filename-reserved-regex": "^4.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/osls/node_modules/https-proxy-agent": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", - "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "proxy-agent-negotiate": "1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/osls/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/osls/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/osls/node_modules/write-file-atomic": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", - "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", - "dev": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/osls/node_modules/yauzl": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", - "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/proxy-agent-negotiate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", - "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "kerberos": "^2.0.0" - }, - "peerDependenciesMeta": { - "kerberos": { - "optional": true - } - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serverless-lss": { - "resolved": "../../../packages/serverless-plugin", - "link": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-kit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz", - "integrity": "sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", - "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/yazl": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-3.3.1.tgz", - "integrity": "sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "^1.0.0" - } - }, - "node_modules/yazl/node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - } - } -} diff --git a/examples/localstack-free/orders-service/package.json b/examples/localstack-free/orders-service/package.json deleted file mode 100644 index 5916fd9..0000000 --- a/examples/localstack-free/orders-service/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "orders-service-example", - "version": "0.0.0", - "private": true, - "description": "JavaScript REST API (payload v1) guarded by auth-service's authorizer (cross-service, by ARN), with an SQS consumer, a scheduled cleanup Lambda, a DynamoDB stream → SNS fan-out, and an S3 upload bucket with a notification-triggered Lambda. Port 3612 (invoke 13612).", - "scripts": { - "package": "serverless package", - "register": "serverless package" - }, - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.0.0", - "@aws-sdk/client-s3": "^3.0.0", - "@aws-sdk/client-sns": "^3.0.0", - "@aws-sdk/client-sqs": "^3.0.0", - "@aws-sdk/lib-dynamodb": "^3.0.0", - "@aws-sdk/util-dynamodb": "^3.0.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "osls": "4.0.0", - "serverless-lss": "file:../../../packages/serverless-plugin" - } -} diff --git a/examples/localstack-free/orders-service/serverless.yml b/examples/localstack-free/orders-service/serverless.yml deleted file mode 100644 index ac3ef19..0000000 --- a/examples/localstack-free/orders-service/serverless.yml +++ /dev/null @@ -1,167 +0,0 @@ -service: orders-service - -frameworkVersion: '>=3' - -provider: - name: aws - runtime: nodejs20.x - region: sa-east-1 - stage: dev - environment: - ORDERS_TABLE: orders-Orders - ORDER_QUEUE_URL: http://localhost:4572/000000000000/orders-OrderQueue - ORDER_EVENTS_TOPIC_ARN: arn:aws:sns:${self:provider.region}:${self:custom.accountId}:orders-OrderEvents - UPLOADS_BUCKET: orders-uploads - AWS_ENDPOINT: http://localhost:4572 - -plugins: - - serverless-lss - -custom: - accountId: '000000000000' - orchestrator: - enabled: true - orchestratorUrl: http://localhost:3120 - lss: - apiPort: 3612 - invokePort: 13612 - -functions: - # POST /orders — protected by a CROSS-SERVICE authorizer: the Lambda behind - # the ARN lives in auth-service. LSS resolves the ARN against its global - # function registry, so one authorizer can guard many services. - createOrder: - handler: src/handlers/createOrder.handler - events: - - http: - path: /orders - method: post - cors: true - authorizer: - name: sessionAuthorizer - arn: arn:aws:lambda:${self:provider.region}:${self:custom.accountId}:function:auth-service-${self:provider.stage}-sessionAuthorizer - type: request - identitySource: method.request.header.code - resultTtlInSeconds: 3600 - - listOrders: - handler: src/handlers/listOrders.handler - events: - - http: - path: /orders - method: get - cors: true - authorizer: - name: sessionAuthorizer - arn: arn:aws:lambda:${self:provider.region}:${self:custom.accountId}:function:auth-service-${self:provider.stage}-sessionAuthorizer - type: request - identitySource: method.request.header.code - resultTtlInSeconds: 3600 - - # SQS consumer — LSS provisions the queue in LocalStack and pipes messages to - # the runtime worker, no serverless-offline involved. - processOrderQueue: - handler: src/handlers/processOrderQueue.handler - events: - - sqs: - arn: - Fn::GetAtt: - - OrderQueue - - Arn - batchSize: 5 - - # Schedule trigger emulation is a documented TODO — LSS still registers the - # function, so it is invocable through the Lambda Invoke API on port 13612. - cleanupExpiredOrders: - handler: src/handlers/cleanupExpiredOrders.handler - events: - - schedule: rate(1 hour) - - # DynamoDB stream consumer — every write to orders-Orders (SQS consumer, - # seeds, onUpload) flows through the table stream to this handler, which - # publishes an order.* message to the orders-OrderEvents SNS topic. - onOrderStream: - handler: src/handlers/onOrderStream.handler - events: - - stream: - type: dynamodb - arn: - Fn::GetAtt: - - OrdersTable - - StreamArn - batchSize: 10 - - # POST /uploads — public; writes the payload to s3://orders-uploads under - # "incoming/" so the bucket notification below fires onUpload. - uploadFile: - handler: src/handlers/uploadFile.handler - events: - - http: - path: /uploads - method: post - cors: true - - # GET /uploads — public; lists the bucket so the S3 round-trip is observable. - listUploads: - handler: src/handlers/listUploads.handler - events: - - http: - path: /uploads - method: get - cors: true - - # Triggered when an object is created under "incoming/" in the uploads - # bucket. The notification is wired via NotificationConfiguration below. - onUpload: - handler: src/handlers/onUpload.handler - -resources: - Resources: - # Orders — PK only, plus a stream (NEW_AND_OLD_IMAGES) feeding onOrderStream. - OrdersTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: orders-Orders - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: id - AttributeType: S - KeySchema: - - AttributeName: id - KeyType: HASH - StreamSpecification: - StreamViewType: NEW_AND_OLD_IMAGES - - OrderQueue: - Type: AWS::SQS::Queue - Properties: - QueueName: orders-OrderQueue - VisibilityTimeout: 60 - MessageRetentionPeriod: 345600 - - OrderEventsTopic: - Type: AWS::SNS::Topic - Properties: - TopicName: orders-OrderEvents - - # S3 bucket with a notification that fires the onUpload Lambda whenever a - # new object is created under the "incoming/" prefix. - UploadsBucket: - Type: AWS::S3::Bucket - Properties: - BucketName: orders-uploads - NotificationConfiguration: - LambdaConfigurations: - - Event: s3:ObjectCreated:* - Function: - Fn::GetAtt: - - OnUploadLambdaFunction - - Arn - Filter: - S3Key: - Rules: - - Name: prefix - Value: incoming/ - -package: - individually: false diff --git a/examples/localstack-free/orders-service/src/handlers/aws.js b/examples/localstack-free/orders-service/src/handlers/aws.js deleted file mode 100644 index 1f36a8e..0000000 --- a/examples/localstack-free/orders-service/src/handlers/aws.js +++ /dev/null @@ -1,23 +0,0 @@ -const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); -const { DynamoDBDocumentClient } = require('@aws-sdk/lib-dynamodb'); -const { SQSClient } = require('@aws-sdk/client-sqs'); -const { SNSClient } = require('@aws-sdk/client-sns'); -const { S3Client } = require('@aws-sdk/client-s3'); - -const baseConfig = { - region: process.env.AWS_REGION || 'sa-east-1', - endpoint: process.env.AWS_ENDPOINT || 'http://localhost:4572', - credentials: { accessKeyId: 'test', secretAccessKey: 'test' }, -}; - -const dynamo = new DynamoDBClient(baseConfig); - -module.exports = { - dynamo, - doc: DynamoDBDocumentClient.from(dynamo), - sqs: new SQSClient(baseConfig), - sns: new SNSClient(baseConfig), - // forcePathStyle is required so LocalStack sees the bucket name in the URL - // path rather than as a virtual-host subdomain. - s3: new S3Client({ ...baseConfig, forcePathStyle: true }), -}; diff --git a/examples/localstack-free/orders-service/src/handlers/cleanupExpiredOrders.js b/examples/localstack-free/orders-service/src/handlers/cleanupExpiredOrders.js deleted file mode 100644 index 9a15364..0000000 --- a/examples/localstack-free/orders-service/src/handlers/cleanupExpiredOrders.js +++ /dev/null @@ -1,28 +0,0 @@ -const { ScanCommand, DeleteCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -const ONE_HOUR_MS = 60 * 60 * 1000; - -// schedule: rate(1 hour). LSS does not fire schedules yet (documented TODO), -// but the function is registered and invocable via the Lambda Invoke API on -// port 13612 — handy for exercising it on demand. -exports.handler = async () => { - const res = await doc.send(new ScanCommand({ TableName: process.env.ORDERS_TABLE })); - const items = res.Items || []; - const cutoff = Date.now() - ONE_HOUR_MS; - - const expired = items.filter((item) => { - const created = Date.parse(item.createdAt || ''); - return Number.isFinite(created) && created < cutoff; - }); - - for (const item of expired) { - await doc.send(new DeleteCommand({ - TableName: process.env.ORDERS_TABLE, - Key: { id: item.id }, - })); - } - - console.log(`[cleanupExpiredOrders] deleted ${expired.length} of ${items.length} order(s) older than 1 hour`); - return { scanned: items.length, deleted: expired.length }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/createOrder.js b/examples/localstack-free/orders-service/src/handlers/createOrder.js deleted file mode 100644 index 46a2abe..0000000 --- a/examples/localstack-free/orders-service/src/handlers/createOrder.js +++ /dev/null @@ -1,39 +0,0 @@ -const { SendMessageCommand } = require('@aws-sdk/client-sqs'); -const { randomUUID } = require('crypto'); -const { sqs } = require('./aws'); - -// POST /orders — the cross-service authorizer (auth-service) already ran and -// put the session user on event.requestContext.authorizer. The order goes -// through SQS; processOrderQueue persists it. -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return { statusCode: 400, body: JSON.stringify({ error: 'invalid json' }) }; - } - - const { item } = payload; - if (!item) { - return { statusCode: 400, body: JSON.stringify({ error: 'item is required' }) }; - } - - const authorizer = (event.requestContext && event.requestContext.authorizer) || {}; - const order = { - id: randomUUID(), - item, - user: authorizer.user, - createdAt: new Date().toISOString(), - }; - - await sqs.send(new SendMessageCommand({ - QueueUrl: process.env.ORDER_QUEUE_URL, - MessageBody: JSON.stringify(order), - })); - - return { - statusCode: 202, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ queued: true, id: order.id }), - }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/listOrders.js b/examples/localstack-free/orders-service/src/handlers/listOrders.js deleted file mode 100644 index 0233400..0000000 --- a/examples/localstack-free/orders-service/src/handlers/listOrders.js +++ /dev/null @@ -1,13 +0,0 @@ -const { ScanCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// GET /orders — protected by the same cross-service authorizer as createOrder. -exports.handler = async () => { - const res = await doc.send(new ScanCommand({ TableName: process.env.ORDERS_TABLE })); - const items = res.Items || []; - return { - statusCode: 200, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ count: items.length, items }), - }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/listUploads.js b/examples/localstack-free/orders-service/src/handlers/listUploads.js deleted file mode 100644 index b02ebfd..0000000 --- a/examples/localstack-free/orders-service/src/handlers/listUploads.js +++ /dev/null @@ -1,25 +0,0 @@ -const { ListObjectsV2Command } = require('@aws-sdk/client-s3'); -const { s3 } = require('./aws'); - -// GET /uploads?prefix=incoming/ -exports.handler = async (event) => { - const prefix = (event.queryStringParameters && event.queryStringParameters.prefix) || undefined; - - const response = await s3.send(new ListObjectsV2Command({ - Bucket: process.env.UPLOADS_BUCKET, - Prefix: prefix, - MaxKeys: 100, - })); - - const objects = (response.Contents || []).map(o => ({ - key: o.Key, - size: o.Size, - lastModified: o.LastModified, - })); - - return { - statusCode: 200, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ bucket: process.env.UPLOADS_BUCKET, count: objects.length, objects }), - }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/onOrderStream.js b/examples/localstack-free/orders-service/src/handlers/onOrderStream.js deleted file mode 100644 index 78df96c..0000000 --- a/examples/localstack-free/orders-service/src/handlers/onOrderStream.js +++ /dev/null @@ -1,34 +0,0 @@ -const { PublishCommand } = require('@aws-sdk/client-sns'); -const { unmarshall } = require('@aws-sdk/util-dynamodb'); -const { sns } = require('./aws'); - -// DynamoDB stream consumer — every INSERT/MODIFY/REMOVE on orders-Orders lands -// here (NEW_AND_OLD_IMAGES), and each record is fanned out as an order.* SNS -// message on the orders-OrderEvents topic. -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[onOrderStream] received ${records.length} stream record(s)`); - - for (const record of records) { - const eventName = record.eventName; // INSERT | MODIFY | REMOVE - const newImage = record.dynamodb?.NewImage ? unmarshall(record.dynamodb.NewImage) : null; - const oldImage = record.dynamodb?.OldImage ? unmarshall(record.dynamodb.OldImage) : null; - - const message = { - type: `order.${eventName.toLowerCase()}`, - orderId: (newImage || oldImage)?.id, - item: (newImage || oldImage)?.item, - user: (newImage || oldImage)?.user, - status: newImage?.status, - occurredAt: new Date().toISOString(), - }; - - await sns.send(new PublishCommand({ - TopicArn: process.env.ORDER_EVENTS_TOPIC_ARN, - Subject: message.type, - Message: JSON.stringify(message), - })); - - console.log(`[onOrderStream] published ${message.type} for ${message.orderId}`); - } -}; diff --git a/examples/localstack-free/orders-service/src/handlers/onUpload.js b/examples/localstack-free/orders-service/src/handlers/onUpload.js deleted file mode 100644 index caa591d..0000000 --- a/examples/localstack-free/orders-service/src/handlers/onUpload.js +++ /dev/null @@ -1,53 +0,0 @@ -const { GetObjectCommand } = require('@aws-sdk/client-s3'); -const { PutCommand } = require('@aws-sdk/lib-dynamodb'); -const { s3, doc } = require('./aws'); - -// Triggered by the S3 bucket notification when an object is created under -// "incoming/". This handler reads the object back, derives some metadata, and -// records it in orders-Orders to prove the round-trip works end-to-end (the -// write also flows through the table stream → onOrderStream → SNS). -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[onUpload] received ${records.length} S3 event(s)`); - - for (const record of records) { - const bucket = record.s3 && record.s3.bucket && record.s3.bucket.name; - const key = record.s3 && record.s3.object && decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')); - if (!bucket || !key) { - console.warn('[onUpload] skipping malformed record'); - continue; - } - - let size = (record.s3.object && record.s3.object.size) || 0; - let preview; - try { - const obj = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key })); - const chunks = []; - for await (const chunk of obj.Body) chunks.push(chunk); - const body = Buffer.concat(chunks); - size = body.length; - preview = body.slice(0, 120).toString('utf-8'); - } catch (err) { - console.warn(`[onUpload] could not read s3://${bucket}/${key}: ${err.message}`); - } - - // Stash an entry in orders-Orders so the trigger is observable from the - // dashboard's DynamoDB explorer without adding a dedicated table. - await doc.send(new PutCommand({ - TableName: process.env.ORDERS_TABLE, - Item: { - id: `upload:${bucket}/${key}`, - item: key, - user: 's3-upload', - status: 'uploaded', - size, - ...(preview ? { preview } : {}), - processedAt: new Date().toISOString(), - }, - })); - - console.log(`[onUpload] indexed s3://${bucket}/${key} (${size} bytes)`); - } - - return { batchItemFailures: [] }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/processOrderQueue.js b/examples/localstack-free/orders-service/src/handlers/processOrderQueue.js deleted file mode 100644 index ee7e6b4..0000000 --- a/examples/localstack-free/orders-service/src/handlers/processOrderQueue.js +++ /dev/null @@ -1,31 +0,0 @@ -const { PutCommand } = require('@aws-sdk/lib-dynamodb'); -const { doc } = require('./aws'); - -// SQS consumer — persists each queued order with status "processed". -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[processOrderQueue] received ${records.length} message(s)`); - - for (const record of records) { - let order; - try { - order = JSON.parse(record.body); - } catch { - console.error('[processOrderQueue] invalid body, dropping:', record.body); - continue; - } - - await doc.send(new PutCommand({ - TableName: process.env.ORDERS_TABLE, - Item: { - ...order, - status: 'processed', - processedAt: new Date().toISOString(), - }, - })); - - console.log(`[processOrderQueue] stored order ${order.id} (processed)`); - } - - return { batchItemFailures: [] }; -}; diff --git a/examples/localstack-free/orders-service/src/handlers/uploadFile.js b/examples/localstack-free/orders-service/src/handlers/uploadFile.js deleted file mode 100644 index 7c89996..0000000 --- a/examples/localstack-free/orders-service/src/handlers/uploadFile.js +++ /dev/null @@ -1,37 +0,0 @@ -const { PutObjectCommand } = require('@aws-sdk/client-s3'); -const { randomUUID } = require('crypto'); -const { s3 } = require('./aws'); - -// POST /uploads -// Body: { "filename": "report.txt", "content": "...", "encoding": "base64" | undefined } -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return { statusCode: 400, body: JSON.stringify({ error: 'invalid json' }) }; - } - - const { filename, content, encoding, contentType } = payload; - if (!content) { - return { statusCode: 400, body: JSON.stringify({ error: 'content is required' }) }; - } - - // Files land under "incoming/" so the S3 → Lambda notification fires. - const safeName = (filename || `${randomUUID()}.txt`).replace(/[^a-zA-Z0-9._/-]/g, '_'); - const key = `incoming/${safeName}`; - const body = encoding === 'base64' ? Buffer.from(content, 'base64') : content; - - await s3.send(new PutObjectCommand({ - Bucket: process.env.UPLOADS_BUCKET, - Key: key, - Body: body, - ContentType: contentType || 'text/plain', - })); - - return { - statusCode: 201, - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ uploaded: true, bucket: process.env.UPLOADS_BUCKET, key }), - }; -}; diff --git a/examples/localstack-free/package.json b/examples/localstack-free/package.json deleted file mode 100644 index 26d0014..0000000 --- a/examples/localstack-free/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "localstack-free", - "version": "0.0.0", - "private": true, - "description": "The LocalStack community example: four services on LSS's API Gateway + Lambda emulation — authorizers (local and cross-service), TypeScript from source, SQS, a shared EventBridge bus, DynamoDB streams → SNS, and S3 notifications. No serverless-offline, no serverless deploy.", - "scripts": { - "lss:start": "node ../../bin/cli.js start", - "lss:stop": "node ../../bin/cli.js stop", - "lss:status": "node ../../bin/cli.js status", - "lss:seed": "node ../../bin/cli.js seed", - "register:events": "npm --prefix events-stack run package", - "register:auth": "npm --prefix auth-service run package", - "register:users": "npm --prefix users-service run package", - "register:orders": "npm --prefix orders-service run package", - "register:gateway": "npm --prefix gateway-stack run package", - "register:all": "npm run register:events && npm run register:auth && npm run register:users && npm run register:orders && npm run register:gateway", - "setup": "npm --prefix events-stack install && npm --prefix auth-service install && npm --prefix users-service install && npm --prefix orders-service install && npm --prefix gateway-stack install", - "console": "npx -y http-server . -p 8620 -c-1" - } -} diff --git a/examples/localstack-free/seeds/auth-Sessions.json b/examples/localstack-free/seeds/auth-Sessions.json deleted file mode 100644 index 0d5a9ec..0000000 --- a/examples/localstack-free/seeds/auth-Sessions.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "code": "code-admin", - "user": "admin", - "createdAt": "2026-01-01T00:00:00.000Z" - } -] diff --git a/examples/localstack-free/seeds/orders-Orders.json b/examples/localstack-free/seeds/orders-Orders.json deleted file mode 100644 index e6bc8d7..0000000 --- a/examples/localstack-free/seeds/orders-Orders.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "id": "o-1001", - "item": "BOOK-01 x2", - "user": "alice", - "status": "processed", - "total": 50, - "createdAt": "2026-05-10T09:00:00.000Z", - "processedAt": "2026-05-10T09:00:02.000Z" - }, - { - "id": "o-1002", - "item": "LAPTOP-XL x1", - "user": "alice", - "status": "pending_review", - "total": 1500, - "createdAt": "2026-05-12T14:20:00.000Z", - "processedAt": "2026-05-12T14:20:01.000Z" - }, - { - "id": "o-1003", - "item": "MUG-RED x3 + STICKER-PK x4", - "user": "bob", - "status": "processed", - "total": 56, - "createdAt": "2026-05-13T16:45:00.000Z", - "processedAt": "2026-05-13T16:45:01.000Z" - } -] diff --git a/examples/localstack-free/seeds/users-Users.json b/examples/localstack-free/seeds/users-Users.json deleted file mode 100644 index d04db8e..0000000 --- a/examples/localstack-free/seeds/users-Users.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "id": "u-ada", - "name": "Ada Lovelace", - "email": "ada@example.com", - "createdAt": "2026-01-01T10:00:00.000Z" - }, - { - "id": "u-grace", - "name": "Grace Hopper", - "email": "grace@example.com", - "createdAt": "2026-01-02T11:30:00.000Z" - } -] diff --git a/examples/localstack-ultimate/.env.example b/examples/localstack-ultimate/.env.example deleted file mode 100644 index 03a71c8..0000000 --- a/examples/localstack-ultimate/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -# Copy to `.env` (which is gitignored) and fill in. -# -# REQUIRED for this example: localstack/localstack-pro refuses to start without -# a valid token (it exits with code 55). Grab a token at -# https://app.localstack.cloud (Personal access tokens). A free Hobby token -# covers everything this example provisions. -LOCALSTACK_AUTH_TOKEN= diff --git a/examples/localstack-ultimate/.gitignore b/examples/localstack-ultimate/.gitignore deleted file mode 100644 index d23b859..0000000 --- a/examples/localstack-ultimate/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules/ -.serverless/ -.lss/ -.dynamodb/ -.esbuild/ -*.log -.env -.env.local diff --git a/examples/localstack-ultimate/README.md b/examples/localstack-ultimate/README.md deleted file mode 100644 index a68c88b..0000000 --- a/examples/localstack-ultimate/README.md +++ /dev/null @@ -1,237 +0,0 @@ -# localstack-ultimate - -End-to-end LSS example pointed at the **LocalStack paid tier**. LocalStack renamed its -paid plans — the top plan is now **Ultimate** — but the Docker image those plans use is -still `localstack/localstack-pro:latest`, and that is exactly what this example boots. - -This is also the one example that deliberately keeps the **serverless-offline -integration path**: the HTTP API is served by `serverless-offline` (not by the LSS -gateway), while the `serverless-lss` plugin registers the service with the orchestrator, -which provisions every CloudFormation resource into the Pro LocalStack and wires the -S3 → Lambda notification. Use it to confirm LSS plays nicely with an offline-based -workflow you may already have. - -## What this exercises - -- **LocalStack Pro image** — `localstackEdition: "pro"` in `lss.config.json`; the - container refuses to start without a valid `LOCALSTACK_AUTH_TOKEN` (exit code 55). -- **serverless-offline compatibility** — REST (v1) routes with `cors: true` served by - the offline server on `3002`; registration with LSS fires on `sls package` and on - offline startup. -- **Region `eu-west-1`** — the whole example (LSS config, provider, SDK clients) runs - outside the default region, proving nothing is hardwired to it. -- **DynamoDB** — PK-only tables, composite key + GSI (`ByStatus`), a stream feeding - the `onOrderStream` Lambda, seeds auto-loaded from `seeds/`. The Users table has - deliberately **no TTL** (surfacing a UI warning); the Sessions table carries an - `expiresAt` attribute so you can enable **TTL from the UI** (Settings tab). -- **SQS + DLQ redrive** — `enqueueOrder` sends to the queue, `processOrderQueue` - consumes in batches (`ReportBatchItemFailures`) and persists orders with a computed - `status`/`total`; poison orders (computed total ≤ 0) are re-received every 10s - (short `VisibilityTimeout`) and redriven to `-OrderProcessingDLQ` after 3 receives — - watch them pile up in the dashboard's Queues tab. -- **SNS** — stream handler publishes `order.*` events to a topic. -- **EventBridge custom bus + pattern rule + audit trail** — `processOrderQueue` - (`order.processed`) and `purgeSessions` (`sessions.purged`) `PutEvents` onto the - `ultimate-order-events` bus; the `auditEvents` rule (pattern filter on `source`) - writes each matched event into the AuditTrail table, readable via `GET /audit`. -- **Schedule** — `purgeSessions` (`rate(2 minutes)`), provisioned as an EventBridge - rule fired by LocalStack, purges expired sessions and leaves an audit entry. -- **S3 + Lambda notification** — uploads under `incoming/` trigger `onUpload`, which - reads the object back and indexes it in the Orders table. -- **OpenSearch Serverless (LSS aoss sidecar)** — LocalStack has **no aoss support in - any edition**, so LSS serves the `ultimate-products` collection in-process on - `14567`; the catalog routes (`/products`, `/search`, `/stats`) cover indexing, - full-text search + filters and aggregations against it. -- **Seeds & persistence** — tables pre-filled from `seeds/`; `persistence: true` - keeps data across `lss:stop`/`lss:start` cycles. -- **Dashboard branding** — per-theme brand tokens with a light default (see below). - -## Prerequisites - -- Docker -- Node.js ≥ 20 -- A **LocalStack auth token**. Paid-tier images refuse to start without one. Grab a - token at → *Personal access tokens*. A free Hobby - token is enough for the resources this example uses. - -## Setup - -```bash -cd examples/localstack-ultimate -npm install - -# Drop your token into a local .env (gitignored). The npm scripts wrap commands -# with dotenv-cli so LOCALSTACK_AUTH_TOKEN reaches both LSS and serverless-offline. -cp .env.example .env -$EDITOR .env # set LOCALSTACK_AUTH_TOKEN=ls-xxxxxxxx -``` - -## Ports used - -| Concern | Port | -|---|---| -| LSS dashboard / API | `3111` | -| LocalStack (Pro image) | `4571` | -| serverless-offline HTTP | `3002` | -| serverless-offline Lambda invoke | `3003` | -| LSS aoss sidecar (OpenSearch Serverless) | `14567` | -| Validation console (`npm run console`) | `8621` | - -These are all different from [`localstack-free`](../localstack-free/) (which uses -LSS `3120`, LocalStack `4572`, service APIs `3610`–`3612`) **and** from a default -external LocalStack on `4566`, so -you can run any combination at the same time without conflict — unless your external -LocalStack publishes the whole `4566–4599` range (a common install default), in which -case `4571` sits inside it and will collide. - -## Run - -```bash -# 1. Boot LSS — pulls localstack/localstack-pro:latest on first run. -npm run lss:start - -# 2. Package + start serverless-offline. The plugin registers this service with -# LSS (3111), which provisions every CloudFormation resource into the Pro -# LocalStack on 4571 and wires the S3 -> onUpload notification, the -# EventBridge bus/rules and the SQS event source mapping. In between, the -# script re-applies the queue's RedrivePolicy via scripts/wire-dlq.js — a -# no-op safety net now that LSS carries that attribute from the template. -npm run offline -``` - -Dashboard: . - -## Try the HTTP routes - -The offline server binds to **port 3002** and prefixes routes with the stage (`/dev`): - -```bash -curl http://localhost:3002/dev/health - -# Create a user -curl -X POST http://localhost:3002/dev/users \ - -H 'Content-Type: application/json' \ - -d '{"name":"Dora","email":"dora@example.com"}' - -# Enqueue an order — the SQS consumer stores it and publishes order.processed -# onto the ultimate-order-events bus -curl -X POST http://localhost:3002/dev/orders \ - -H 'Content-Type: application/json' \ - -d '{"userId":"u-alice","items":[{"sku":"BOOK-02","price":42,"qty":1}]}' - -# The auditEvents rule wrote it into the AuditTrail table (sessions.purged -# entries from the rate(2 minutes) schedule show up here too) -curl http://localhost:3002/dev/audit - -# Poison order: computed total is 0, so processOrderQueue throws and reports -# the message as a batch item failure — after 3 receives (~30s at a 10s -# visibility timeout) SQS redrives it to localstack-ultimate-OrderProcessingDLQ -# (dashboard -> Queues tab). -curl -X POST http://localhost:3002/dev/orders \ - -H 'Content-Type: application/json' \ - -d '{"userId":"u-alice","items":[{"sku":"BROKEN","price":0,"qty":1}]}' - -# Upload to S3 -> triggers the onUpload Lambda via bucket notification -curl -X POST http://localhost:3002/dev/uploads \ - -H 'Content-Type: application/json' \ - -d '{"filename":"hello.txt","content":"hello from ultimate"}' - -curl http://localhost:3002/dev/uploads - -# Index a product into the ultimate-products collection — served by the LSS -# aoss sidecar on :14567 (LocalStack has no OpenSearch Serverless) -curl -X POST http://localhost:3002/dev/products \ - -H 'Content-Type: application/json' \ - -d '{"name":"Wireless Mouse","category":"peripherals","price":25,"tags":["usb","wireless"]}' - -# Fetch / delete it by the id returned above -curl http://localhost:3002/dev/products/ -curl -X DELETE http://localhost:3002/dev/products/ - -# Full-text search + filters, then aggregations (count + avg price per category) -curl 'http://localhost:3002/dev/search?q=wireless&category=peripherals&maxPrice=50' -curl http://localhost:3002/dev/stats -``` - -## Validation console - -`index.html` at the example root is a small browser console that pings every port and -runs the flows above end to end (create user → list, enqueue → verify the SQS consumer -wrote the order, order → audit trail via EventBridge, poison order → DLQ, schedule -observation, upload → verify the S3 notification fired, catalog index → search → -stats → delete against the aoss sidecar). Open it directly from the -filesystem (`file://…/index.html`) or serve it: - -```bash -npm run console # http://localhost:8621 -``` - -CORS is pre-wired for it: every `http` event declares `cors: true` (serverless-offline -answers the preflight) and every handler response carries -`Access-Control-Allow-Origin: *` via the shared `src/handlers/respond.js` helper. - -## Dashboard branding - -The example also showcases [dashboard branding](../../docs/CONFIGURATION.md#configuration-properties): -`lss.config.json` sets a custom title/subtitle, points `logo`/`favicon` at -`assets/logo.svg`, forces `defaultTheme: "light"`, and overrides the brand tokens -(`brand-primary`/`brand-hover`/`brand-soft`, plus `brand-contrast` in dark) **per -theme** with amber tones — the dashboard at `http://localhost:3111` opens light with an -amber accent. Each example in this folder uses a different branding mechanism, so -compare them to see what the dashboard supports. - -## Reset - -```bash -npm run lss:seed:clear # empties seeded tables — prompts for confirmation - # (type "confirmar"); append -- --yes for - # non-interactive use -npm run lss:stop # stops orchestrator + LocalStack Pro container -``` - -Persistence is on, so a `lss:stop` / `lss:start` cycle preserves data. To wipe -completely, also `docker volume rm lss-localstack-4571-data` (the `--rm` container is -removed automatically on stop). - -## What's different from localstack-free - -- `lss.config.json` -> `"localstackEdition": "pro"`, `serverPort: 3111`, `localstackPort: 4571`. -- Region is **`eu-west-1`** — each example runs in its own region (localstack-free: - `sa-east-1`, self-hosted: `us-west-2`), so they also prove multi-region coherence - side by side. -- Service name is `localstack-ultimate`, so resources live under a separate namespace - (`localstack-ultimate-Users`, `localstack-ultimate-uploads`, etc.). -- All ports shifted to dodge the community example, so both can run side by side. -- `LOCALSTACK_AUTH_TOKEN` is **required**; without it the Pro image exits with code 55. -- The HTTP API is served by **serverless-offline** — the other examples route HTTP - through the LSS gateway instead. -- Shape: this is a single service (one `serverless.yml`) owning its own EventBridge - bus, while `localstack-free` is a four-service stack exercising authorizers and a - **shared** bus across services. -- **OpenSearch Serverless** — LocalStack has no aoss support in any edition (not even - paid ones), so LSS serves the `ultimate-products` collection **in-process** via its - aoss sidecar on `14567` (on by default for LocalStack engines; the port is pinned in - `lss.config.json`) while everything else lives in the Pro container. - -Run both side by side when you want to confirm a behavior is or isn't gated behind a -paid plan. - -## File map - -``` -serverless.yml ← REST routes + SQS/DLQ + streams + EventBridge bus, - pattern rule, rate(2 minutes) schedule, aoss - collection + policies (eu-west-1) -lss.config.json ← edition: pro, region eu-west-1, services incl. - "events", ports 3111/4571 (+ aoss sidecar 14567), - branding block -.env / .env.example ← LOCALSTACK_AUTH_TOKEN (gitignored) -index.html ← validation console (file:// or npm run console) -assets/logo.svg ← dashboard logo/favicon -scripts/wire-dlq.js ← applies the RedrivePolicy to the live queue -src/handlers/ ← HTTP + event handlers, shared respond.js CORS helper -src/handlers/opensearch.js ← fetch-based OpenSearch helper (aoss sidecar :14567) -src/handlers/createProduct.js ← + getProduct/deleteProduct/searchProducts/ - productStats — the OpenSearch catalog routes -seeds/ ← localstack-ultimate-Users / -Orders / -Sessions seeds -``` diff --git a/examples/localstack-ultimate/assets/logo.svg b/examples/localstack-ultimate/assets/logo.svg deleted file mode 100644 index 723ab82..0000000 --- a/examples/localstack-ultimate/assets/logo.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - LU - diff --git a/examples/localstack-ultimate/index.html b/examples/localstack-ultimate/index.html deleted file mode 100644 index 6f8bfdb..0000000 --- a/examples/localstack-ultimate/index.html +++ /dev/null @@ -1,320 +0,0 @@ - - - - - - -localstack-ultimate · validation console - - - -
- -
-

localstack-ultimate

-

LSS + LocalStack Pro image (Ultimate) — serverless-offline integration path

-
- -
-
-
-

Status

-
-
-
-

Flows

-
-
-
-

Request log

-
-
-
-
Generated for the LSS example "localstack-ultimate" — open this file directly or via npm run console.
- - - diff --git a/examples/localstack-ultimate/lss.config.json b/examples/localstack-ultimate/lss.config.json deleted file mode 100644 index d4423cd..0000000 --- a/examples/localstack-ultimate/lss.config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "serverPort": 3111, - "localstackPort": 4571, - "localstackEndpoint": "http://localhost:4571", - "mode": "managed", - "localstackEdition": "pro", - "region": "eu-west-1", - "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], - "aossSidecar": { "port": 14567 }, - "persistence": true, - "stateDir": ".lss", - "seedsDir": "./seeds", - "autoPackage": true, - "packageCommand": "npx serverless package", - "packageTimeoutMs": 300000, - "branding": { - "title": "LocalStack Ultimate Lab", - "subtitle": "LSS + LocalStack Pro image — paid-tier features, serverless-offline path", - "logo": "./assets/logo.svg", - "favicon": "./assets/logo.svg", - "defaultTheme": "light", - "themeColors": { - "light": { "brand-primary": "#b45309", "brand-hover": "#92400e", "brand-soft": "#fef3c7" }, - "dark": { "brand-primary": "#fbbf24", "brand-hover": "#fcd34d", "brand-soft": "#78350f", "brand-contrast": "#451a03" } - } - } -} diff --git a/examples/localstack-ultimate/package-lock.json b/examples/localstack-ultimate/package-lock.json deleted file mode 100644 index 14c8c63..0000000 --- a/examples/localstack-ultimate/package-lock.json +++ /dev/null @@ -1,4790 +0,0 @@ -{ - "name": "localstack-ultimate", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "localstack-ultimate", - "version": "0.0.0", - "dependencies": { - "@aws-sdk/client-dynamodb": "3.974.0", - "@aws-sdk/client-eventbridge": "^3.974.0", - "@aws-sdk/client-s3": "^3.974.0", - "@aws-sdk/client-sns": "3.974.0", - "@aws-sdk/client-sqs": "3.974.0", - "@aws-sdk/util-dynamodb": "3.974.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "osls": "4.0.0", - "serverless-lss": "file:../../packages/serverless-plugin", - "serverless-offline": "^13.6.0" - } - }, - "../../packages/serverless-plugin": { - "name": "serverless-lss", - "version": "0.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "devDependencies": { - "@types/node": "^22.10.5", - "typescript": "^5.7.3" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "osls": "4.0.0" - }, - "peerDependenciesMeta": { - "osls": { - "optional": true - } - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-15.5.0.tgz", - "integrity": "sha512-Ps4w0FwrDoeVK6hfYxWkVbkmxm+zN+6xoXF2ZfEhfiox0ZNbcSAiUWO6iAIvP5bc3DB270r+EaKcoT1IUyzfxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@types/json-schema": "^7.0.15" - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/checksums": { - "version": "3.1000.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.16.tgz", - "integrity": "sha512-EKnvkXSmz3IpA99tCNuI+dLFXyZyClSm8zns9sB/elvkU+MTuomAs6toJMPMBf98/fICG/urXDkzGz0/c3yyAQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-api-gateway": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-api-gateway/-/client-api-gateway-3.1051.0.tgz", - "integrity": "sha512-eYUubuiRmlf+YVyyP6CjRmBmpelDzYNL5i8wkR3tLR7yVRHi8l54Ft9Kesn8FON+OAeFNK2O5rbXMG2X8f6ACg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/middleware-sdk-api-gateway": "^3.972.12", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-apigatewayv2": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-apigatewayv2/-/client-apigatewayv2-3.1085.0.tgz", - "integrity": "sha512-IeDwKOit9IndGVNOcEAAIxwj5z+YhX4aGVNXU+C0sZvALnSOI83rGMekPGxGrZf6tDxpmwtIrSm6qYWPbFkNXA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudformation": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.1051.0.tgz", - "integrity": "sha512-5R6SFqCkJitoatw7FV6BjefxFhkvRyW9FHhr9H89kcvqPIx8Ah433giyiPEMVsdmmb9msOWCpHsC81CELPJp6g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch/-/client-cloudwatch-3.1085.0.tgz", - "integrity": "sha512-2WyjUH6zdRvPSvL/8JJYo6BJfK4hNn9RA3+3XEfPczQ/uYxhFfIR8hbNIrRQe7ffb9X8CCxN6YpSQtw8iXQboA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/middleware-compression": "^4.5.7", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1085.0.tgz", - "integrity": "sha512-jNMt5zMsnJ6X0fZJKKNU5/qTQ98OIsUSFLqDh+FTXQTiEI3NTq95gAdsaAwXVWO9hTaT5gY7fbwF5Ally69bwg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1081.0.tgz", - "integrity": "sha512-ipDgvZ3Hy8kaFrkwj62yuoghKkZi5WrWTiJnaqGc/ntbuAuijIkRWhzSb8d1MGEE+qb+vFFTrWVFwGSqt76TCA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/fetch-http-handler": "^5.6.2", - "@smithy/node-http-handler": "^4.9.2", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity-provider": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.1051.0.tgz", - "integrity": "sha512-7bJ2fxeEVNtrxH/kL5Tk8H2EGuNbPtuI4BfpwogHmJfn7oUrIODlnJJL43l/LU2i6d5MoXCZKJf18EufkGpgVw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.974.0.tgz", - "integrity": "sha512-Nw4/sL0IbBMvQdBvLlnBTFBrG+Aqg22ewMVJWOXSVdktfomtpPJ+jpJXBMJDMF9LsrgTNF/zsSVRJSEHYlBkOA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.0", - "@aws-sdk/credential-provider-node": "^3.972.1", - "@aws-sdk/dynamodb-codec": "^3.972.1", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.1", - "@aws-sdk/middleware-host-header": "^3.972.1", - "@aws-sdk/middleware-logger": "^3.972.1", - "@aws-sdk/middleware-recursion-detection": "^3.972.1", - "@aws-sdk/middleware-user-agent": "^3.972.1", - "@aws-sdk/region-config-resolver": "^3.972.1", - "@aws-sdk/types": "^3.973.0", - "@aws-sdk/util-endpoints": "3.972.0", - "@aws-sdk/util-user-agent-browser": "^3.972.1", - "@aws-sdk/util-user-agent-node": "^3.972.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.21.0", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.10", - "@smithy/middleware-retry": "^4.4.26", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.10.11", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.25", - "@smithy/util-defaults-mode-node": "^4.2.28", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ecr": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.1085.0.tgz", - "integrity": "sha512-I1MWQNb01MlfC2MENTll+GrRV2RSGmkQSyB289CEY2QGf4ImqeEsySWFtpau/39zqTxqOyx/jfXrT5vdr3hOyQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-eventbridge": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-eventbridge/-/client-eventbridge-3.1051.0.tgz", - "integrity": "sha512-lF356sBGSoeI5bDkDBUrS4lVERZE2lRiankELUCKcfRARoas0Wvn4gCFunisKQjf4Za+RywZMC+PP0Zp1P3Z4w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/signature-v4-multi-region": "^3.996.27", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-iam": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.1051.0.tgz", - "integrity": "sha512-9MRigaj8/9/ZofuICTc8vUa2v+SOAFaeKkt7Fmom0pzbob3LaJquMkT4RmawevJQ/T6UHJmC6F1s6xon/lZrZQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1051.0.tgz", - "integrity": "sha512-Oc7Rc9R6BbltJGYUls4xYswIujugscTbjAao51izJvW+UKAzgoYg0TenVDslXoPQbkkIAnZjAF6ehLxB8eui4g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1085.0.tgz", - "integrity": "sha512-O0xe8sR50AYkwxlvRRsV0qytEO2dtXQTQ1CF3YBBdE5xtVkbu27H0vGa1mjQi1/+fbYM80AWEIPai5jZmXyubw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/checksums": "^3.1000.16", - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/middleware-sdk-s3": "^3.972.62", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sns": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.974.0.tgz", - "integrity": "sha512-k2PFHgJ1qs7MpTnvkrQciaU2YIlYkOPkPCyt/SfA3I8Gi+1Q8CDQUfMbBPWeSFhQuNIE/U3Sl/F5j1SGqjclsg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.0", - "@aws-sdk/credential-provider-node": "^3.972.1", - "@aws-sdk/middleware-host-header": "^3.972.1", - "@aws-sdk/middleware-logger": "^3.972.1", - "@aws-sdk/middleware-recursion-detection": "^3.972.1", - "@aws-sdk/middleware-user-agent": "^3.972.1", - "@aws-sdk/region-config-resolver": "^3.972.1", - "@aws-sdk/types": "^3.973.0", - "@aws-sdk/util-endpoints": "3.972.0", - "@aws-sdk/util-user-agent-browser": "^3.972.1", - "@aws-sdk/util-user-agent-node": "^3.972.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.21.0", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.10", - "@smithy/middleware-retry": "^4.4.26", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.10.11", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.25", - "@smithy/util-defaults-mode-node": "^4.2.28", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sqs": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sqs/-/client-sqs-3.974.0.tgz", - "integrity": "sha512-dfJcrDwEGxOB2fea4IhhMdr7WL7OKY+fWegrlf91ewG7h7Lk0Zws/6yLQP2GCNECoLwveGQkYNZTUT2rfF52Gw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.973.0", - "@aws-sdk/credential-provider-node": "^3.972.1", - "@aws-sdk/middleware-host-header": "^3.972.1", - "@aws-sdk/middleware-logger": "^3.972.1", - "@aws-sdk/middleware-recursion-detection": "^3.972.1", - "@aws-sdk/middleware-sdk-sqs": "^3.972.1", - "@aws-sdk/middleware-user-agent": "^3.972.1", - "@aws-sdk/region-config-resolver": "^3.972.1", - "@aws-sdk/types": "^3.973.0", - "@aws-sdk/util-endpoints": "3.972.0", - "@aws-sdk/util-user-agent-browser": "^3.972.1", - "@aws-sdk/util-user-agent-node": "^3.972.1", - "@smithy/config-resolver": "^4.4.6", - "@smithy/core": "^3.21.0", - "@smithy/fetch-http-handler": "^5.3.9", - "@smithy/hash-node": "^4.2.8", - "@smithy/invalid-dependency": "^4.2.8", - "@smithy/md5-js": "^4.2.8", - "@smithy/middleware-content-length": "^4.2.8", - "@smithy/middleware-endpoint": "^4.4.10", - "@smithy/middleware-retry": "^4.4.26", - "@smithy/middleware-serde": "^4.2.9", - "@smithy/middleware-stack": "^4.2.8", - "@smithy/node-config-provider": "^4.3.8", - "@smithy/node-http-handler": "^4.4.8", - "@smithy/protocol-http": "^5.3.8", - "@smithy/smithy-client": "^4.10.11", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.25", - "@smithy/util-defaults-mode-node": "^4.2.28", - "@smithy/util-endpoints": "^3.2.8", - "@smithy/util-middleware": "^4.2.8", - "@smithy/util-retry": "^4.2.8", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-ssm": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1085.0.tgz", - "integrity": "sha512-vFYFncOReqEtOj110hdTQK/4JzNEHdVR90Ob6FjdEeb8cNer+HShI64Nuw9J4gTUQAWJ0eErHZqqxQPTViplew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-node": "^3.972.66", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.1051.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1051.0.tgz", - "integrity": "sha512-7A3YcLSGNXqCMI4/W6NkMCgqDi0H+mER4d6wqGCk2PsgzpePgXzG2ufa4EAXFEH5qAhYft8PmAJZczhjhDmM2A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.12", - "@aws-sdk/credential-provider-node": "^3.972.43", - "@aws-sdk/signature-v4-multi-region": "^3.996.27", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.975.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.975.1.tgz", - "integrity": "sha512-8qh/6EYb7hl/ZwVfQufhbMEZs1gQIc7GbdrIf4eprQJ7cv042+74nE6l3YDfyWNzb9iPXb8fRyYSHkNIk5eE6Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@aws-sdk/xml-builder": "^3.972.34", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.29.2", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.972.56", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.56.tgz", - "integrity": "sha512-nedaZz6Wz2FGUBMsWhlvBPGIkTMfRuMJ99YDHJI4CaC31JS8WPyTavEAio74cfd5nGhi0A8XASB4fZA5VqTdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.57.tgz", - "integrity": "sha512-1RfJaF7SW1TOnvNGU7kaYjwUf5H3sfm+synGH1bHhRlqcnxCt3szebH3dmKEyY4tuGcbQ6ffzUT89cRitBV8OQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.59", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.59.tgz", - "integrity": "sha512-sRCkpTiFnCdQvuaRVjQ6SVoHu6i7RUpurVo1c4F81HWhPvUJ7Wdp5MNtSdX1O29CNXc8em3O5m52hCjVtAD9SA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.1.tgz", - "integrity": "sha512-6d8H6ZAh3ZPKZ6fe1nG2OWeZEZPtt9ravoD1dezPdPtsSkJRoxGAnFSHwKT3E/Te6fHE30zRzjV6TD12rvF6yQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-login": "^3.972.63", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.63.tgz", - "integrity": "sha512-GREWRrMj0XnNKMaVa/Mauoaui26qBEHu71WWqXbwZOu/jFQOnPZjTf7u0KtGKC8VGa6VUs9kDWGgocrKNLS9vw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.66", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.66.tgz", - "integrity": "sha512-f+qjRXZpz7sgzbc4QB+6nLKfyKFgRRXzWdXbsKPv/VhVRyHsDyq4yBWC/B75BAJpFIcUeI2XR/3gdWJ677zB4A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.57", - "@aws-sdk/credential-provider-http": "^3.972.59", - "@aws-sdk/credential-provider-ini": "^3.973.1", - "@aws-sdk/credential-provider-process": "^3.972.57", - "@aws-sdk/credential-provider-sso": "^3.973.1", - "@aws-sdk/credential-provider-web-identity": "^3.972.63", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/credential-provider-imds": "^4.4.7", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.57", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.57.tgz", - "integrity": "sha512-TiVQhuU0pbhIZAUZacbPHMyzrIdiH+lnx+PMY/Pu/b93dJrq3wdZwzUJ0TPpvNxaqbHsxJvQZW3/h/beLiKq7Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.1.tgz", - "integrity": "sha512-3foTZUJ4821Ij60X7K3NJroygiZLnbBmarN+T//O2cjkISan90zElN3NBmgSlDrTQ7Gs6z/yO8V7h60QNcDZHQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/token-providers": "3.1083.0", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.63", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.63.tgz", - "integrity": "sha512-8qZLFhM69eKcS37m459ctPR05Qimycm/74OPVioe6wNZabMT54GYhwBju0+J656RkMasNSawWQu+c8CmBe3TUQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.1081.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1081.0.tgz", - "integrity": "sha512-UHWvxd1F5nfBXBRXtQaXWoNT8CYKXZovLQOyz6XZlgFTGc2mWzzPGspOfnh49jwvB2qzsdH046i9jnnmND+64w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.1081.0", - "@aws-sdk/core": "^3.974.29", - "@aws-sdk/credential-provider-cognito-identity": "^3.972.54", - "@aws-sdk/credential-provider-env": "^3.972.55", - "@aws-sdk/credential-provider-http": "^3.972.57", - "@aws-sdk/credential-provider-ini": "^3.972.62", - "@aws-sdk/credential-provider-login": "^3.972.61", - "@aws-sdk/credential-provider-node": "^3.972.64", - "@aws-sdk/credential-provider-process": "^3.972.55", - "@aws-sdk/credential-provider-sso": "^3.972.61", - "@aws-sdk/credential-provider-web-identity": "^3.972.61", - "@aws-sdk/nested-clients": "^3.997.29", - "@aws-sdk/types": "^3.973.15", - "@smithy/core": "^3.29.0", - "@smithy/credential-provider-imds": "^4.4.5", - "@smithy/types": "^4.15.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.12.tgz", - "integrity": "sha512-E+qpJPN1QLzfeVDQe1gVmMiHu9PTJWwXqSQjIt8mH5OQXmds2J/IN+Ar6Oa9ZhhuPZb4fPkcgZg4UEpwJM90NA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.5.tgz", - "integrity": "sha512-itVdge0NozgtgmtbZ25FVwWU3vGlE7x7feE/aOEJNkQfEpbkrF8Rj1QmnK+2blFfYE1xWt/iU+6/jUp/pv1+MA==", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/lib-storage": { - "version": "3.1085.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1085.0.tgz", - "integrity": "sha512-S+yCGIMxQ5Zs2A5ZDdYfXwOxu5kKjBaCQVOxp6+mnwCQYXUNkBD/aKCnW1eniMTavzz3YidhD5eTFpDlcUv2gQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.1085.0" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.13.tgz", - "integrity": "sha512-1r6EkFdSQ4quTP3pW8yWIcYuyDwdwdBxGr+kfuPFYE3DqR+1gBc6NyJneAyoIs+wc/cUfnyJ4ZYC0T2SQTxP9A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.5", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.13.tgz", - "integrity": "sha512-EA3+u2LD3kGcfRNmCSjyJuzX4XvG4zYv57i4ZksH+1IEciuSyHQGvzivEz7vZ+jbRPdAAe7WWKy/4M8InCKDcw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.12.tgz", - "integrity": "sha512-NxB2dS4/mV3380hNkC72TkhMaLLjWGGBeTAEucqlJptVVovTbNmQWZLwaMC74ICo9NZHmFiBVVTHzDfAh/3y6Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.972.14", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.14.tgz", - "integrity": "sha512-bqL+upATpOJ/7px4IVfMVxcM6Lyt9uRizmEx3mNg4N6+IQlnOaYXXOJ4TNX6P0mKPPW0lwn9ZW8QEhXwQuCH9A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-api-gateway": { - "version": "3.972.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-api-gateway/-/middleware-sdk-api-gateway-3.972.12.tgz", - "integrity": "sha512-Fb9oEuB3875hI/187dj4MclC/nlBzc/iTEOYecUjFoipRGxqBE38XPqiE0g8oshs9rJXCZJousW0e/aElDFuDA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.62", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.62.tgz", - "integrity": "sha512-k8JJwYXVYlOOjWnPZDThQS1xDFJgi5Dokt73qFlDtrZAbdcint5aIdjB9XgJAAQVP5OoqcefQmh1FYXiPpvsvw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-sqs": { - "version": "3.972.24", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sqs/-/middleware-sdk-sqs-3.972.24.tgz", - "integrity": "sha512-ej3vwWFzTP2B0FxlU2JelMaxplEncflFv2ARsoMQ9TXI/yfmsPEZw8zkOdsQp3rMEJ/vN7iKTYDYIcpeMmDRoQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.42", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.42.tgz", - "integrity": "sha512-U7jjlJKQnuUlI2swC2umFLFzLAxMLudSRFv+Bqk2F8ORmr5bG25qsFxGm4GEFwoZeGaFFnAFmTY0xReVRfyl2A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.31.tgz", - "integrity": "sha512-BDHTpwcsZHEBNEJzOg/B1BkFYJxAXY50dau/NyVWs3d51F0WgIUGSWZot/Os+N3KpDhXeaXnz37mWffAvduREw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/signature-v4-multi-region": "^3.996.39", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/fetch-http-handler": "^5.6.4", - "@smithy/node-http-handler": "^4.9.4", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.16.tgz", - "integrity": "sha512-/YaivCvKUkEeMN9VTKBSvBn5w/4osAM1YboM58DKaLF/vqFGf/FdJCLmppqiPPJWZaXcASqByVjc3evE7KHKdA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.39.tgz", - "integrity": "sha512-8+srXqYIF8KYMLC4FxMLEM5Ek7kUNibJu1R4m8/fUhhNYIZZz26oGtKkCr8I/HiG2fFQxBvaGgQZT4/mqRCSnA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.0", - "@smithy/signature-v4": "^5.6.3", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1083.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1083.0.tgz", - "integrity": "sha512-s0woKnxuHrExLc5L2ArIH5BMkbonHPtt+5hSBM8oknp9M6QTuUmmAmJ2E0EdzCGONrO+8+ADPqvv6UX0nNcc7A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.975.1", - "@aws-sdk/nested-clients": "^3.997.31", - "@aws-sdk/types": "^3.974.0", - "@smithy/core": "^3.29.2", - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.0.tgz", - "integrity": "sha512-QIBrw90CDm4O0UaIIzkU6DrFdeJzEb2Va5EPEVpyldj6sHJxB6cshhStJuhZxk3wR3PmjJlYsjPmY1kNb+KGBg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.974.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.974.0.tgz", - "integrity": "sha512-n/VlmXl4Yp9RS3i9+ALSr7Y+f1VrKJGX88Q8C67cg+xWzgv0n1+sE/7ZAxJZKEBNpP9tjmpgqWej8f1pWalbIA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "3.974.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.972.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.972.0.tgz", - "integrity": "sha512-6JHsl1V/a1ZW8D8AFfd4R52fwZPnZ5H4U6DS8m/bWT8qad72NvbOFAC7U2cDtFs2TShqUO3TEiX/EJibtY3ijg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.972.0", - "@smithy/types": "^4.12.0", - "@smithy/url-parser": "^4.2.8", - "@smithy/util-endpoints": "^3.2.8", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints/node_modules/@aws-sdk/types": { - "version": "3.972.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.972.0.tgz", - "integrity": "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.965.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", - "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.13.tgz", - "integrity": "sha512-wfk9ZdVwh187gdGXB1EyAoprwjSMt/bSfVtva+OaZx+LyNdKD7smlZf611yMd42UpfQ9vaS8NOftjSajgpdd+w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.973.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.28.tgz", - "integrity": "sha512-A2l/PTRzsOS9L8dmZbXtDyJQgeeX+qjqLJ+fr0UU5Dz0AUQMuxgZCPSLKZgUDlHAmLFuk34owdMEvJxmDTBgRg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.12", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.34.tgz", - "integrity": "sha512-wHhWL1y7sN3enBA8POrPpQM5jCcmu2ozyhbRei4c8OjVcEaEs6yLucLa/pla457ggS/ysuy7bosagz3HaJkZXA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@hapi/accept": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@hapi/accept/-/accept-6.0.3.tgz", - "integrity": "sha512-p72f9k56EuF0n3MwlBNThyVE5PXX40g+aQh+C/xbKrfzahM2Oispv3AXmOIU51t3j77zay1qrX7IIziZXspMlw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/ammo": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@hapi/ammo/-/ammo-6.0.1.tgz", - "integrity": "sha512-pmL+nPod4g58kXrMcsGLp05O2jF4P2Q3GiL8qYV7nKYEh3cGf+rV4P5Jyi2Uq0agGhVU63GtaSAfBEZOlrJn9w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/b64": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-6.0.1.tgz", - "integrity": "sha512-ZvjX4JQReUmBheeCq+S9YavcnMMHWqx3S0jHNXWIM1kQDxB9cyfSycpVvjfrKcIS8Mh5N3hmu/YKo4Iag9g2Kw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/boom": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-10.0.1.tgz", - "integrity": "sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/bounce": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@hapi/bounce/-/bounce-3.0.2.tgz", - "integrity": "sha512-d0XmlTi3H9HFDHhQLjg4F4auL1EY3Wqj7j7/hGDhFFe6xAbnm3qiGrXeT93zZnPH8gH+SKAFYiRzu26xkXcH3g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/bourne": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-3.0.0.tgz", - "integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/call": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@hapi/call/-/call-9.0.1.tgz", - "integrity": "sha512-uPojQRqEL1GRZR4xXPqcLMujQGaEpyVPRyBlD8Pp5rqgIwLhtveF9PkixiKru2THXvuN8mUrLeet5fqxKAAMGg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/catbox": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@hapi/catbox/-/catbox-12.1.1.tgz", - "integrity": "sha512-hDqYB1J+R0HtZg4iPH3LEnldoaBsar6bYp0EonBmNQ9t5CO+1CqgCul2ZtFveW1ReA5SQuze9GPSU7/aecERhw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2", - "@hapi/podium": "^5.0.0", - "@hapi/validate": "^2.0.1" - } - }, - "node_modules/@hapi/catbox-memory": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/catbox-memory/-/catbox-memory-6.0.2.tgz", - "integrity": "sha512-H1l4ugoFW/ZRkqeFrIo8p1rWN0PA4MDTfu4JmcoNDvnY975o29mqoZblqFTotxNHlEkMPpIiIBJTV+Mbi+aF0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/content": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/content/-/content-6.0.2.tgz", - "integrity": "sha512-OKyCOTjNR1hftwSjk9ueyAQTw8AwapvzBrPIWMGn39vhR5PmqLdYFmLc35bsSBye7gSMnlkXfc679bUdMIcRyQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.0" - } - }, - "node_modules/@hapi/cryptiles": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-6.0.3.tgz", - "integrity": "sha512-r6VKalpbMHz4ci3gFjFysBmhwCg70RpYZy6OkjEpdXzAYnYFX5XsW7n4YMJvuIYpnMwLxGUjK/cBhA7X3JDvXw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/file": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@hapi/file/-/file-3.0.0.tgz", - "integrity": "sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/h2o2": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@hapi/h2o2/-/h2o2-10.0.4.tgz", - "integrity": "sha512-dvD8+Y/Okc0fh0blqaYCLIrcy0+1LqIhMr7hjk8elLQZ9mkw2hKFB9dFKuRfWf+1nvHpGlW+PwccqkdebynQbg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2", - "@hapi/validate": "^2.0.1", - "@hapi/wreck": "^18.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/hapi": { - "version": "21.4.9", - "resolved": "https://registry.npmjs.org/@hapi/hapi/-/hapi-21.4.9.tgz", - "integrity": "sha512-YnecZOVx2AD08VvPl0ZaFS0MjEHqg+InGRmBRli731ct+VwI++dpu3BIYA1Z4SMr6HUAnpyvbQ1aq5woe3fBWg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/accept": "^6.0.3", - "@hapi/ammo": "^6.0.1", - "@hapi/boom": "^10.0.1", - "@hapi/bounce": "^3.0.2", - "@hapi/call": "^9.0.1", - "@hapi/catbox": "^12.1.1", - "@hapi/catbox-memory": "^6.0.2", - "@hapi/heavy": "^8.0.1", - "@hapi/hoek": "^11.0.7", - "@hapi/mimos": "^7.0.1", - "@hapi/podium": "^5.0.2", - "@hapi/shot": "^6.0.2", - "@hapi/somever": "^4.1.1", - "@hapi/statehood": "^8.2.1", - "@hapi/subtext": "^8.1.3", - "@hapi/teamwork": "^6.0.1", - "@hapi/topo": "^6.0.2", - "@hapi/validate": "^2.0.1" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@hapi/heavy": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@hapi/heavy/-/heavy-8.0.1.tgz", - "integrity": "sha512-gBD/NANosNCOp6RsYTsjo2vhr5eYA3BEuogk6cxY0QdhllkkTaJFYtTXv46xd6qhBVMbMMqcSdtqey+UQU3//w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/hoek": "^11.0.2", - "@hapi/validate": "^2.0.1" - } - }, - "node_modules/@hapi/hoek": { - "version": "11.0.7", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/iron": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-7.0.1.tgz", - "integrity": "sha512-tEZnrOujKpS6jLKliyWBl3A9PaE+ppuL/+gkbyPPDb/l2KSKQyH4lhMkVb+sBhwN+qaxxlig01JRqB8dk/mPxQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/b64": "^6.0.1", - "@hapi/boom": "^10.0.1", - "@hapi/bourne": "^3.0.0", - "@hapi/cryptiles": "^6.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/mimos": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@hapi/mimos/-/mimos-7.0.1.tgz", - "integrity": "sha512-b79V+BrG0gJ9zcRx1VGcCI6r6GEzzZUgiGEJVoq5gwzuB2Ig9Cax8dUuBauQCFKvl2YWSWyOc8mZ8HDaJOtkew==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2", - "mime-db": "^1.52.0" - } - }, - "node_modules/@hapi/nigel": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/nigel/-/nigel-5.0.1.tgz", - "integrity": "sha512-uv3dtYuB4IsNaha+tigWmN8mQw/O9Qzl5U26Gm4ZcJVtDdB1AVJOwX3X5wOX+A07qzpEZnOMBAm8jjSqGsU6Nw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2", - "@hapi/vise": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/pez": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@hapi/pez/-/pez-6.1.1.tgz", - "integrity": "sha512-yg2OS1tC0S1sHXvhUtWsfRn6lrKl9jKtRhZ+EI0woOW/gqX5vM2PZ1459ypCvCYDRLJ9nIyueeEH5MJV1ZDqIg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/b64": "^6.0.1", - "@hapi/boom": "^10.0.1", - "@hapi/content": "^6.0.1", - "@hapi/hoek": "^11.0.7", - "@hapi/nigel": "^5.0.1" - } - }, - "node_modules/@hapi/podium": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-5.0.2.tgz", - "integrity": "sha512-T7gf2JYHQQfEfewTQFbsaXoZxSvuXO/QBIGljucUQ/lmPnTTNAepoIKOakWNVWvo2fMEDjycu77r8k6dhreqHA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2", - "@hapi/teamwork": "^6.0.0", - "@hapi/validate": "^2.0.1" - } - }, - "node_modules/@hapi/shot": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/shot/-/shot-6.0.2.tgz", - "integrity": "sha512-WKK1ShfJTrL1oXC0skoIZQYzvLsyMDEF8lfcWuQBjpjCN29qivr9U36ld1z0nt6edvzv28etNMOqUF4klnHryw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2", - "@hapi/validate": "^2.0.1" - } - }, - "node_modules/@hapi/somever": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@hapi/somever/-/somever-4.1.1.tgz", - "integrity": "sha512-lt3QQiDDOVRatS0ionFDNrDIv4eXz58IibQaZQDOg4DqqdNme8oa0iPWcE0+hkq/KTeBCPtEOjDOBKBKwDumVg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/bounce": "^3.0.1", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/statehood": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@hapi/statehood/-/statehood-8.2.1.tgz", - "integrity": "sha512-xf72TG/QINW26jUu+uL5H+crE1o8GplIgfPWwPZhnAGJzetIVAQEQYvzq+C0aEVHg5/lMMtQ+L9UryuSa5Yjkg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/bounce": "^3.0.1", - "@hapi/bourne": "^3.0.0", - "@hapi/cryptiles": "^6.0.1", - "@hapi/hoek": "^11.0.2", - "@hapi/iron": "^7.0.1", - "@hapi/validate": "^2.0.1" - } - }, - "node_modules/@hapi/subtext": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@hapi/subtext/-/subtext-8.1.3.tgz", - "integrity": "sha512-WTpEZQjBP3UJ3gGunNl3w5Ao1EOJsuu2vttZ2KEcG+csSLxc0dI6VIkl2md2jDlHiQ2ARAoqdSUScy05A/NHtA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/bourne": "^3.0.0", - "@hapi/content": "^6.0.2", - "@hapi/file": "^3.0.0", - "@hapi/hoek": "^11.0.7", - "@hapi/pez": "^6.1.1", - "@hapi/wreck": "^18.1.1" - } - }, - "node_modules/@hapi/teamwork": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-6.0.1.tgz", - "integrity": "sha512-52OXRslUfYwXAOG8k58f2h2ngXYQGP0x5RPOo+eWA/FtyLgHjGMrE3+e9LSXP/0q2YfHAK5wj9aA9DTy1K+kyQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@hapi/topo": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/validate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-2.0.1.tgz", - "integrity": "sha512-NZmXRnrSLK8MQ9y/CMqE9WSspgB9xA41/LlYR0k967aSZebWr4yNrpxIbov12ICwKy4APSlWXZga9jN5p6puPA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2", - "@hapi/topo": "^6.0.1" - } - }, - "node_modules/@hapi/vise": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@hapi/vise/-/vise-5.0.1.tgz", - "integrity": "sha512-XZYWzzRtINQLedPYlIkSkUr7m5Ddwlu99V9elh8CSygXstfv3UnWIXT0QD+wmR0VAG34d2Vx3olqcEhRRoTu9A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@hapi/wreck": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@hapi/wreck/-/wreck-18.1.2.tgz", - "integrity": "sha512-3dMnV2pfhQiyEqu8DL3VBmxkdLiRDiiUDuG79Dp+UK1gL9ZxAfDOUhB6k3D5MLqcgJJ1IARyGFhwoc1NITr/pg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@hapi/boom": "^10.0.1", - "@hapi/bourne": "^3.0.0", - "@hapi/hoek": "^11.0.2" - } - }, - "node_modules/@jsep-plugin/assignment": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", - "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@jsep-plugin/regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", - "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.5.3.tgz", - "integrity": "sha512-TpS6Am5zSEtx3ow7VynThEL7UwRM06zZZcmFaP6Ij9hqKPfsFhTYCLcgU7gjFjw9QAI2kzwXrfS7InH8BivJTA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "3.29.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.3.tgz", - "integrity": "sha512-L+Ys6ecjk5vwPMAKHBpPKlJ3DkqwNcnfEISXBZIsVvWG/XKXfsAP8mwIYlTeLcd2ElHdesPI8OuOmJSFAPhm6A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.8.tgz", - "integrity": "sha512-q9J7JTiXrAhB8sDp4px97uEPT7CwKH61Co78grdNQvU8QZAdiuaSRhP0tUVf2ogy36RZTrlMU1rBmDEH+cnkiA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.6.5", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.5.tgz", - "integrity": "sha512-SuqeisTyPoiIPtIYru/sGxGyXzmZ+8nnFOhC+qRPglt06Ebd1yH//CDltZB2J/3WBNVhwfUaZ0EtHB3cm2X32g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.3.3.tgz", - "integrity": "sha512-tSUA38sM7kzMoLhqQ2aCGTwLXovjurz3jjG+a0sxqD4qT/4FhQr/wxMdhCumT70giM+axC1pPjimAHLlEQCfzw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.3.3.tgz", - "integrity": "sha512-wUWowbCm7DGczl6bfLI6wGGtoxwN5Pon8DhF0Q8AA4NvgLwYfLo3h2DWI7sHr33lLcEsyTLQKeUeTHydqSfQ5Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/md5-js": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.3.3.tgz", - "integrity": "sha512-pFw8gEMrHw9BbRwNm//UU4WgnVO7+dhfFRaSAkFPfwslWU2LXt0mM+oap3iFwGbdD8kuAWIeOAxqSiamOcM3Dw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-compression": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@smithy/middleware-compression/-/middleware-compression-4.5.8.tgz", - "integrity": "sha512-ODHXD5tDW3+25pfiLjJ2ZTIHRfWWxqVGPqIMz1NjmiV4bG4i1S0kuibHxik6WXibR03nmDGMiI1/hF6647F/Zg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "fflate": "0.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.3.3.tgz", - "integrity": "sha512-Up1XAYnj6oxFBypWpkhNpgX+yReQxkKAV/iLaeP0KVLb2oTkmA9X+UJuGBVvEA9uZIN06y0irDi7sBMuTZMVJg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.5.3.tgz", - "integrity": "sha512-p60HGFflWsJC6V9GAYeFgbfORn+9ILx8FqgMa/8PzA0rhIUxF57EKoOR4Irs6oe1oy8RLzhjhcGS8CBtPv/t+Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.6.3.tgz", - "integrity": "sha512-MnfYnJs3cBXK3ZBqbPzXRPHIp+QtgpkX5NogcUOWHPU5GbgTAQSIfPLi91lTcEbkFDcH2YbgjLPQjWeyQ689rA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.3.3.tgz", - "integrity": "sha512-RUVCZgn92izDAARs5OJSM2+KWSfTRvQWwN9t0MmiybT3pquRgDx9vD9t/YZjd/5lwcFbsNuPojJSddYQEZGeWw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.3.3.tgz", - "integrity": "sha512-+BPabWluqxo3EfMMvOgnAmPtWnCSzj+gf5mJ27wTZUbvS0hpdUIU1g80R01bEGKZx4JCi8P58jAXD9FUGMjhwA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.4.3.tgz", - "integrity": "sha512-vDtz5OuytrjP4o9GtAOz1JloN003p94utJIQeO0WAjorhpafFFjpbDOrP6btPoCN3UxaU/U84OIEt5dM7ZRRLA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.5.tgz", - "integrity": "sha512-bNqdxTQTxmLbomSmlkZFz8L6B/feQ2HHzw4L2zY7Ecp2XffYAZq2uzdWDdxJHJFbEvqd+SRuluJso0P8+xPdbw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.4.3.tgz", - "integrity": "sha512-P16TBD/d8ZcD9MHQ0ubQ9BbOYSd5HZKbHOLsyFWxKk2oBEoghbRFPfGOoqToZX1yrfLITXRylL16EyPP4IzLPg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.4.tgz", - "integrity": "sha512-B89bpf2t/y/wia6LZ+4JfHXYQT9PnVftsH05rgJKKIStS7r/4XSs9HOjtPoLtgcA6HCW9jVqX5DBbq7E0PAkiQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.29.3", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "4.13.3", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.13.3.tgz", - "integrity": "sha512-Z8mQ+YryjP5krDadV6unnp5035L4S1brafXpTiRmjPweKSaQ6X9CYDYWvmEggXjDIa1oufX/2a/bdwu8EIz/lw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz", - "integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.3.3.tgz", - "integrity": "sha512-TsMTAOnjuMOv1zJBw8cfYGWhopyc3og8tZX/KuyCPjg7V3ji3f4YjFOVu843UjBmrfS/+X6kwFv5ZKg7sSm1bQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-base64": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.4.3.tgz", - "integrity": "sha512-91lxjhFpAktA9yPBxniqVR/NSH9zyjMjLmoa+jbQHQFR9WiJA+n61T7HBrfh5APdEoAledJwGq8l4cS+ZJFUnQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.3.3.tgz", - "integrity": "sha512-/M6Ya1Fjq8hg3rYjiwwqTen6s1bAa3U3g/2eicBaBQfaoa4ymLUke/x4T8mwb9dSq/L8TQ4YgndS0MaB9ShgmA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.3.3.tgz", - "integrity": "sha512-M+zdSrevWj0grtZx2RBULPUyjTq1aB+n+13Hrm9owiGpow6DqY/WqiSj6sHVQy/rKp0j7NzV3TNf2LrwDel8JQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.4.3.tgz", - "integrity": "sha512-Q60hxKkMEkmBsOEzxlMWEymBWov0dtWGgoJhOUs6mE8k2FDPjK8NlsRdMkmO80n2pwzreHtrYcX5jiRP7ZkP3w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.3.3.tgz", - "integrity": "sha512-RYj+8gr95WiiBqvVghoRvL12NS9ryvLyufp7FOs7EzKwGX0W5gOVlXdCrFkJScSf8gxdjQMRyIZ3Y82/MvXQ3Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.5.3.tgz", - "integrity": "sha512-2JqSmzQtKDKqBckLl/9NXTL1fY+zQBU5fNGMpud7AT65vql0tVFhb2UEZNZmLSHayLeD+X/Qzn84oXw5KS+KSQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.3.3.tgz", - "integrity": "sha512-8NZwlQ+nyAIWn9YZxH14FC8ca0i6ZGW1aJyPjD+zMZz3k9jOhXXKhdCSRvjmcSYLW42uhbrxavXqMkrTKHyY3A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.4.3.tgz", - "integrity": "sha512-8RJXeU5lEhdNfXm4XAuHlf6VtNzd279Z2FJZSR7VaELYCR46ffgjJBSjc+3UAy7V1YqBOLV0G9gWhLB/nA44nA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.3.3.tgz", - "integrity": "sha512-c1QpRBn3aMsoqE64dd4Imgjy8Pynfw+eR7GkjElquxUFSnezwYVaOFm8JcYa+Bo/5ssbEyPKcT3+4bmrWYh6eQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.4.3.tgz", - "integrity": "sha512-WSHSF865zDGFGtJdMmYPI2Blq/MbUrn5CB4bLDg4ARbQ9z7oA87ZZ/FSiwNZbQrU/EiVyl9lpINswALgI4lZXA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-unflat-js": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/array-unflat-js/-/array-unflat-js-0.1.3.tgz", - "integrity": "sha512-8pljkLj4vfz2i7Tf3yB31tRrszjP8/kwIyABGfcZ1GcHlvdUB0Sbx0WzQkOPMqUBxa/bu4+/NAyHEpDtZJzlJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, - "node_modules/boxen": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", - "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.1", - "chalk": "^5.2.0", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/boxen/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/boxen/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", - "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/cli-sprintf-format": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cli-sprintf-format/-/cli-sprintf-format-1.1.1.tgz", - "integrity": "sha512-BbEjY9BEdA6wagVwTqPvmAwGB24U93rQPBFZUT8lNCDxXzre5LFHQUTJc70czjgUomVg8u8R5kW8oY9DYRFNeg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cli-color": "^2.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cli-sprintf-format/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-sprintf-format/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/content-disposition": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", - "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cron-parser": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", - "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "luxon": "^3.2.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/desm": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/desm/-/desm-1.3.1.tgz", - "integrity": "sha512-vgTAOosB1aHrmzjGnzFCbjvXbk8QAOC/36JxJhcBkeAuUy8QwRFxAWBHemiDpUB3cbrBruFUdzpUS21aocvaWg==", - "dev": true, - "license": "MIT" - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-cli": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.4.4.tgz", - "integrity": "sha512-XkBYCG0tPIes+YZr4SpfFv76SQrV/LeCE8CI7JSEMi3VR9MvTihCGTOtbIexD6i2mXF+6px7trb1imVCXSNMDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "dotenv": "^16.3.0", - "dotenv-expand": "^10.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/duration": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", - "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.46" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "license": "ISC", - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/execa/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/execa/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/execa/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.7.2" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fflate": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", - "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/filename-reserved-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-4.0.0.tgz", - "integrity": "sha512-9ZT504KxEQDamsOogZImAWGEN24R1uFAxU3ZS4AZqn2ooidmN68Olh7n4/RcA4lLatZztjA0ZSuxeLHVoCc8JA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/filenamify": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-7.0.2.tgz", - "integrity": "sha512-fz10TUqSZ1lG7ftW1KnRotJzMD8YRb6kaAQKpZJBLvqXXfFgIEpuazy1w2lK3zhMiBSdH/uF9LFlv5smJ2Jl1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "filename-reserved-regex": "^4.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/https-proxy-agent": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", - "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "proxy-agent-negotiate": "1.1.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-inside-container/node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/java-invoke-local": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/java-invoke-local/-/java-invoke-local-0.0.6.tgz", - "integrity": "sha512-gZmQKe1QrfkkMjCn8Qv9cpyJFyogTYqkP5WCobX5RNaHsJzIV/6NvAnlnouOcwKr29QrxLGDGcqYuJ+ae98s1A==", - "dev": true, - "license": "MIT", - "bin": { - "java-invoke-local": "lib/cli.js" - } - }, - "node_modules/jose": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", - "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsep": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.16.0" - } - }, - "node_modules/json-cycle": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.5.0.tgz", - "integrity": "sha512-GOehvd5PO2FeZ5T4c+RxobeT5a1PiGpF4u9/3+UvrMU4bhnVqzJY7hm39wg8PDCqkU91fWGH8qjWR4bn+wgq9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpath-plus": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", - "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" - }, - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/jsonschema": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", - "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/log": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/log/-/log-6.3.2.tgz", - "integrity": "sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "duration": "^0.2.2", - "es5-ext": "^0.10.64", - "event-emitter": "^0.3.5", - "sprintf-kit": "^2.0.2", - "type": "^2.7.3", - "uni-global": "^1.0.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/log-node": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/log-node/-/log-node-8.0.3.tgz", - "integrity": "sha512-1UBwzgYiCIDFs8A0rM2QdBFo8Wd8UQ0HrSTu/MNI+/2zN3NoHRj2fhplurAyuxTYUXu3Oohugq1jAn5s05u1MQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "ansi-regex": "^5.0.1", - "cli-color": "^2.0.1", - "cli-sprintf-format": "^1.1.1", - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "sprintf-kit": "^2.0.1", - "supports-color": "^8.1.1", - "type": "^2.5.0" - }, - "engines": { - "node": ">=10.0" - }, - "peerDependencies": { - "log": "^6.0.0" - } - }, - "node_modules/long-timeout": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", - "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es5-ext": "~0.10.2" - } - }, - "node_modules/luxon": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", - "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "license": "ISC", - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mnemonist": { - "version": "0.38.3", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", - "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", - "license": "MIT", - "dependencies": { - "obliterator": "^1.6.1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/node-schedule": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", - "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cron-parser": "^4.2.0", - "long-timeout": "0.1.1", - "sorted-array-functions": "^1.3.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/obliterator": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", - "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", - "license": "MIT" - }, - "node_modules/osls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/osls/-/osls-4.0.0.tgz", - "integrity": "sha512-ti1s4IhJLfpdWtgyb3gj8slDs1KoucRU0jNyqGIaEGPGCODiJtFXXVM3cs52pQLi3Ig2RBeqHzhD84vWOLvSeQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", - "@aws-sdk/client-api-gateway": "^3.1034.0", - "@aws-sdk/client-apigatewayv2": "^3.1034.0", - "@aws-sdk/client-cloudformation": "^3.1034.0", - "@aws-sdk/client-cloudwatch": "^3.1034.0", - "@aws-sdk/client-cloudwatch-logs": "^3.1034.0", - "@aws-sdk/client-cognito-identity-provider": "^3.1034.0", - "@aws-sdk/client-ecr": "^3.1034.0", - "@aws-sdk/client-eventbridge": "^3.1034.0", - "@aws-sdk/client-iam": "^3.1034.0", - "@aws-sdk/client-lambda": "^3.1034.0", - "@aws-sdk/client-s3": "^3.1034.0", - "@aws-sdk/client-ssm": "^3.1034.0", - "@aws-sdk/client-sts": "^3.1034.0", - "@aws-sdk/credential-providers": "^3.1034.0", - "@aws-sdk/lib-storage": "^3.1034.0", - "@smithy/core": "^3.23.16", - "@smithy/node-http-handler": "^4.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "content-disposition": "^2.0.1", - "cross-spawn": "^7.0.6", - "dotenv": "^17.4.2", - "dotenv-expand": "^13.0.0", - "ext": "^1.7.0", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "filenamify": "^7.0.1", - "https-proxy-agent": "^9.0.0", - "js-yaml": "^4.3.0", - "json-cycle": "^1.5.0", - "log": "^6.3.1", - "log-node": "^8.0.3", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "mime-types": "^3.0.2", - "semver": "^7.5.3", - "signal-exit": "^4.1.0", - "tsx": "^4.20.3", - "type": "^2.7.2", - "undici": "^7.25.0", - "write-file-atomic": "^7.0.1", - "yauzl": "^3.3.0", - "yazl": "^3.3.1" - }, - "bin": { - "osls": "bin/serverless.js", - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/osls/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/osls/node_modules/dotenv-expand": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", - "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^17.4.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/p-memoize": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/p-memoize/-/p-memoize-7.1.1.tgz", - "integrity": "sha512-DZ/bONJILHkQ721hSr/E9wMz5Am/OTJ9P6LhLFo2Tu+jL8044tgc9LwHO8g4PiaYePnlVVRAJcKmgy8J9MVFrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0", - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/p-memoize?sponsor=1" - } - }, - "node_modules/p-memoize/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-memoize/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-agent-negotiate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", - "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "kerberos": "^2.0.0" - }, - "peerDependenciesMeta": { - "kerberos": { - "optional": true - } - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serverless": { - "name": "osls", - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/osls/-/osls-4.0.0.tgz", - "integrity": "sha512-ti1s4IhJLfpdWtgyb3gj8slDs1KoucRU0jNyqGIaEGPGCODiJtFXXVM3cs52pQLi3Ig2RBeqHzhD84vWOLvSeQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^15.3.5", - "@aws-sdk/client-api-gateway": "^3.1034.0", - "@aws-sdk/client-apigatewayv2": "^3.1034.0", - "@aws-sdk/client-cloudformation": "^3.1034.0", - "@aws-sdk/client-cloudwatch": "^3.1034.0", - "@aws-sdk/client-cloudwatch-logs": "^3.1034.0", - "@aws-sdk/client-cognito-identity-provider": "^3.1034.0", - "@aws-sdk/client-ecr": "^3.1034.0", - "@aws-sdk/client-eventbridge": "^3.1034.0", - "@aws-sdk/client-iam": "^3.1034.0", - "@aws-sdk/client-lambda": "^3.1034.0", - "@aws-sdk/client-s3": "^3.1034.0", - "@aws-sdk/client-ssm": "^3.1034.0", - "@aws-sdk/client-sts": "^3.1034.0", - "@aws-sdk/credential-providers": "^3.1034.0", - "@aws-sdk/lib-storage": "^3.1034.0", - "@smithy/core": "^3.23.16", - "@smithy/node-http-handler": "^4.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "content-disposition": "^2.0.1", - "cross-spawn": "^7.0.6", - "dotenv": "^17.4.2", - "dotenv-expand": "^13.0.0", - "ext": "^1.7.0", - "fast-glob": "^3.3.3", - "fastest-levenshtein": "^1.0.16", - "filenamify": "^7.0.1", - "https-proxy-agent": "^9.0.0", - "js-yaml": "^4.3.0", - "json-cycle": "^1.5.0", - "log": "^6.3.1", - "log-node": "^8.0.3", - "memoizee": "^0.4.15", - "micromatch": "^4.0.5", - "mime-types": "^3.0.2", - "semver": "^7.5.3", - "signal-exit": "^4.1.0", - "tsx": "^4.20.3", - "type": "^2.7.2", - "undici": "^7.25.0", - "write-file-atomic": "^7.0.1", - "yauzl": "^3.3.0", - "yazl": "^3.3.1" - }, - "bin": { - "osls": "bin/serverless.js", - "serverless": "bin/serverless.js", - "sls": "bin/serverless.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/serverless-lss": { - "resolved": "../../packages/serverless-plugin", - "link": true - }, - "node_modules/serverless-offline": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/serverless-offline/-/serverless-offline-13.10.0.tgz", - "integrity": "sha512-TchZKgG9bLos347h4lHbuXgVLoODxx5mafcCTDT3CGWWcbv0k92L7/xoMTMCCvWGzeOC+7DMcXxJ0vSGbMjT7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@aws-sdk/client-lambda": "^3.636.0", - "@hapi/boom": "^10.0.1", - "@hapi/h2o2": "^10.0.4", - "@hapi/hapi": "^21.3.10", - "array-unflat-js": "^0.1.3", - "boxen": "^7.1.1", - "chalk": "^5.3.0", - "desm": "^1.3.1", - "execa": "^8.0.1", - "fs-extra": "^11.2.0", - "is-wsl": "^3.1.0", - "java-invoke-local": "0.0.6", - "jose": "^5.7.0", - "js-string-escape": "^1.0.1", - "jsonpath-plus": "^10.2.0", - "jsonschema": "^1.4.1", - "jszip": "^3.10.1", - "luxon": "^3.5.0", - "node-schedule": "^2.1.1", - "p-memoize": "^7.1.1", - "velocityjs": "^2.0.6", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "serverless": "^3.2.0" - } - }, - "node_modules/serverless-offline/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/serverless-offline/node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/serverless-offline/node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serverless-offline/node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/serverless/node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/serverless/node_modules/dotenv-expand": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-13.0.0.tgz", - "integrity": "sha512-aBfBS8eYIeXmpHI9ThIlA7/WLq+SLt18iXUZhb52rW89QLKQFoIpPG1bPeewoPZsTyjSSO3T7234FBVUM1V2rA==", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "dotenv": "^17.4.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sorted-array-functions": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", - "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==", - "dev": true, - "license": "MIT" - }, - "node_modules/sprintf-kit": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz", - "integrity": "sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", - "dev": true, - "license": "ISC", - "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.0.tgz", - "integrity": "sha512-eUdUIaCr963q2h5u3+QwvYp0+eqPvn+egeqZUm0hwERCqqx1E3kK5ehbGCvqSE5MQAULr67ww0cA3jKc3YkM1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, - "node_modules/uni-global": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", - "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/velocityjs": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/velocityjs/-/velocityjs-2.1.6.tgz", - "integrity": "sha512-8bc+yDR2NjwPioMqOLsAs5VBMT16xr/jTfStHMmr7btRPvbCCiEoZ9k9k/7Uhxl3bUxIHY7uDNbvm5rTwPZlXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/widest-line/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/widest-line/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/write-file-atomic": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", - "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", - "dev": true, - "license": "ISC", - "dependencies": { - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/yauzl": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", - "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yazl": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-3.3.1.tgz", - "integrity": "sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-crc32": "^1.0.0" - } - }, - "node_modules/yazl/node_modules/buffer-crc32": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - } - } -} diff --git a/examples/localstack-ultimate/package.json b/examples/localstack-ultimate/package.json deleted file mode 100644 index 9862739..0000000 --- a/examples/localstack-ultimate/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "localstack-ultimate", - "version": "0.0.0", - "private": true, - "description": "LocalStack Ultimate (paid-tier) example for Local Serverless Stack — runs against localstack/localstack-pro with LOCALSTACK_AUTH_TOKEN and keeps the serverless-offline integration path.", - "scripts": { - "setup": "npm install", - "offline": "dotenv -- serverless package && npm run dlq:wire && dotenv -- serverless offline start", - "package": "dotenv -- serverless package", - "deploy": "dotenv -- serverless deploy", - "console": "npx -y http-server . -p 8621 -c-1", - "dlq:wire": "node scripts/wire-dlq.js", - "seed": "npm run lss:seed", - "lss:start": "dotenv -- node ../../bin/cli.js start", - "lss:stop": "dotenv -- node ../../bin/cli.js stop", - "lss:status": "dotenv -- node ../../bin/cli.js status", - "lss:logs": "dotenv -- node ../../bin/cli.js logs", - "lss:seed": "dotenv -- node ../../bin/cli.js seed", - "lss:seed:clear": "dotenv -- node ../../bin/cli.js seed:clear" - }, - "dependencies": { - "@aws-sdk/client-dynamodb": "3.974.0", - "@aws-sdk/client-eventbridge": "^3.974.0", - "@aws-sdk/client-s3": "^3.974.0", - "@aws-sdk/client-sns": "3.974.0", - "@aws-sdk/client-sqs": "3.974.0", - "@aws-sdk/util-dynamodb": "3.974.0" - }, - "devDependencies": { - "dotenv-cli": "^7.4.4", - "serverless-lss": "file:../../packages/serverless-plugin", - "osls": "4.0.0", - "serverless-offline": "^13.6.0" - }, - "overrides": { - "serverless": "npm:osls@4.0.0" - } -} diff --git a/examples/localstack-ultimate/scripts/wire-dlq.js b/examples/localstack-ultimate/scripts/wire-dlq.js deleted file mode 100644 index b2ebaff..0000000 --- a/examples/localstack-ultimate/scripts/wire-dlq.js +++ /dev/null @@ -1,73 +0,0 @@ -// Applies the RedrivePolicy declared in serverless.yml to the LIVE LocalStack -// queue. LSS now carries RedrivePolicy from the CloudFormation template into -// CreateQueue, so this is a no-op safety net: it re-applies the same policy, -// which matters only for a queue provisioned by an older LSS (CreateQueue -// cannot change the attributes of a queue that already exists). -// `npm run offline` runs this right after `serverless package` (which -// registers the service and provisions the queues); it is also available -// standalone as `npm run dlq:wire`. -const { - SQSClient, - GetQueueUrlCommand, - GetQueueAttributesCommand, - SetQueueAttributesCommand, -} = require('@aws-sdk/client-sqs'); - -const sqs = new SQSClient({ - region: process.env.AWS_REGION || 'eu-west-1', - endpoint: process.env.AWS_ENDPOINT || 'http://localhost:4571', - credentials: { accessKeyId: 'test', secretAccessKey: 'test' }, -}); - -const QUEUE = 'localstack-ultimate-OrderProcessing'; -const DLQ = 'localstack-ultimate-OrderProcessingDLQ'; -const MAX_RECEIVE_COUNT = 3; - -const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); - -// Registration provisions the queues asynchronously to this script, so poll -// for up to ~30s before giving up. -async function getQueueUrlWithRetry(name) { - for (let attempt = 1; attempt <= 30; attempt++) { - try { - const res = await sqs.send(new GetQueueUrlCommand({ QueueName: name })); - return res.QueueUrl; - } catch { - await sleep(1000); - } - } - return undefined; -} - -async function main() { - const queueUrl = await getQueueUrlWithRetry(QUEUE); - const dlqUrl = await getQueueUrlWithRetry(DLQ); - if (!queueUrl || !dlqUrl) { - // Fail soft: don't block `npm run offline` when LSS/LocalStack isn't up - // yet — re-run `npm run dlq:wire` once it is. - console.warn(`[wire-dlq] ⚠ queues not found on ${process.env.AWS_ENDPOINT || 'http://localhost:4571'} — is LSS running (npm run lss:start)? Skipping.`); - return; - } - - const attrs = await sqs.send(new GetQueueAttributesCommand({ - QueueUrl: dlqUrl, - AttributeNames: ['QueueArn'], - })); - const dlqArn = attrs.Attributes && attrs.Attributes.QueueArn; - - await sqs.send(new SetQueueAttributesCommand({ - QueueUrl: queueUrl, - Attributes: { - RedrivePolicy: JSON.stringify({ - deadLetterTargetArn: dlqArn, - maxReceiveCount: MAX_RECEIVE_COUNT, - }), - }, - })); - - console.log(`[wire-dlq] ✓ RedrivePolicy set on ${QUEUE} → ${DLQ} (maxReceiveCount: ${MAX_RECEIVE_COUNT})`); -} - -main().catch((err) => { - console.warn(`[wire-dlq] ⚠ ${err.message} — skipping.`); -}); diff --git a/examples/localstack-ultimate/seeds/localstack-ultimate-Orders.json b/examples/localstack-ultimate/seeds/localstack-ultimate-Orders.json deleted file mode 100644 index d2dd3e7..0000000 --- a/examples/localstack-ultimate/seeds/localstack-ultimate-Orders.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "userId": "u-alice", - "orderId": "o-1001", - "status": "CONFIRMED", - "items": [{ "sku": "BOOK-01", "price": 25, "qty": 2 }], - "total": 50, - "createdAt": "2026-05-10T09:00:00.000Z", - "processedAt": "2026-05-10T09:00:02.000Z" - }, - { - "userId": "u-alice", - "orderId": "o-1002", - "status": "PENDING_REVIEW", - "items": [{ "sku": "LAPTOP-XL", "price": 1500, "qty": 1 }], - "total": 1500, - "createdAt": "2026-05-12T14:20:00.000Z", - "processedAt": "2026-05-12T14:20:01.000Z" - }, - { - "userId": "u-bob", - "orderId": "o-1003", - "status": "CONFIRMED", - "items": [ - { "sku": "MUG-RED", "price": 12, "qty": 3 }, - { "sku": "STICKER-PK", "price": 5, "qty": 4 } - ], - "total": 56, - "createdAt": "2026-05-13T16:45:00.000Z", - "processedAt": "2026-05-13T16:45:01.000Z" - } -] diff --git a/examples/localstack-ultimate/seeds/localstack-ultimate-Sessions.json b/examples/localstack-ultimate/seeds/localstack-ultimate-Sessions.json deleted file mode 100644 index 5f13c6a..0000000 --- a/examples/localstack-ultimate/seeds/localstack-ultimate-Sessions.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "sessionId": "s-expired-demo", - "userId": "u-carol", - "createdAt": "2026-01-01T08:00:00.000Z", - "expiresAt": 1767261600 - }, - { - "sessionId": "s-alice-forever", - "userId": "u-alice", - "createdAt": "2026-05-01T10:05:00.000Z", - "expiresAt": 4102444800 - }, - { - "sessionId": "s-bob-forever", - "userId": "u-bob", - "createdAt": "2026-05-02T11:35:00.000Z", - "expiresAt": 4102444800 - } -] diff --git a/examples/localstack-ultimate/seeds/localstack-ultimate-Users.json b/examples/localstack-ultimate/seeds/localstack-ultimate-Users.json deleted file mode 100644 index ae5cead..0000000 --- a/examples/localstack-ultimate/seeds/localstack-ultimate-Users.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "userId": "u-alice", - "name": "Alice Hopper", - "email": "alice@example.com", - "active": true, - "createdAt": "2026-05-01T10:00:00.000Z", - "roles": ["admin", "founder"] - }, - { - "userId": "u-bob", - "name": "Bob Turing", - "email": "bob@example.com", - "active": true, - "createdAt": "2026-05-02T11:30:00.000Z", - "roles": ["engineer"] - }, - { - "userId": "u-carol", - "name": "Carol Lovelace", - "email": "carol@example.com", - "active": false, - "createdAt": "2026-05-03T08:15:00.000Z", - "roles": ["intern"] - } -] diff --git a/examples/localstack-ultimate/serverless.yml b/examples/localstack-ultimate/serverless.yml deleted file mode 100644 index 8abab75..0000000 --- a/examples/localstack-ultimate/serverless.yml +++ /dev/null @@ -1,359 +0,0 @@ -service: localstack-ultimate - -frameworkVersion: '>=3' - -provider: - name: aws - runtime: nodejs20.x - region: eu-west-1 - environment: - USERS_TABLE: ${self:service}-Users - SESSIONS_TABLE: ${self:service}-Sessions - ORDERS_TABLE: ${self:service}-Orders - AUDIT_TABLE: ${self:service}-AuditTrail - ORDER_QUEUE_URL: http://localhost:4571/000000000000/${self:service}-OrderProcessing - ORDER_EVENTS_TOPIC_ARN: arn:aws:sns:${self:provider.region}:${self:custom.accountId}:${self:service}-OrderEvents - ORDER_EVENTS_BUS: ultimate-order-events - UPLOADS_BUCKET: localstack-ultimate-uploads - AWS_ENDPOINT: http://localhost:4571 - # Served by the LSS aoss sidecar (LocalStack has no OpenSearch Serverless - # in any edition): /_aoss/. On real AWS you would - # read it from GetAtt ProductsCollection.CollectionEndpoint. - OPENSEARCH_ENDPOINT: http://localhost:14567/_aoss/ultimate-products - PRODUCTS_INDEX: products - -plugins: - - serverless-lss - - serverless-offline - -custom: - accountId: '000000000000' - orchestrator: - enabled: true - orchestratorUrl: http://localhost:3111 - serverless-offline: - httpPort: 3002 - lambdaPort: 3003 - -functions: - health: - handler: src/handlers/health.handler - events: - - http: - path: /health - method: get - cors: true - - createUser: - handler: src/handlers/createUser.handler - events: - - http: - path: /users - method: post - cors: true - - listUsers: - handler: src/handlers/listUsers.handler - events: - - http: - path: /users - method: get - cors: true - - enqueueOrder: - handler: src/handlers/enqueueOrder.handler - events: - - http: - path: /orders - method: post - cors: true - - # SQS consumer. ReportBatchItemFailures makes the redrive demo work: poison - # orders (total <= 0 / missing userId) are reported as batch item failures, - # SQS keeps re-delivering them and, after maxReceiveCount receives, moves - # them to the OrderProcessingDLQ (RedrivePolicy below). - processOrderQueue: - handler: src/handlers/processOrderQueue.handler - events: - - sqs: - arn: - Fn::GetAtt: - - OrderProcessingQueue - - Arn - batchSize: 5 - functionResponseType: ReportBatchItemFailures - - onOrderStream: - handler: src/handlers/onOrderStream.handler - events: - - stream: - type: dynamodb - arn: - Fn::GetAtt: - - OrdersTable - - StreamArn - batchSize: 10 - - uploadFile: - handler: src/handlers/uploadFile.handler - events: - - http: - path: /uploads - method: post - cors: true - - listUploads: - handler: src/handlers/listUploads.handler - events: - - http: - path: /uploads - method: get - cors: true - - # Triggered when an object is created in the uploads bucket. - # The bucket notification is wired via NotificationConfiguration below. - onUpload: - handler: src/handlers/onUpload.handler - - # eventBridge trigger with pattern filtering against the custom bus declared - # in resources (referenced by ARN so Serverless does not create a second - # bus). processOrderQueue and purgeSessions publish onto the bus with plain - # SDK PutEvents calls; events from any other source are not delivered here. - # The handler receives the REAL EventBridge envelope (source, detail-type, - # detail) — no Records wrapper. - auditEvents: - handler: src/handlers/auditEvents.handler - events: - - eventBridge: - eventBus: arn:aws:events:${self:provider.region}:${self:custom.accountId}:event-bus/ultimate-order-events - pattern: - source: - - ultimate.orders - - ultimate.scheduler - - # GET /audit — lists the AuditTrail entries written by auditEvents so the - # bus → rule → Lambda flow is observable over plain HTTP. - getAudit: - handler: src/handlers/getAudit.handler - events: - - http: - path: /audit - method: get - cors: true - - # Scheduled function — compiled to an EventBridge rule on the default bus; - # LocalStack fires it every 2 minutes through the LSS proxy → Invoke API. - # Purges Sessions rows whose expiresAt (epoch seconds) is in the past and - # publishes a sessions.purged event onto the custom bus (→ audit trail). - purgeSessions: - handler: src/handlers/purgeSessions.handler - events: - - schedule: rate(2 minutes) - - # OpenSearch Serverless product catalog. LocalStack has NO aoss support in - # any edition, so these handlers talk straight to the LSS aoss sidecar - # (OPENSEARCH_ENDPOINT above) — the ultimate-products collection declared in - # resources is provisioned there on registration. - createProduct: - handler: src/handlers/createProduct.handler - events: - - http: - path: /products - method: post - cors: true - - getProduct: - handler: src/handlers/getProduct.handler - events: - - http: - path: /products/{id} - method: get - cors: true - - deleteProduct: - handler: src/handlers/deleteProduct.handler - events: - - http: - path: /products/{id} - method: delete - cors: true - - # GET /search?q=&category=&maxPrice= — full-text search + filters. - searchProducts: - handler: src/handlers/searchProducts.handler - events: - - http: - path: /search - method: get - cors: true - - # GET /stats — terms + avg aggregations over the whole catalog. - productStats: - handler: src/handlers/productStats.handler - events: - - http: - path: /stats - method: get - cors: true - -resources: - Resources: - # Users — PK only, NO TTL configured (will surface a warning in the UI). - UsersTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: ${self:service}-Users - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: userId - AttributeType: S - KeySchema: - - AttributeName: userId - KeyType: HASH - - # Sessions — PK only, intended for TTL (you can enable it from the Settings tab in the UI). - SessionsTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: ${self:service}-Sessions - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: sessionId - AttributeType: S - KeySchema: - - AttributeName: sessionId - KeyType: HASH - - # Orders — composite key + GSI on status + DynamoDB stream. - OrdersTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: ${self:service}-Orders - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: userId - AttributeType: S - - AttributeName: orderId - AttributeType: S - - AttributeName: status - AttributeType: S - KeySchema: - - AttributeName: userId - KeyType: HASH - - AttributeName: orderId - KeyType: RANGE - GlobalSecondaryIndexes: - - IndexName: ByStatus - KeySchema: - - AttributeName: status - KeyType: HASH - - AttributeName: orderId - KeyType: RANGE - Projection: - ProjectionType: ALL - StreamSpecification: - StreamViewType: NEW_AND_OLD_IMAGES - - # AuditTrail — filled by the auditEvents eventBridge trigger; read back - # over GET /audit. - AuditTrailTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: ${self:service}-AuditTrail - BillingMode: PAY_PER_REQUEST - AttributeDefinitions: - - AttributeName: auditId - AttributeType: S - KeySchema: - - AttributeName: auditId - KeyType: HASH - - # VisibilityTimeout is deliberately short (10s) so the DLQ demo resolves in - # ~30s instead of minutes: a poison message is re-received every 10s and - # redriven to the DLQ after the 3rd receive. LSS's CloudFormation parser now - # carries RedrivePolicy through to CreateQueue, so `npm run offline`'s - # scripts/wire-dlq.js step is only a no-op safety net (it re-applies the same - # policy to a queue provisioned by an older LSS). - OrderProcessingQueue: - Type: AWS::SQS::Queue - Properties: - QueueName: ${self:service}-OrderProcessing - VisibilityTimeout: 10 - MessageRetentionPeriod: 345600 - RedrivePolicy: - deadLetterTargetArn: - Fn::GetAtt: - - OrderProcessingDLQ - - Arn - maxReceiveCount: 3 - - # Dead-letter queue — poison orders land here; watch them accumulate in - # the dashboard's Queues tab. - OrderProcessingDLQ: - Type: AWS::SQS::Queue - Properties: - QueueName: ${self:service}-OrderProcessingDLQ - MessageRetentionPeriod: 345600 - - OrderEventsTopic: - Type: AWS::SNS::Topic - Properties: - TopicName: ${self:service}-OrderEvents - - # Custom EventBridge bus — processOrderQueue (order.processed) and - # purgeSessions (sessions.purged) publish here; the auditEvents rule - # (pattern-filtered) consumes. - OrderEventsBus: - Type: AWS::Events::EventBus - Properties: - Name: ultimate-order-events - - # S3 bucket with a notification that fires the onUpload Lambda whenever a - # new object is created under the "incoming/" prefix. - UploadsBucket: - Type: AWS::S3::Bucket - Properties: - BucketName: localstack-ultimate-uploads - NotificationConfiguration: - LambdaConfigurations: - - Event: s3:ObjectCreated:* - Function: - Fn::GetAtt: - - OnUploadLambdaFunction - - Arn - Filter: - S3Key: - Rules: - - Name: prefix - Value: incoming/ - - # OpenSearch Serverless collection — LocalStack cannot provision this - # (no aoss in any edition), so LSS serves it in-process via the aoss - # sidecar on 14567; the data plane is /_aoss/ultimate-products. - ProductsCollection: - Type: AWS::OpenSearchServerless::Collection - Properties: - Name: ultimate-products - Type: SEARCH - Description: Ultimate product catalog full-text search - - # On AWS a collection cannot be created without an encryption policy and is - # unreachable without a data-access policy. LSS accepts and skips both with - # a registration warning — nothing enforces them locally — so the template - # stays deployable as-is to the real cloud. - ProductsEncryptionPolicy: - Type: AWS::OpenSearchServerless::SecurityPolicy - Properties: - Name: ultimate-products-encryption - Type: encryption - Policy: '{"Rules":[{"ResourceType":"collection","Resource":["collection/ultimate-products"]}],"AWSOwnedKey":true}' - - ProductsAccessPolicy: - Type: AWS::OpenSearchServerless::AccessPolicy - Properties: - Name: ultimate-products-access - Type: data - Policy: '[{"Rules":[{"ResourceType":"index","Resource":["index/ultimate-products/*"],"Permission":["aoss:*"]}],"Principal":["arn:aws:iam::000000000000:role/local-dev"]}]' - -package: - individually: false diff --git a/examples/localstack-ultimate/src/handlers/auditEvents.js b/examples/localstack-ultimate/src/handlers/auditEvents.js deleted file mode 100644 index dec79aa..0000000 --- a/examples/localstack-ultimate/src/handlers/auditEvents.js +++ /dev/null @@ -1,27 +0,0 @@ -const { PutItemCommand } = require('@aws-sdk/client-dynamodb'); -const { marshall } = require('@aws-sdk/util-dynamodb'); -const { dynamo } = require('./aws'); - -// EventBridge target — receives the event exactly as AWS delivers it: -// { version, id, source, "detail-type", detail, ... }. No Records wrapper. -// The rule pattern (source: ultimate.orders | ultimate.scheduler) on the -// ultimate-order-events bus filtered it here; each matched event becomes a -// row in the AuditTrail table, readable via GET /audit. -exports.handler = async (event) => { - console.log(`[auditEvents] ${event.source} → ${event['detail-type']} (${event.id})`); - - const entry = { - auditId: event.id, - source: event.source, - detailType: event['detail-type'], - detail: event.detail, - receivedAt: new Date().toISOString(), - }; - - await dynamo.send(new PutItemCommand({ - TableName: process.env.AUDIT_TABLE, - Item: marshall(entry, { removeUndefinedValues: true }), - })); - - return { stored: entry.auditId }; -}; diff --git a/examples/localstack-ultimate/src/handlers/aws.js b/examples/localstack-ultimate/src/handlers/aws.js deleted file mode 100644 index 976048a..0000000 --- a/examples/localstack-ultimate/src/handlers/aws.js +++ /dev/null @@ -1,21 +0,0 @@ -const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); -const { SQSClient } = require('@aws-sdk/client-sqs'); -const { SNSClient } = require('@aws-sdk/client-sns'); -const { S3Client } = require('@aws-sdk/client-s3'); -const { EventBridgeClient } = require('@aws-sdk/client-eventbridge'); - -const baseConfig = { - region: process.env.AWS_REGION || 'eu-west-1', - endpoint: process.env.AWS_ENDPOINT || 'http://localhost:4571', - credentials: { accessKeyId: 'test', secretAccessKey: 'test' }, -}; - -module.exports = { - dynamo: new DynamoDBClient(baseConfig), - sqs: new SQSClient(baseConfig), - sns: new SNSClient(baseConfig), - eventBridge: new EventBridgeClient(baseConfig), - // forcePathStyle is required so LocalStack sees the bucket name in the URL path - // rather than as a virtual-host subdomain. - s3: new S3Client({ ...baseConfig, forcePathStyle: true }), -}; diff --git a/examples/localstack-ultimate/src/handlers/createProduct.js b/examples/localstack-ultimate/src/handlers/createProduct.js deleted file mode 100644 index 28bb11c..0000000 --- a/examples/localstack-ultimate/src/handlers/createProduct.js +++ /dev/null @@ -1,35 +0,0 @@ -const { randomUUID } = require('crypto'); -const { request, INDEX } = require('./opensearch'); -const respond = require('./respond'); - -// POST /products — body: { "name": "...", "category": "...", "price": 12.5, "tags": ["..."] } -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return respond(400, { error: 'invalid json' }); - } - - const { name, category, price, tags } = payload; - if (!name || !category || typeof price !== 'number') { - return respond(400, { error: 'name, category and numeric price are required' }); - } - - const id = payload.id || randomUUID(); - const product = { - name, - category, - price, - tags: Array.isArray(tags) ? tags : [], - createdAt: new Date().toISOString(), - }; - - const { status, json } = await request('PUT', `/${INDEX}/_doc/${encodeURIComponent(id)}`, product); - if (status >= 400) { - return respond(502, { error: 'indexing failed', detail: json }); - } - - console.log(`[createProduct] ${id} indexed (${json.result})`); - return respond(201, { id, ...product }); -}; diff --git a/examples/localstack-ultimate/src/handlers/createUser.js b/examples/localstack-ultimate/src/handlers/createUser.js deleted file mode 100644 index 841218b..0000000 --- a/examples/localstack-ultimate/src/handlers/createUser.js +++ /dev/null @@ -1,34 +0,0 @@ -const { PutItemCommand } = require('@aws-sdk/client-dynamodb'); -const { marshall } = require('@aws-sdk/util-dynamodb'); -const { randomUUID } = require('crypto'); -const { dynamo } = require('./aws'); -const respond = require('./respond'); - -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return respond(400, { error: 'invalid json' }); - } - - const { name, email } = payload; - if (!name || !email) { - return respond(400, { error: 'name and email are required' }); - } - - const user = { - userId: randomUUID(), - name, - email, - createdAt: new Date().toISOString(), - active: true, - }; - - await dynamo.send(new PutItemCommand({ - TableName: process.env.USERS_TABLE, - Item: marshall(user), - })); - - return respond(201, user); -}; diff --git a/examples/localstack-ultimate/src/handlers/deleteProduct.js b/examples/localstack-ultimate/src/handlers/deleteProduct.js deleted file mode 100644 index bb0fcbc..0000000 --- a/examples/localstack-ultimate/src/handlers/deleteProduct.js +++ /dev/null @@ -1,14 +0,0 @@ -const { request, INDEX } = require('./opensearch'); -const respond = require('./respond'); - -// DELETE /products/{id} -exports.handler = async (event) => { - const id = event.pathParameters && event.pathParameters.id; - const { status } = await request('DELETE', `/${INDEX}/_doc/${encodeURIComponent(id)}`); - - if (status === 404) { - return respond(404, { error: `product ${id} not found` }); - } - console.log(`[deleteProduct] ${id} deleted`); - return respond(200, { deleted: id }); -}; diff --git a/examples/localstack-ultimate/src/handlers/enqueueOrder.js b/examples/localstack-ultimate/src/handlers/enqueueOrder.js deleted file mode 100644 index e615665..0000000 --- a/examples/localstack-ultimate/src/handlers/enqueueOrder.js +++ /dev/null @@ -1,32 +0,0 @@ -const { SendMessageCommand } = require('@aws-sdk/client-sqs'); -const { randomUUID } = require('crypto'); -const { sqs } = require('./aws'); -const respond = require('./respond'); - -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return respond(400, { error: 'invalid json' }); - } - - const { userId, items } = payload; - if (!userId || !Array.isArray(items) || items.length === 0) { - return respond(400, { error: 'userId and non-empty items[] are required' }); - } - - const order = { - orderId: randomUUID(), - userId, - items, - createdAt: new Date().toISOString(), - }; - - await sqs.send(new SendMessageCommand({ - QueueUrl: process.env.ORDER_QUEUE_URL, - MessageBody: JSON.stringify(order), - })); - - return respond(202, { enqueued: true, order }); -}; diff --git a/examples/localstack-ultimate/src/handlers/getAudit.js b/examples/localstack-ultimate/src/handlers/getAudit.js deleted file mode 100644 index e6b8f29..0000000 --- a/examples/localstack-ultimate/src/handlers/getAudit.js +++ /dev/null @@ -1,15 +0,0 @@ -const { ScanCommand } = require('@aws-sdk/client-dynamodb'); -const { unmarshall } = require('@aws-sdk/util-dynamodb'); -const { dynamo } = require('./aws'); -const respond = require('./respond'); - -// GET /audit — makes the bus → rule → auditEvents flow observable: whatever -// the eventBridge trigger stored shows up here, newest first. -exports.handler = async () => { - const res = await dynamo.send(new ScanCommand({ TableName: process.env.AUDIT_TABLE })); - const entries = (res.Items || []) - .map((i) => unmarshall(i)) - .sort((a, b) => String(b.receivedAt || '').localeCompare(String(a.receivedAt || ''))) - .slice(0, 50); - return respond(200, { count: entries.length, entries }); -}; diff --git a/examples/localstack-ultimate/src/handlers/getProduct.js b/examples/localstack-ultimate/src/handlers/getProduct.js deleted file mode 100644 index 0d4fd52..0000000 --- a/examples/localstack-ultimate/src/handlers/getProduct.js +++ /dev/null @@ -1,13 +0,0 @@ -const { request, INDEX } = require('./opensearch'); -const respond = require('./respond'); - -// GET /products/{id} -exports.handler = async (event) => { - const id = event.pathParameters && event.pathParameters.id; - const { status, json } = await request('GET', `/${INDEX}/_doc/${encodeURIComponent(id)}`); - - if (status === 404) { - return respond(404, { error: `product ${id} not found` }); - } - return respond(200, { id: json._id, ...json._source }); -}; diff --git a/examples/localstack-ultimate/src/handlers/health.js b/examples/localstack-ultimate/src/handlers/health.js deleted file mode 100644 index 26271c8..0000000 --- a/examples/localstack-ultimate/src/handlers/health.js +++ /dev/null @@ -1,3 +0,0 @@ -const respond = require('./respond'); - -exports.handler = async () => respond(200, { ok: true, service: 'localstack-ultimate', ts: Date.now() }); diff --git a/examples/localstack-ultimate/src/handlers/listUploads.js b/examples/localstack-ultimate/src/handlers/listUploads.js deleted file mode 100644 index 6f37636..0000000 --- a/examples/localstack-ultimate/src/handlers/listUploads.js +++ /dev/null @@ -1,22 +0,0 @@ -const { ListObjectsV2Command } = require('@aws-sdk/client-s3'); -const { s3 } = require('./aws'); -const respond = require('./respond'); - -// GET /uploads?prefix=incoming/ -exports.handler = async (event) => { - const prefix = (event.queryStringParameters && event.queryStringParameters.prefix) || undefined; - - const response = await s3.send(new ListObjectsV2Command({ - Bucket: process.env.UPLOADS_BUCKET, - Prefix: prefix, - MaxKeys: 100, - })); - - const objects = (response.Contents || []).map(o => ({ - key: o.Key, - size: o.Size, - lastModified: o.LastModified, - })); - - return respond(200, { bucket: process.env.UPLOADS_BUCKET, count: objects.length, objects }); -}; diff --git a/examples/localstack-ultimate/src/handlers/listUsers.js b/examples/localstack-ultimate/src/handlers/listUsers.js deleted file mode 100644 index c9fcf88..0000000 --- a/examples/localstack-ultimate/src/handlers/listUsers.js +++ /dev/null @@ -1,10 +0,0 @@ -const { ScanCommand } = require('@aws-sdk/client-dynamodb'); -const { unmarshall } = require('@aws-sdk/util-dynamodb'); -const { dynamo } = require('./aws'); -const respond = require('./respond'); - -exports.handler = async () => { - const res = await dynamo.send(new ScanCommand({ TableName: process.env.USERS_TABLE })); - const users = (res.Items || []).map((i) => unmarshall(i)); - return respond(200, { count: users.length, users }); -}; diff --git a/examples/localstack-ultimate/src/handlers/onOrderStream.js b/examples/localstack-ultimate/src/handlers/onOrderStream.js deleted file mode 100644 index 79a428c..0000000 --- a/examples/localstack-ultimate/src/handlers/onOrderStream.js +++ /dev/null @@ -1,31 +0,0 @@ -const { PublishCommand } = require('@aws-sdk/client-sns'); -const { unmarshall } = require('@aws-sdk/util-dynamodb'); -const { sns } = require('./aws'); - -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[onOrderStream] received ${records.length} stream record(s)`); - - for (const record of records) { - const eventName = record.eventName; // INSERT | MODIFY | REMOVE - const newImage = record.dynamodb?.NewImage ? unmarshall(record.dynamodb.NewImage) : null; - const oldImage = record.dynamodb?.OldImage ? unmarshall(record.dynamodb.OldImage) : null; - - const message = { - type: `order.${eventName.toLowerCase()}`, - orderId: (newImage || oldImage)?.orderId, - userId: (newImage || oldImage)?.userId, - status: newImage?.status, - total: newImage?.total, - occurredAt: new Date().toISOString(), - }; - - await sns.send(new PublishCommand({ - TopicArn: process.env.ORDER_EVENTS_TOPIC_ARN, - Subject: message.type, - Message: JSON.stringify(message), - })); - - console.log(`[onOrderStream] published ${message.type} for ${message.orderId}`); - } -}; diff --git a/examples/localstack-ultimate/src/handlers/onUpload.js b/examples/localstack-ultimate/src/handlers/onUpload.js deleted file mode 100644 index 96d7919..0000000 --- a/examples/localstack-ultimate/src/handlers/onUpload.js +++ /dev/null @@ -1,54 +0,0 @@ -const { GetObjectCommand } = require('@aws-sdk/client-s3'); -const { PutItemCommand } = require('@aws-sdk/client-dynamodb'); -const { marshall } = require('@aws-sdk/util-dynamodb'); -const { s3, dynamo } = require('./aws'); - -// Triggered by the S3 bucket notification when an object is created under -// "incoming/". This handler reads the object back, derives some metadata, and -// records it in the Orders table to prove the round-trip works end-to-end. -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[onUpload] received ${records.length} S3 event(s)`); - - for (const record of records) { - const bucket = record.s3 && record.s3.bucket && record.s3.bucket.name; - const key = record.s3 && record.s3.object && decodeURIComponent(record.s3.object.key.replace(/\+/g, ' ')); - if (!bucket || !key) { - console.warn('[onUpload] skipping malformed record'); - continue; - } - - let size = (record.s3.object && record.s3.object.size) || 0; - let preview; - try { - const obj = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key })); - const chunks = []; - for await (const chunk of obj.Body) chunks.push(chunk); - const body = Buffer.concat(chunks); - size = body.length; - preview = body.slice(0, 120).toString('utf-8'); - } catch (err) { - console.warn(`[onUpload] could not read s3://${bucket}/${key}: ${err.message}`); - } - - // Stash an entry in Orders so the trigger is observable from the UI's - // DynamoDB explorer without adding a dedicated table. - const item = { - userId: 's3-upload', - orderId: `${bucket}/${key}`, - status: 'UPLOADED', - total: size, - items: preview ? [{ preview }] : [], - processedAt: new Date().toISOString(), - }; - - await dynamo.send(new PutItemCommand({ - TableName: process.env.ORDERS_TABLE, - Item: marshall(item, { removeUndefinedValues: true }), - })); - - console.log(`[onUpload] indexed s3://${bucket}/${key} (${size} bytes)`); - } - - return { batchItemFailures: [] }; -}; diff --git a/examples/localstack-ultimate/src/handlers/opensearch.js b/examples/localstack-ultimate/src/handlers/opensearch.js deleted file mode 100644 index a155f89..0000000 --- a/examples/localstack-ultimate/src/handlers/opensearch.js +++ /dev/null @@ -1,25 +0,0 @@ -// Minimal OpenSearch REST helper over Node's global fetch. LocalStack has no -// OpenSearch Serverless (aoss) in any edition, so the LSS orchestrator serves -// the ultimate-products collection in-process (aoss sidecar on :14567) and -// skips SigV4 verification — plain HTTP is enough locally. Against real -// OpenSearch Serverless swap this for @opensearch-project/opensearch with -// AwsSigv4Signer({service: 'aoss'}) — the calls themselves are identical. -const ENDPOINT = process.env.OPENSEARCH_ENDPOINT || 'http://localhost:14567/_aoss/ultimate-products'; -const INDEX = process.env.PRODUCTS_INDEX || 'products'; - -async function request(method, path, body) { - const res = await fetch(`${ENDPOINT}${path}`, { - method, - headers: { 'content-type': 'application/json' }, - body: body === undefined ? undefined : JSON.stringify(body), - }); - let json = {}; - try { - json = await res.json(); - } catch { - // HEAD/empty responses have no body - } - return { status: res.status, json }; -} - -module.exports = { request, INDEX }; diff --git a/examples/localstack-ultimate/src/handlers/processOrderQueue.js b/examples/localstack-ultimate/src/handlers/processOrderQueue.js deleted file mode 100644 index 456dffc..0000000 --- a/examples/localstack-ultimate/src/handlers/processOrderQueue.js +++ /dev/null @@ -1,74 +0,0 @@ -const { PutItemCommand } = require('@aws-sdk/client-dynamodb'); -const { PutEventsCommand } = require('@aws-sdk/client-eventbridge'); -const { marshall } = require('@aws-sdk/util-dynamodb'); -const { dynamo, eventBridge } = require('./aws'); - -exports.handler = async (event) => { - const records = event.Records || []; - console.log(`[processOrderQueue] received ${records.length} message(s)`); - - // ReportBatchItemFailures contract: only the messageIds listed here are kept - // on the queue; everything else is deleted. A poison message is re-received - // until maxReceiveCount, then SQS redrives it to the OrderProcessingDLQ. - const batchItemFailures = []; - - for (const record of records) { - try { - let order; - try { - order = JSON.parse(record.body); - } catch (e) { - throw new Error(`invalid body: ${record.body}`); - } - - const total = (order.items || []).reduce( - (s, it) => s + (Number(it.price) || 0) * (Number(it.qty) || 1), - 0, - ); - - // Obviously invalid orders are poison messages: throwing (instead of - // dropping) keeps them on the queue so the DLQ redrive is observable. - if (!order.userId) { - throw new Error('poison order: missing userId'); - } - if (total <= 0) { - throw new Error(`poison order ${order.orderId}: total ${total} <= 0`); - } - - const persisted = { - ...order, - status: total > 100 ? 'PENDING_REVIEW' : 'CONFIRMED', - total, - processedAt: new Date().toISOString(), - }; - - await dynamo.send(new PutItemCommand({ - TableName: process.env.ORDERS_TABLE, - Item: marshall(persisted, { removeUndefinedValues: true }), - })); - - // Announce the processed order on the custom EventBridge bus — the - // auditEvents rule (source: ultimate.orders) picks it up. - await eventBridge.send(new PutEventsCommand({ - Entries: [{ - EventBusName: process.env.ORDER_EVENTS_BUS, - Source: 'ultimate.orders', - DetailType: 'order.processed', - Detail: JSON.stringify({ - orderId: persisted.orderId, - userId: persisted.userId, - status: persisted.status, - total: persisted.total, - }), - }], - })); - - console.log(`[processOrderQueue] stored order ${persisted.orderId} (${persisted.status})`); - } catch (err) { - console.error(`[processOrderQueue] message ${record.messageId} failed: ${err.message}`); - batchItemFailures.push({ itemIdentifier: record.messageId }); - } - } - - return { batchItemFailures }; -}; diff --git a/examples/localstack-ultimate/src/handlers/productStats.js b/examples/localstack-ultimate/src/handlers/productStats.js deleted file mode 100644 index 5d9f5aa..0000000 --- a/examples/localstack-ultimate/src/handlers/productStats.js +++ /dev/null @@ -1,30 +0,0 @@ -const { request, INDEX } = require('./opensearch'); -const respond = require('./respond'); - -// GET /stats — product count and average price per category (aggregations). -exports.handler = async () => { - const { status, json } = await request('POST', `/${INDEX}/_search`, { - size: 0, - aggs: { - by_category: { terms: { field: 'category' } }, - avg_price: { avg: { field: 'price' } }, - }, - }); - - // No index yet (nothing was ever created) → empty stats, not an error. - if (status === 404) { - return respond(200, { total: 0, averagePrice: null, categories: [] }); - } - if (status >= 400) { - return respond(502, { error: 'aggregation failed', detail: json }); - } - - return respond(200, { - total: json.hits.total.value, - averagePrice: json.aggregations.avg_price.value, - categories: json.aggregations.by_category.buckets.map((bucket) => ({ - category: bucket.key, - products: bucket.doc_count, - })), - }); -}; diff --git a/examples/localstack-ultimate/src/handlers/purgeSessions.js b/examples/localstack-ultimate/src/handlers/purgeSessions.js deleted file mode 100644 index e7e72b5..0000000 --- a/examples/localstack-ultimate/src/handlers/purgeSessions.js +++ /dev/null @@ -1,41 +0,0 @@ -const { ScanCommand, DeleteItemCommand } = require('@aws-sdk/client-dynamodb'); -const { PutEventsCommand } = require('@aws-sdk/client-eventbridge'); -const { marshall, unmarshall } = require('@aws-sdk/util-dynamodb'); -const { dynamo, eventBridge } = require('./aws'); - -// schedule: rate(2 minutes) — compiled to an EventBridge rule on the default -// bus and fired by LocalStack through the LSS proxy. Deletes Sessions rows -// whose expiresAt (epoch seconds) is in the past — the poor man's TTL; the -// Settings tab in the UI can enable real DynamoDB TTL on the same attribute. -exports.handler = async () => { - const res = await dynamo.send(new ScanCommand({ TableName: process.env.SESSIONS_TABLE })); - const sessions = (res.Items || []).map((i) => unmarshall(i)); - const nowSeconds = Math.floor(Date.now() / 1000); - - const expired = sessions.filter((s) => Number(s.expiresAt) > 0 && Number(s.expiresAt) < nowSeconds); - - for (const session of expired) { - await dynamo.send(new DeleteItemCommand({ - TableName: process.env.SESSIONS_TABLE, - Key: marshall({ sessionId: session.sessionId }), - })); - } - - // Leave a trace on the custom bus so every run shows up in GET /audit via - // the auditEvents rule (source: ultimate.scheduler). - await eventBridge.send(new PutEventsCommand({ - Entries: [{ - EventBusName: process.env.ORDER_EVENTS_BUS, - Source: 'ultimate.scheduler', - DetailType: 'sessions.purged', - Detail: JSON.stringify({ - scanned: sessions.length, - purged: expired.length, - purgedIds: expired.map((s) => s.sessionId), - }), - }], - })); - - console.log(`[purgeSessions] purged ${expired.length} of ${sessions.length} session(s)`); - return { scanned: sessions.length, purged: expired.length }; -}; diff --git a/examples/localstack-ultimate/src/handlers/respond.js b/examples/localstack-ultimate/src/handlers/respond.js deleted file mode 100644 index e402161..0000000 --- a/examples/localstack-ultimate/src/handlers/respond.js +++ /dev/null @@ -1,11 +0,0 @@ -// Shared HTTP response helper. Every response carries a permissive CORS header -// so the validation console (index.html) can call these routes straight from -// the browser; serverless-offline answers the preflight (cors: true per event). -module.exports = (statusCode, payload) => ({ - statusCode, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - body: JSON.stringify(payload), -}); diff --git a/examples/localstack-ultimate/src/handlers/searchProducts.js b/examples/localstack-ultimate/src/handlers/searchProducts.js deleted file mode 100644 index 5e7d788..0000000 --- a/examples/localstack-ultimate/src/handlers/searchProducts.js +++ /dev/null @@ -1,42 +0,0 @@ -const { request, INDEX } = require('./opensearch'); -const respond = require('./respond'); - -// GET /search?q=&category=&maxPrice= -// Composes a bool query: full-text match on name/tags, term filter on -// category, range filter on price — the everyday OpenSearch search shape. -exports.handler = async (event) => { - const params = event.queryStringParameters || {}; - const must = []; - const filter = []; - - if (params.q) { - must.push({ multi_match: { query: params.q, fields: ['name', 'tags'] } }); - } - if (params.category) { - filter.push({ term: { category: params.category } }); - } - if (params.maxPrice) { - filter.push({ range: { price: { lte: Number(params.maxPrice) } } }); - } - - const query = must.length + filter.length > 0 ? { bool: { must, filter } } : { match_all: {} }; - const { status, json } = await request('POST', `/${INDEX}/_search`, { - query, - sort: [{ price: 'asc' }], - size: 20, - }); - - // The index only exists after the first product is created — an empty - // catalog is an empty result, not an error. - if (status === 404) { - return respond(200, { total: 0, products: [] }); - } - if (status >= 400) { - return respond(502, { error: 'search failed', detail: json }); - } - - return respond(200, { - total: json.hits.total.value, - products: json.hits.hits.map((hit) => ({ id: hit._id, ...hit._source })), - }); -}; diff --git a/examples/localstack-ultimate/src/handlers/uploadFile.js b/examples/localstack-ultimate/src/handlers/uploadFile.js deleted file mode 100644 index 4d3e9fc..0000000 --- a/examples/localstack-ultimate/src/handlers/uploadFile.js +++ /dev/null @@ -1,34 +0,0 @@ -const { PutObjectCommand } = require('@aws-sdk/client-s3'); -const { randomUUID } = require('crypto'); -const { s3 } = require('./aws'); -const respond = require('./respond'); - -// POST /uploads -// Body: { "filename": "report.txt", "content": "...", "encoding": "base64" | undefined } -exports.handler = async (event) => { - let payload = {}; - try { - payload = event.body ? JSON.parse(event.body) : {}; - } catch { - return respond(400, { error: 'invalid json' }); - } - - const { filename, content, encoding, contentType } = payload; - if (!content) { - return respond(400, { error: 'content is required' }); - } - - // Files land under "incoming/" so the S3 → Lambda notification fires. - const safeName = (filename || `${randomUUID()}.txt`).replace(/[^a-zA-Z0-9._/-]/g, '_'); - const key = `incoming/${safeName}`; - const body = encoding === 'base64' ? Buffer.from(content, 'base64') : content; - - await s3.send(new PutObjectCommand({ - Bucket: process.env.UPLOADS_BUCKET, - Key: key, - Body: body, - ContentType: contentType || 'text/plain', - })); - - return respond(201, { uploaded: true, bucket: process.env.UPLOADS_BUCKET, key }); -}; diff --git a/examples/self-hosted/lss.config.json b/examples/self-hosted/lss.config.json index ca4288e..439bcfb 100644 --- a/examples/self-hosted/lss.config.json +++ b/examples/self-hosted/lss.config.json @@ -1,6 +1,5 @@ { "serverPort": 3140, - "engine": "self", "selfEngine": { "port": 14566 }, @@ -17,7 +16,7 @@ }, "branding": { "title": "Self-Hosted Services", - "subtitle": "Every AWS service emulated in-process by LSS — no Docker, no tokens", + "subtitle": "Every AWS service emulated in-process by LSS \u2014 no Docker, no tokens", "logo": "./assets/logo.svg", "favicon": "./assets/logo.svg", "defaultTheme": "dark", diff --git a/examples/self-hosted/package.json b/examples/self-hosted/package.json index e25daad..6abc5ea 100644 --- a/examples/self-hosted/package.json +++ b/examples/self-hosted/package.json @@ -4,7 +4,7 @@ "private": true, "description": "Four microservices (orders → billing → notifications pipeline + product catalog) running entirely on the LSS self engine: DynamoDB, SQS, S3, EventBridge and OpenSearch Serverless emulated in-process — no Docker, no LocalStack, no auth token.", "scripts": { - "lss:start": "node ../../bin/cli.js start --self-engine", + "lss:start": "node ../../bin/cli.js start", "lss:stop": "node ../../bin/cli.js stop", "lss:status": "node ../../bin/cli.js status", "register:orders": "npm --prefix orders-service run package", diff --git a/jest.integration.config.js b/jest.integration.config.js index 47e32d8..16de710 100644 --- a/jest.integration.config.js +++ b/jest.integration.config.js @@ -1,6 +1,6 @@ -// Integration test config: boots a real isolated LSS + LocalStack (Docker). +// Integration test config: boots a real isolated LSS on the self engine. // No coverage gate; long timeouts. Run with `npm run test:integration`. -// Requires Docker and a LOCALSTACK_AUTH_TOKEN (community images >= 2026.5). +// No Docker and no auth token — it runs on any machine and in any CI job. module.exports = { preset: 'ts-jest', testEnvironment: 'node', @@ -11,8 +11,8 @@ module.exports = { '^(\\.{1,2}/.*)\\.js$': '$1', }, testTimeout: 120000, - // Docker-bound suites must not run in parallel workers (they would fight over - // LocalStack containers/ports). Run serially. + // Each suite binds real ports (orchestrator, engine, per-service listeners), + // so they must not overlap. Run serially. maxWorkers: 1, setupFilesAfterEnv: ['/tests/setup.integration.ts'], verbose: true, diff --git a/lss.config.json b/lss.config.json index 04e9c53..e841d44 100644 --- a/lss.config.json +++ b/lss.config.json @@ -1,21 +1,12 @@ { "serverPort": 3101, - "localstackPort": 4567, - "localstackEndpoint": "http://localhost:4567", - "mode": "managed", - "localstackEdition": "community", - "localstackVersion": "latest", + "selfEngine": { + "port": 14566 + }, "enableDynamoProxy": false, "dynamoProxyPort": 8001, "region": "us-east-1", - "services": [ - "dynamodb", - "sqs", - "sns", - "s3", - "lambda", - "events" - ], "persistence": true, - "debug": true + "debug": true, + "stateDir": ".lss" } diff --git a/lss.config.json.example b/lss.config.json.example index d394841..b3550c3 100644 --- a/lss.config.json.example +++ b/lss.config.json.example @@ -1,15 +1,16 @@ { "serverPort": 3100, - "engine": "localstack", - "mode": "managed", - "localstackEdition": "community", - "localstackVersion": "latest", - "localstackPort": 4566, - "localstackEndpoint": "http://localhost:4566", + "selfEngine": { + "port": 14566, + "account": "000000000000", + "idleUnloadMs": 300000, + "memoryBudgetMb": 128, + "fsync": false, + "fallbackEndpoint": null + }, "enableDynamoProxy": false, "dynamoProxyPort": 8000, "region": "us-east-1", - "services": ["dynamodb", "sqs", "sns", "s3", "lambda", "events"], "persistence": true, "debug": false, "seedsDir": "./seeds", @@ -25,15 +26,14 @@ "lambdaRuntime": { "enabled": true, "execution": "auto", - "invokePortOffset": 10000 + "invokePortOffset": 10000, + "lazy": true, + "idleTimeoutMs": 60000, + "maxWarmWorkers": 8 }, "serviceRuntime": { "users-service": { "apiPort": 3010, "invokePort": 13010 } }, - "selfEngine": { - "port": 14566, - "fallbackEndpoint": null - }, "branding": { "title": "Local Serverless Stack", "subtitle": "Local development control plane", @@ -41,12 +41,12 @@ "favicon": "./assets/favicon.ico", "defaultTheme": "dark", "colors": { - "brand-primary": "#3b82f6", - "brand-hover": "#2563eb" + "brand-primary": "#0d9488", + "brand-hover": "#0f766e" }, "themeColors": { - "dark": { "bg-primary": "#0d1117" }, - "light": { "bg-primary": "#f8fafc" } + "dark": { "brand-primary": "#2dd4bf" }, + "light": { "brand-primary": "#0d9488" } } } } diff --git a/package-lock.json b/package-lock.json index f47de15..9b22966 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "local-serverless-stack", - "version": "0.18.0", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "local-serverless-stack", - "version": "0.18.0", + "version": "2.0.0", "license": "MIT", "workspaces": [ "packages/*", @@ -3388,23 +3388,25 @@ } }, "node_modules/@treeui/tokens": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@treeui/tokens/-/tokens-0.15.0.tgz", - "integrity": "sha512-5sKMhIcnevCCYNAbDucXsMqNuo6k7yQZGuMv3cLhzyuFNKjEUyHGQitamuzQFzwU2cZbWv/s8WQnSoTei0xDZg==" + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@treeui/tokens/-/tokens-0.25.0.tgz", + "integrity": "sha512-1SUax16rfklxcwInOwaa904yty91ncTRXFTBk6f3yoc2KwESvCeYhv1MbZJqePw7dtjlQzWOmw5f9mJBXTOELQ==", + "license": "MIT" }, "node_modules/@treeui/utils": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@treeui/utils/-/utils-0.13.0.tgz", - "integrity": "sha512-E/ZWsq/CDb1y3L8hn+PFTKvGMp5E5R9yyH2o4mSwf/dL3DykQ8bu7hVDLzJVk6T82jYvVtSEvQClh82ZJZsCuQ==" + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@treeui/utils/-/utils-0.24.0.tgz", + "integrity": "sha512-Q/KoWmCvZJKaS/ilGu2VsX3m9f89cGOl4totonbT5Gddy3iYAMNUj5v63I/WGS0rHQ/mey+47owuYhfnyC4dcw==" }, "node_modules/@treeui/vue": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@treeui/vue/-/vue-0.23.0.tgz", - "integrity": "sha512-CP0sRN1Q8kzbqGEN/E4fdfuKlVTPQsnZv3sOnQCED87dCrgu4ixDus8wdbsoLe8ki2zVF9Ji2mUtON6V8i2IDw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@treeui/vue/-/vue-0.25.0.tgz", + "integrity": "sha512-Evzj56Yk1+L6MsdwRsIkMj4EBa9gkwrUS8atEmPKDL0Xt2nSmzBhJ7gfV9FfqAEAug+QyjrpCFMH8xUnTGUhWg==", + "license": "MIT", "dependencies": { "@treeui/icons": "0.18.0", - "@treeui/tokens": "0.15.0", - "@treeui/utils": "0.13.0" + "@treeui/tokens": "0.25.0", + "@treeui/utils": "0.24.0" }, "peerDependencies": { "vue": "^3.5.13" @@ -10037,7 +10039,7 @@ "name": "lss-orchestrator-ui", "version": "0.1.2", "dependencies": { - "@treeui/vue": "^0.23.0", + "@treeui/vue": "^0.25.0", "vue": "^3.5.13", "vue-router": "^4.6.4" }, diff --git a/package.json b/package.json index 898f1aa..a92d3f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "local-serverless-stack", - "version": "0.18.0", + "version": "2.0.0", "description": "Local control plane for serverless development with LocalStack orchestration", "author": "LSS Contributors", "license": "MIT", diff --git a/src/client/lifecycle.ts b/src/client/lifecycle.ts index d4e702f..91a4719 100644 --- a/src/client/lifecycle.ts +++ b/src/client/lifecycle.ts @@ -1,7 +1,7 @@ // Programmatic orchestrator lifecycle. start/stop/status/logs are process-spawn // + PID/stateDir file work — NOT HTTP — so instead of duplicating the CLI's // battle-tested logic we shell out to `bin/cli.js`. `waitUntilReady` then polls -// GET /api/health, because `lss start` returns before LocalStack is actually up. +// GET /api/health, because `lss start` returns before the engine is serving. import { spawn } from 'child_process'; import path from 'path'; @@ -11,9 +11,6 @@ export interface StartOptions { /** Overrides the client's configPath for this invocation (threaded as --config). */ configPath?: string; enableDynamoProxy?: boolean; - external?: boolean; - pro?: boolean; - localstackToken?: string; } export interface StartResult { alreadyRunning: boolean; @@ -40,7 +37,7 @@ export interface LifecycleApi { stop(): Promise; status(): Promise; logs(): Promise; - /** Poll GET /api/health until LocalStack reports ready, or reject after timeoutMs. */ + /** Poll GET /api/health until the engine reports ready, or reject after timeoutMs. */ waitUntilReady(opts?: WaitUntilReadyOptions): Promise; } @@ -94,9 +91,6 @@ export class Lifecycle implements LifecycleApi { async start(opts: StartOptions = {}): Promise { const args = ['start', ...this.configArgs(opts.configPath)]; if (opts.enableDynamoProxy) args.push('--enable-dynamo-proxy'); - if (opts.external) args.push('--external'); - if (opts.pro) args.push('--pro'); - if (opts.localstackToken) args.push('--localstack-token', opts.localstackToken); const r = await runCli(args, this.deps.cwd); if (r.code !== 0) throw cliError('start', r); @@ -127,7 +121,7 @@ export class Lifecycle implements LifecycleApi { for (;;) { try { const health = await this.deps.health.get(); - if (health.localstack === true) return; + if (health.engineRunning === true) return; } catch { // Orchestrator not accepting connections yet — keep polling. } diff --git a/src/client/namespaces/health.ts b/src/client/namespaces/health.ts index c611af4..0a8d858 100644 --- a/src/client/namespaces/health.ts +++ b/src/client/namespaces/health.ts @@ -2,7 +2,7 @@ import type { Http } from '../http'; import type { HealthStatus } from '../types'; export interface HealthApi { - /** GET /api/health — orchestrator + LocalStack + dynamo-proxy status. */ + /** GET /api/health — orchestrator + engine + dynamo-proxy status. */ get(): Promise; } diff --git a/src/client/namespaces/seeds.ts b/src/client/namespaces/seeds.ts index 2570c3d..002a221 100644 --- a/src/client/namespaces/seeds.ts +++ b/src/client/namespaces/seeds.ts @@ -2,7 +2,7 @@ import type { Http } from '../http'; import type { ClearResult, SeedResult, SeedsListResult } from '../types'; export interface SeedsApi { - /** GET /api/seeds — seed files on disk + the tables currently live in LocalStack. */ + /** GET /api/seeds — seed files on disk + the tables currently live in the engine. */ list(region?: string): Promise; /** POST /api/seeds/run — apply seed file(s). No tableName seeds every matching table. */ run(tableName?: string, region?: string): Promise<{ results: SeedResult[] }>; diff --git a/src/client/types.ts b/src/client/types.ts index 51e3e3b..29c32ff 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -236,6 +236,16 @@ export interface StartServiceInput { // ── Health ──────────────────────────────────────────────────────────────────── export interface HealthStatus { status: string; - localstack: boolean; + /** True once the in-process AWS engine is serving. */ + engineRunning: boolean; + engine: { + kind: 'self'; + running: boolean; + endpoint: string; + /** Emulated AWS services the engine answers for. */ + services?: string[]; + eventSourceLoops?: { sqs: number; streams: number }; + scheduleRules?: number; + }; dynamoProxy: { enabled: boolean; running: boolean; port: number }; } diff --git a/src/mcp/tools.ts b/src/mcp/tools.ts index 5de48e0..ae1c73d 100644 --- a/src/mcp/tools.ts +++ b/src/mcp/tools.ts @@ -52,7 +52,7 @@ export const TOOLS: ToolDefinition[] = [ { name: 'lss_health', description: - 'Orchestrator and engine health: which engine is active (self or localstack), its endpoint, ' + 'Orchestrator and engine health: the engine endpoint, the AWS services it answers for, ' + 'how many event-source loops and schedule rules are armed. Use this first to confirm a stack is up.', inputSchema: { type: 'object', properties: {} }, run: (_a, http) => http('GET', '/api/health'), diff --git a/src/server/engine/aoss-sidecar.ts b/src/server/engine/aoss-sidecar.ts deleted file mode 100644 index c42b5ef..0000000 --- a/src/server/engine/aoss-sidecar.ts +++ /dev/null @@ -1,117 +0,0 @@ -// OpenSearch Serverless (aoss) sidecar: the self-engine OpenSearch emulator -// served in-process behind the engine router, on its own port next to a -// LocalStack engine. No LocalStack edition provides aoss, so LSS fills the -// gap itself — the control plane (X-Amz-Target OpenSearchServerless.*) and -// the data plane (/_aoss//...) both answer on this listener, -// persisted under the sidecar's own data dir. Never started in self-engine -// mode, where aoss is native. - -import http from 'http'; -import type { Socket } from 'net'; -import type { AddressInfo } from 'net'; -import type { EngineContext } from './types.js'; -import { EngineBus } from './bus.js'; -import { createEngineStore } from './store/engine-store.js'; -import { createEngineRequestHandler } from './http/router.js'; -import { OpenSearchEmulator } from './emulators/opensearch/index.js'; - -// Same residency defaults as the self engine (config-manager.ts) — the -// sidecar hosts one emulator, so there is no reason to expose knobs for them. -const IDLE_UNLOAD_MS = 300_000; -const MEMORY_BUDGET_MB = 128; - -export interface AossSidecarOptions { - // 0 binds an ephemeral port (tests); the endpoint always reflects the - // actually bound port. - port: number; - dataDir: string; - region: string; - account?: string; -} - -export interface AossSidecarHandle { - port: number; - endpoint: string; - close(): Promise; -} - -export async function startAossSidecar(opts: AossSidecarOptions): Promise { - const store = createEngineStore({ - dataDir: opts.dataDir, - idleUnloadMs: IDLE_UNLOAD_MS, - memoryBudgetMb: MEMORY_BUDGET_MB, - fsync: false, - }); - - // The emulator resolves collectionEndpoint through ctx.endpoint() at request - // time; a closure over the mutable port keeps it correct once listen() has - // picked the real port (port 0 case). - let boundPort = opts.port; - const ctx: EngineContext = { - config: { - port: opts.port, - dataDir: opts.dataDir, - account: opts.account ?? '000000000000', - region: opts.region, - idleUnloadMs: IDLE_UNLOAD_MS, - memoryBudgetMb: MEMORY_BUDGET_MB, - fsync: false, - fallbackEndpoint: null, - persistence: true, - }, - store, - bus: new EngineBus(), - // The OpenSearch emulator never invokes functions; the stub keeps the - // context honest without dragging the dispatcher (and the Lambda runtime) - // into the sidecar. - dispatcher: { invokeFunction: async () => ({ ok: true }) }, - endpoint: () => `http://localhost:${boundPort}`, - }; - - const emulator = new OpenSearchEmulator(ctx); - const handler = createEngineRequestHandler({ ctx, emulators: [emulator] }); - const server = http.createServer(handler); - // Keep-alive sockets must be destroyed for server.close() not to hang. - const sockets = new Set(); - server.on('connection', socket => { - sockets.add(socket); - socket.on('close', () => sockets.delete(socket)); - }); - - await new Promise((resolve, reject) => { - const onError = (err: NodeJS.ErrnoException): void => { - server.removeListener('listening', onListening); - if (err.code === 'EADDRINUSE') { - reject(new Error( - `aoss sidecar could not bind port ${opts.port}: address already in use. ` + - 'Stop the conflicting process or set aossSidecar.port to a free port.', - )); - } else { - reject(err); - } - }; - const onListening = (): void => { - server.removeListener('error', onError); - resolve(); - }; - server.once('error', onError); - server.once('listening', onListening); - server.listen(opts.port, '0.0.0.0'); - }); - boundPort = (server.address() as AddressInfo).port; - store.startSweeper(); - - return { - port: boundPort, - endpoint: `http://localhost:${boundPort}`, - async close(): Promise { - await store.flushAll(); - store.stopSweeper(); - await new Promise(resolve => { - server.close(() => resolve()); - for (const socket of sockets) socket.destroy(); - sockets.clear(); - }); - }, - }; -} diff --git a/src/server/engine/backends/localstack-backend.ts b/src/server/engine/backends/localstack-backend.ts deleted file mode 100644 index e6df2db..0000000 --- a/src/server/engine/backends/localstack-backend.ts +++ /dev/null @@ -1,229 +0,0 @@ -// LocalStack lifecycle backend (docker container, managed/external). This is -// the code that used to live in services/localstack-manager.ts — that module -// is now a thin facade over EngineManager so existing call sites keep working -// regardless of the active engine. - -import { spawn, ChildProcess, exec } from 'child_process'; -import { promisify } from 'util'; -import { ConfigManager } from '../../services/config-manager.js'; -import type { EngineBackend } from '../engine-backend.js'; - -const execAsync = promisify(exec); - -export class LocalStackBackend implements EngineBackend { - readonly kind = 'localstack' as const; - private process: ChildProcess | null = null; - private _isRunning = false; - private endpoint: string; - // Container name is scoped to the LocalStack port so multiple LSS instances - // (one per example/project) can launch their own container side by side. - // Falls back to "lss-localstack" when the default 4566 is in use to preserve - // existing teardown scripts that look for that name. - private readonly containerName: string; - private readonly configManager: ConfigManager; - - constructor() { - this.configManager = ConfigManager.getInstance(); - this.endpoint = this.configManager.getLocalStackEndpoint(); - const port = this.configManager.getLocalStackPort(); - this.containerName = port === 4566 ? 'lss-localstack' : `lss-localstack-${port}`; - } - - async start(): Promise { - if (this._isRunning) { - console.log('⚠️ LocalStack already running'); - return; - } - - if (this.configManager.isExternal()) { - console.log(`🔗 Using external LocalStack at ${this.endpoint}`); - await this.waitForReady(30); - this._isRunning = true; - console.log('✅ Connected to external LocalStack'); - return; - } - - try { - // Check if docker is available - await execAsync('docker ps -q', { timeout: 5000 }); - } catch { - throw new Error('Docker is not available or not running. Please start Docker first.'); - } - - const edition = this.configManager.getLocalStackEdition(); - const image = this.configManager.getLocalStackImage(); - const authToken = this.configManager.getLocalStackAuthToken(); - - if (edition === 'pro' && !authToken) { - throw new Error( - 'LocalStack Pro requires LOCALSTACK_AUTH_TOKEN. Set the env var or "localstackAuthToken" in your config.', - ); - } - if (edition === 'community' && !authToken) { - console.warn( - '⚠️ LOCALSTACK_AUTH_TOKEN not set. Recent localstack/localstack images (>= 2026.5) require a token even for the community edition.', - ); - } - - return new Promise((resolve, reject) => { - console.log(`🔄 Starting LocalStack (${image})...`); - - const port = this.configManager.getLocalStackPort(); - const services = this.configManager.getServices().join(','); - const persistence = this.configManager.isPersistence() ? '1' : '0'; - const debug = this.configManager.isDebug() ? '1' : '0'; - - // Persistence volume is scoped to the container so two LSS instances - // don't share (and corrupt) the same on-disk state. - const volumeName = this.containerName === 'lss-localstack' - ? 'lss-localstack-data' - : `${this.containerName}-data`; - - const dockerArgs = [ - 'run', - '--rm', - '-p', - `${port}:4566`, - '-v', - `${volumeName}:/var/lib/localstack`, - '-v', - '/var/run/docker.sock:/var/run/docker.sock', - // host.docker.internal resolves natively on Docker Desktop but not on - // Linux; the generated Lambda proxies target it to reach the invoke - // listeners on the host, so map it explicitly (no-op elsewhere). - '--add-host', - 'host.docker.internal:host-gateway', - '--name', - this.containerName, - '-e', - `SERVICES=${services}`, - '-e', - 'LAMBDA_EXECUTOR=local', - // Lambda containers spawned BY LocalStack (which run the proxies) need - // the same host mapping. - '-e', - 'LAMBDA_DOCKER_FLAGS=--add-host host.docker.internal:host-gateway', - '-e', - `PERSISTENCE=${persistence}`, - '-e', - `DEBUG=${debug}`, - ]; - - if (authToken) { - dockerArgs.push('-e', `LOCALSTACK_AUTH_TOKEN=${authToken}`); - } - - dockerArgs.push(image); - - this.process = spawn('docker', dockerArgs); - - let stderr = ''; - let stdout = ''; - this.process.stderr?.on('data', data => { - stderr += data.toString(); - console.log(`[LocalStack stderr] ${data.toString().trim()}`); - }); - this.process.stdout?.on('data', data => { - stdout += data.toString(); - console.log(`[LocalStack stdout] ${data.toString().trim()}`); - }); - - this.process.on('error', error => { - console.error('❌ Failed to start LocalStack process:', error); - reject(error); - }); - - this.process.on('close', code => { - if (code !== 0) { - console.error(`Container exited with code ${code}`); - console.error('stderr:', stderr); - console.error('stdout:', stdout); - } - }); - - // Wait for LocalStack to be ready - this.waitForReady() - .then(() => { - this._isRunning = true; - console.log('✅ LocalStack ready'); - resolve(); - }) - .catch(err => { - console.error('LocalStack startup error:', err.message); - this.process?.kill(); - reject(err); - }); - }); - } - - async stop(): Promise { - if (!this._isRunning) { - return; - } - - if (this.configManager.isExternal()) { - console.log('🔗 External LocalStack — leaving container untouched'); - this._isRunning = false; - return; - } - - console.log('🛑 Stopping LocalStack...'); - - try { - await execAsync(`docker stop ${this.containerName}`, { timeout: 10000 }); - this._isRunning = false; - this.process = null; - console.log('✅ LocalStack stopped'); - } catch (error) { - console.error('⚠️ Error stopping LocalStack:', error instanceof Error ? error.message : 'Unknown error'); - this._isRunning = false; - } - } - - private async waitForReady(maxAttempts = 120): Promise { - for (let i = 0; i < maxAttempts; i++) { - try { - const response = await fetch(`${this.endpoint}/_localstack/health`); - if (response.ok) { - console.log(`✓ LocalStack is responsive (attempt ${i + 1}/${maxAttempts})`); - return; - } - } catch { - // Ignore fetch errors during startup - if (i % 20 === 0) { - console.log(`⏳ Waiting for LocalStack... (attempt ${i + 1}/${maxAttempts})`); - } - } - await new Promise(resolve => setTimeout(resolve, 1000)); - } - throw new Error('LocalStack failed to start in time (120s timeout). Check Docker and container logs.'); - } - - isRunning(): boolean { - return this._isRunning; - } - - getEndpoint(): string { - return this.endpoint; - } - - getConfig() { - return { - endpoint: this.endpoint, - region: this.configManager.getRegion(), - credentials: { - accessKeyId: process.env.LOCALSTACK_ACCESS_KEY_ID || 'test', - secretAccessKey: process.env.LOCALSTACK_SECRET_ACCESS_KEY || 'test', - }, - }; - } - - healthDetail(): Record { - return { - endpoint: this.endpoint, - running: this._isRunning, - mode: this.configManager.getMode(), - image: this.configManager.isExternal() ? undefined : this.configManager.getLocalStackImage(), - }; - } -} diff --git a/src/server/engine/backends/self-backend.ts b/src/server/engine/backends/self-backend.ts index 73abbe2..95e1fda 100644 --- a/src/server/engine/backends/self-backend.ts +++ b/src/server/engine/backends/self-backend.ts @@ -9,7 +9,6 @@ import fs from 'fs'; import path from 'path'; import type { Socket } from 'net'; import type { AddressInfo } from 'net'; -import type { EngineBackend } from '../engine-backend.js'; import { ConfigManager, type ResolvedSelfEngineConfig } from '../../services/config-manager.js'; import type { DispatcherApi, EngineContext } from '../types.js'; import { EngineBus } from '../bus.js'; @@ -31,7 +30,7 @@ import { EngineScheduler } from '../dispatch/scheduler.js'; const SERVICES = ['dynamodb', 'sqs', 'sns', 's3', 'events', 'lambda', 'sts', 'secretsmanager', 'aoss'] as const; const SQS_SNAPSHOT_FILE = 'sqs-messages.snapshot.json'; -export class SelfEngineBackend implements EngineBackend { +export class SelfEngineBackend { readonly kind = 'self' as const; private readonly overrides: Partial; diff --git a/src/server/engine/engine-backend.ts b/src/server/engine/engine-backend.ts deleted file mode 100644 index 5bab3b6..0000000 --- a/src/server/engine/engine-backend.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Lifecycle seam between the orchestrator and whichever AWS provider is -// active. Provisioning is NOT part of this interface on purpose: both engines -// are driven through the AWS wire API by the existing SDK-based code -// (provisioner, explorers, seeds), so the only thing that varies is lifecycle -// and endpoint. See docs/PRD_SELF_ENGINE.md §5.1. - -export interface EngineBackend { - readonly kind: 'localstack' | 'self'; - start(): Promise; - stop(): Promise; - isRunning(): boolean; - getEndpoint(): string; - getConfig(): { - endpoint: string; - region: string; - credentials: { accessKeyId: string; secretAccessKey: string }; - }; - healthDetail(): Record; -} diff --git a/src/server/engine/engine-manager.ts b/src/server/engine/engine-manager.ts index bd44a0c..8c30f0a 100644 --- a/src/server/engine/engine-manager.ts +++ b/src/server/engine/engine-manager.ts @@ -1,16 +1,18 @@ -// Selects and owns the active EngineBackend (LocalStack container vs the -// in-process self engine) based on `engine` in the config. Every consumer of -// the old LocalStackManager API goes through here (via the facade kept at -// services/localstack-manager.ts), so the provisioner/explorers/seeds are -// engine-agnostic: they always talk AWS wire against getConfig().endpoint. +// Owns the AWS engine for this process. +// +// v2 removed the LocalStack backend: the self engine is the only engine, so +// this is no longer a chooser — it is the singleton every SDK-based consumer +// (provisioner, explorers, seeds, dynamo proxy, routes) goes through to get an +// endpoint + credentials. It stays as a seam so those consumers never import +// the backend, and so `getEndpoint()` answers correctly before `start()` — the +// explorers build their clients at construction time. import { ConfigManager } from '../services/config-manager.js'; -import { LocalStackBackend } from './backends/localstack-backend.js'; -import type { EngineBackend } from './engine-backend.js'; +import type { SelfEngineBackend } from './backends/self-backend.js'; export class EngineManager { private static instance: EngineManager; - private backend: EngineBackend | null = null; + private backend: SelfEngineBackend | null = null; private readonly configManager = ConfigManager.getInstance(); static getInstance(): EngineManager { @@ -20,13 +22,8 @@ export class EngineManager { return EngineManager.instance; } - getKind(): 'localstack' | 'self' { - return this.configManager.getEngineKind(); - } - async start(): Promise { - const backend = await this.resolveBackend(); - await backend.start(); + await (await this.resolveBackend()).start(); } async stop(): Promise { @@ -40,8 +37,6 @@ export class EngineManager { } getEndpoint(): string { - // Computable without the backend instance so callers can read it before - // start() (the self backend is loaded lazily inside start()). return this.backend?.getEndpoint() ?? this.configManager.getEngineEndpoint(); } @@ -52,32 +47,29 @@ export class EngineManager { return { endpoint: this.getEndpoint(), region: this.configManager.getRegion(), - credentials: { - accessKeyId: process.env.LOCALSTACK_ACCESS_KEY_ID || 'test', - secretAccessKey: process.env.LOCALSTACK_SECRET_ACCESS_KEY || 'test', - }, + // The engine never verifies signatures; the SDKs just refuse to send a + // request without credentials at all. + credentials: { accessKeyId: 'test', secretAccessKey: 'test' }, }; } healthDetail(): Record { return { - kind: this.getKind(), + kind: 'self', running: this.isRunning(), endpoint: this.getEndpoint(), ...(this.backend?.healthDetail() ?? {}), }; } - // The self backend is loaded with a dynamic import so LocalStack-mode - // processes never pay for the engine's code (RSS provably unchanged). - private async resolveBackend(): Promise { + // Loaded on demand rather than at module scope. Everything that reads an + // endpoint imports this module (explorers, provisioner, seeds), and a static + // import would drag the whole engine — emulators, dispatch, the Lambda + // runtime — into every one of their unit tests. + private async resolveBackend(): Promise { if (!this.backend) { - if (this.configManager.isSelfEngine()) { - const { SelfEngineBackend } = await import('./backends/self-backend.js'); - this.backend = new SelfEngineBackend(); - } else { - this.backend = new LocalStackBackend(); - } + const { SelfEngineBackend: Backend } = await import('./backends/self-backend.js'); + this.backend = new Backend(); } return this.backend; } diff --git a/src/server/engine/http/router.ts b/src/server/engine/http/router.ts index bdb194e..88e3513 100644 --- a/src/server/engine/http/router.ts +++ b/src/server/engine/http/router.ts @@ -48,8 +48,14 @@ const TARGET_PREFIXES: Record = { const LEGACY_SQS_MESSAGE = 'Your SDK predates the SQS JSON protocol. The LSS self engine serves SQS over ' + 'AWS JSON 1.0 (aws-sdk v3 / recent boto3); set selfEngine.fallbackEndpoint to ' + - 'route legacy SDKs to a LocalStack instance.'; - + 'route legacy SDKs to an endpoint that still speaks Query.'; + +// Compatibility alias, not a dependency: plenty of third-party tooling (wait-for +// scripts, IDE plugins, docker-compose healthchecks) probes GET +// /_localstack/health to decide whether a local AWS is up. Answering it in the +// shape they expect — with `edition: "self"`, so nothing pretends otherwise — +// lets that tooling keep working unchanged. `/_lss/health` above is the native +// endpoint. const LOCALSTACK_HEALTH = { services: { dynamodb: 'available', diff --git a/src/server/index.ts b/src/server/index.ts index e987ed3..5998475 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -24,7 +24,6 @@ import { GatewayManager } from './services/gateway-manager.js'; import { SourceWatcher } from './services/source-watcher.js'; import { startDynamoProxy } from './dev/dynamo-proxy.js'; import { applyRegionToExplorers } from './services/explorer-region.js'; -import type { AossSidecarHandle } from './engine/aoss-sidecar.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -33,7 +32,6 @@ const app = express(); const configManager = ConfigManager.getInstance(); const PORT = configManager.getDashboardPort(); let dynamoProxyServer: http.Server | null = null; -let aossSidecar: AossSidecarHandle | null = null; // Middleware app.use(cors()); @@ -57,10 +55,6 @@ app.get('/api/health', (_req, res) => { const engine = EngineManager.getInstance(); res.json({ status: 'ok', - // Deprecated alias for engineRunning, kept so older clients keep working. - // It says "localstack" even when the self engine is the one running, which - // is exactly the naming the dashboard now avoids. - localstack: engine.isRunning(), engineRunning: engine.isRunning(), engine: engine.healthDetail(), dynamoProxy: { @@ -68,11 +62,6 @@ app.get('/api/health', (_req, res) => { running: Boolean(dynamoProxyServer?.listening), port: configManager.getDynamoProxyPort(), }, - aossSidecar: { - enabled: configManager.getAossSidecarConfig().enabled, - running: aossSidecar !== null, - port: configManager.getAossSidecarConfig().port, - }, }); }); @@ -93,48 +82,22 @@ app.get('*', (_req, res) => { res.sendFile(path.join(uiBuildPath, 'index.html')); }); -// Start server and LocalStack +// Boot: engine → HTTP → services. async function start() { try { console.log('🚀 Starting Orchestrator Server...'); - // Initialize the AWS engine (LocalStack container or in-process self engine) + // In-process AWS engine: no Docker, no container, no auth token. const engine = EngineManager.getInstance(); await engine.start(); - // OpenSearch Serverless (aoss) sidecar: no LocalStack edition provides - // aoss, so LSS serves the self-engine emulator in-process next to it. - // Dynamic import keeps the LocalStack-mode memory profile lean, matching - // how the self backend is loaded. Failure is non-fatal — everything but - // aoss still works. - const aossConfig = configManager.getAossSidecarConfig(); - if (aossConfig.enabled) { - try { - const { startAossSidecar } = await import('./engine/aoss-sidecar.js'); - aossSidecar = await startAossSidecar({ - port: aossConfig.port, - dataDir: aossConfig.dataDir, - region: configManager.getRegion(), - }); - console.log( - `🔎 OpenSearch Serverless (aoss) sidecar on ${aossSidecar.endpoint} — ` + - 'LocalStack does not provide aoss; LSS serves it in-process', - ); - } catch (error) { - console.warn( - '⚠️ Failed to start the aoss sidecar (OpenSearch Serverless will be unavailable):', - error instanceof Error ? error.message : error, - ); - } - } - // An EADDRINUSE on the dashboard port has to be a named, actionable // failure: without an 'error' listener it surfaces as an unhandled // exception AFTER the engine has already bound its own port and started // its delivery loops, leaving a half-alive process behind. const httpServer = app.listen(PORT, () => { console.log(`✅ Server running on http://localhost:${PORT}`); - console.log(`✅ Engine (${engine.getKind()}) running on ${engine.getEndpoint()}`); + console.log(`✅ Self engine running on ${engine.getEndpoint()}`); }); httpServer.on('error', (error: NodeJS.ErrnoException) => { if (error.code === 'EADDRINUSE') { @@ -167,7 +130,7 @@ async function start() { // Seed Secrets Manager BEFORE reactivating services so any handler that // reads a secret on its first invocation (including relay-triggered handlers // that fire during rehydrate) already finds an AWSCURRENT version. Non-fatal - // — a seed failure must not abort startup (matches the aoss-sidecar block). + // — a seed failure must not abort startup. try { SeedManager.getInstance().setDefaultRegion(configManager.getRegion()); await SeedManager.getInstance().seedAllSecrets(configManager.getRegion()); @@ -207,8 +170,6 @@ async function shutdown(code = 0) { await LambdaRuntimeManager.getInstance().stopAll(); processManager.stopAll(); await processManager.cleanup(); - await aossSidecar?.close(); - aossSidecar = null; await EngineManager.getInstance().stop(); process.exit(code); } diff --git a/src/server/routes/config.ts b/src/server/routes/config.ts index ebbe83b..683165d 100644 --- a/src/server/routes/config.ts +++ b/src/server/routes/config.ts @@ -27,28 +27,17 @@ function redactPackaging(map: Record) { } // Public-safe LSS configuration snapshot — everything the dashboard shows and -// edits. Never expose secret VALUES: the LocalStack auth token collapses to -// hasAuthToken, packageEnv maps collapse to their key names, and the secrets -// seed map collapses to a count. +// edits. Never expose secret VALUES: packageEnv maps collapse to their key +// names and the secrets seed map collapses to a count. function buildConfigSnapshot(cm: ConfigManager) { const raw = cm.getConfig(); const selfEngine = cm.getSelfEngineConfig(); - const aossSidecar = cm.getAossSidecarConfig(); return { serverPort: cm.getServerPort(), engine: { - kind: cm.getEngineKind(), + kind: 'self' as const, endpoint: cm.getEngineEndpoint(), }, - localstack: { - mode: cm.getMode(), - endpoint: cm.getLocalStackEndpoint(), - port: cm.getLocalStackPort(), - edition: cm.getLocalStackEdition(), - version: cm.getLocalStackVersion(), - image: cm.getLocalStackImage(), - hasAuthToken: Boolean(cm.getLocalStackAuthToken()), - }, selfEngine: { port: selfEngine.port, dataDir: selfEngine.dataDir, @@ -58,17 +47,11 @@ function buildConfigSnapshot(cm: ConfigManager) { fsync: selfEngine.fsync, fallbackEndpoint: selfEngine.fallbackEndpoint, }, - aossSidecar: { - enabled: aossSidecar.enabled, - port: aossSidecar.port, - endpoint: aossSidecar.endpoint, - }, dynamoProxy: { enabled: cm.isEnableDynamoProxy(), port: cm.getDynamoProxyPort(), }, region: cm.getRegion(), - services: cm.getServices(), persistence: cm.isPersistence(), debug: cm.isDebug(), seedsDir: cm.getSeedsDir(), @@ -159,14 +142,13 @@ router.post('/reload', (_req: Request, res: Response) => { }); // Every local port the stack exposes, so "what do I point my SDK/browser at?" -// has one answer: orchestrator, active engine (LocalStack edge or self engine), -// aoss sidecar, DynamoDB proxy, plus each registered service's HTTP API and -// Lambda invoke listeners. +// has one answer: orchestrator, engine, DynamoDB proxy, plus each registered +// service's HTTP API and Lambda invoke listeners. router.get('/ports', (_req: Request, res: Response) => { const cm = ConfigManager.getInstance(); const ports: Array<{ name: string; - kind: 'orchestrator' | 'engine' | 'sidecar' | 'proxy' | 'service-api' | 'service-invoke'; + kind: 'orchestrator' | 'engine' | 'proxy' | 'service-api' | 'service-invoke'; port: number; url: string; description: string; @@ -180,34 +162,14 @@ router.get('/ports', (_req: Request, res: Response) => { description: 'Dashboard UI + REST API (register, explorers, seeds)', }); - if (cm.isSelfEngine()) { - const selfEngine = cm.getSelfEngineConfig(); - ports.push({ - name: 'Self engine', - kind: 'engine', - port: selfEngine.port, - url: `http://localhost:${selfEngine.port}`, - description: 'In-process AWS emulator — point SDK endpoints here', - }); - } else { - ports.push({ - name: `LocalStack (${cm.getMode()})`, - kind: 'engine', - port: cm.getLocalStackPort(), - url: cm.getLocalStackEndpoint(), - description: 'LocalStack edge — every AWS service on one port', - }); - const aossSidecar = cm.getAossSidecarConfig(); - if (aossSidecar.enabled) { - ports.push({ - name: 'OpenSearch Serverless sidecar', - kind: 'sidecar', - port: aossSidecar.port, - url: aossSidecar.endpoint, - description: 'aoss served in-process — no LocalStack edition provides it', - }); - } - } + const selfEngine = cm.getSelfEngineConfig(); + ports.push({ + name: 'Self engine', + kind: 'engine', + port: selfEngine.port, + url: `http://localhost:${selfEngine.port}`, + description: 'In-process AWS emulator — point SDK endpoints here', + }); if (cm.isEnableDynamoProxy()) { ports.push({ diff --git a/src/server/services/config-manager.ts b/src/server/services/config-manager.ts index 200d354..828c381 100644 --- a/src/server/services/config-manager.ts +++ b/src/server/services/config-manager.ts @@ -14,20 +14,13 @@ function realpathOrSelf(dir: string): string { } } -export type LocalStackMode = 'managed' | 'external'; -export type LocalStackEdition = 'community' | 'pro'; - -// Which AWS provider backs the orchestrator: -// "localstack" (default): Docker container managed/external as per `mode`. -// "self": the in-process self engine (no Docker) — see docs/PRD_SELF_ENGINE.md. -export type EngineKind = 'localstack' | 'self'; export interface SelfEngineConfig { // Front door port. Default 14566 — deliberately outside 4566–4599, which a // real LocalStack install intercepts on some hosts (Docker Desktop/WSL2). port?: number; // Engine persistence root. Defaults to /engine when stateDir is - // set (test isolation), else ~/.lss/engine. + // set, else a per-project directory under ~/.lss/projects/. dataDir?: string; account?: string; // Dehydrate hydrated data stores idle past this window. @@ -37,8 +30,8 @@ export interface SelfEngineConfig { // fsync on every WAL flush (paranoid mode). Default: fsync only at // compaction/dehydrate/shutdown. fsync?: boolean; - // Reverse-proxy target for AWS services/operations the engine does not - // implement (e.g. a LocalStack instance during migration). + // Reverse-proxy target for AWS operations the engine does not implement. + // An escape hatch for a niche gap — see docs/SELF_ENGINE.md "Coverage". fallbackEndpoint?: string | null; } @@ -55,25 +48,6 @@ export interface ResolvedSelfEngineConfig { region: string; } -// OpenSearch Serverless (aoss) sidecar: no LocalStack edition provides aoss, -// so on LocalStack engines LSS serves the self-engine OpenSearch emulator -// in-process on its own port. Never used in self mode (aoss is native there). -export interface AossSidecarConfig { - // Default: enabled whenever the active engine is LocalStack. - enabled?: boolean; - // Sidecar port. Default 14567 — one above the self engine's 14566. - port?: number; -} - -// AossSidecarConfig with every default applied plus the derived endpoint and -// persistence root. -export interface ResolvedAossSidecarConfig { - enabled: boolean; - port: number; - endpoint: string; - dataDir: string; -} - // Per-service packaging overrides. Keyed in `servicePackaging` by the service // directory name (basename) OR its path relative to the config file's directory. export interface ServicePackageConfig { @@ -109,10 +83,9 @@ export interface LambdaRuntimeConfig { // apiPort (30xx) → invokePort (130xx) derivation when a service doesn't // declare an explicit invoke port. Default: 10000. invokePortOffset?: number; - // Hostname the LocalStack event proxies use to call back into the orchestrator - // host (default: "host.docker.internal"). Override when that name doesn't - // resolve to this machine — e.g. Docker-in-Docker devcontainers, where the - // correct host is the docker network gateway (e.g. "172.17.0.1"). + // Hostname used to build the invoke URL a service's event proxies call back + // on (default "127.0.0.1" — everything runs in this process). Override only + // when the orchestrator must be reachable under another name. invokeHost?: string; // Fork a service's worker on its first invocation instead of at registration // (default: true). Each worker is a Node process costing ~48 MB resident, so @@ -193,34 +166,16 @@ export interface ResolvedBranding { }; } +// Front door port for the engine. Deliberately outside 4566–4599, which a real +// LocalStack install intercepts on some hosts (Docker Desktop/WSL2). +const DEFAULT_ENGINE_PORT = 14566; + export type BrandingAssetKind = 'logo' | 'favicon'; export interface LSSConfig { // Server port (dashboard + API) serverPort?: number; - // LocalStack endpoint and port - localstackPort?: number; - localstackEndpoint?: string; - - // LocalStack operation mode: - // "managed" (default): LSS starts/stops a Docker container. - // "external": LSS connects to an already-running LocalStack instance. - mode?: LocalStackMode; - - // LocalStack edition: "community" (free) or "pro" (requires auth token). - localstackEdition?: LocalStackEdition; - - // LocalStack image tag/version. Defaults to "latest". - localstackVersion?: string; - - // Full image override. Wins over edition+version when set. - localstackImage?: string; - - // Auth token for LocalStack Pro and recent (>=2026.5) community images. - // Prefer the LOCALSTACK_AUTH_TOKEN env var over committing this to a file. - localstackAuthToken?: string; - // DynamoDB Proxy enableDynamoProxy?: boolean; dynamoProxyPort?: number; @@ -228,9 +183,6 @@ export interface LSSConfig { // AWS Configuration region?: string; - // LocalStack services - services?: string[]; - // Persistence persistence?: boolean; @@ -285,16 +237,13 @@ export interface LSSConfig { // Per-service runtime overrides (ports, execution mode, watch). serviceRuntime?: Record; - // AWS provider selection ("localstack" default; "self" = in-process engine). - engine?: EngineKind; + // Accepted only so a v1 file fails loudly instead of silently: the only + // value LSS v2 tolerates is "self". See assertNoLocalStackEngine. + engine?: string; - // Self-engine settings (only used when engine is "self"). + // Self-engine settings. selfEngine?: SelfEngineConfig; - // OpenSearch Serverless sidecar settings (only used on LocalStack engines, - // which have no aoss provider). - aossSidecar?: AossSidecarConfig; - // Dashboard branding (title, logo, theme colors). Cosmetic only. branding?: BrandingConfig; } @@ -319,24 +268,16 @@ interface ConfigKeySpec { entrySubKeys?: Record; } -// Two config keys are deliberately absent (and rejected on write): -// `localstackAuthToken` — the supported channel is the LOCALSTACK_AUTH_TOKEN -// env var, the token must never transit the dashboard API — and `secrets`, -// which holds seed material that belongs in the file/env only. -const BLOCKED_CONFIG_KEYS: ReadonlySet = new Set(['localstackAuthToken', 'secrets']); +// `secrets` is deliberately absent (and rejected on write): it holds seed +// material that belongs in the config file or the environment, never in a +// payload that crosses the dashboard API. +const BLOCKED_CONFIG_KEYS: ReadonlySet = new Set(['secrets']); const EDITABLE_CONFIG_KEYS: Record = { serverPort: { kind: 'port' }, - localstackPort: { kind: 'port' }, - localstackEndpoint: { kind: 'string' }, - mode: { kind: 'string', enum: ['managed', 'external'] }, - localstackEdition: { kind: 'string', enum: ['community', 'pro'] }, - localstackVersion: { kind: 'string' }, - localstackImage: { kind: 'string' }, enableDynamoProxy: { kind: 'boolean' }, dynamoProxyPort: { kind: 'port' }, region: { kind: 'string' }, - services: { kind: 'stringArray' }, persistence: { kind: 'boolean' }, debug: { kind: 'boolean' }, seedsDir: { kind: 'string' }, @@ -378,7 +319,6 @@ const EDITABLE_CONFIG_KEYS: Record = { watch: { kind: 'boolean' }, }, }, - engine: { kind: 'string', enum: ['localstack', 'self'] }, selfEngine: { kind: 'object', subKeys: { @@ -391,13 +331,6 @@ const EDITABLE_CONFIG_KEYS: Record = { fallbackEndpoint: { kind: 'string' }, }, }, - aossSidecar: { - kind: 'object', - subKeys: { - enabled: { kind: 'boolean' }, - port: { kind: 'port' }, - }, - }, branding: { kind: 'object', subKeys: { @@ -424,13 +357,6 @@ const EDITABLE_CONFIG_KEYS: Record = { // is unset. const CONFIG_ENV_OVERRIDES: Record = { serverPort: ['LSS_DASHBOARD_PORT', 'PORT'], - localstackPort: ['LSS_LOCALSTACK_PORT'], - localstackEndpoint: ['LSS_LOCALSTACK_ENDPOINT'], - mode: ['LSS_LOCALSTACK_MODE'], - localstackEdition: ['LSS_LOCALSTACK_EDITION'], - localstackVersion: ['LSS_LOCALSTACK_VERSION'], - localstackImage: ['LSS_LOCALSTACK_IMAGE'], - localstackAuthToken: ['LOCALSTACK_AUTH_TOKEN'], // Note: the deprecated unprefixed ENABLE_DYNAMO_PROXY is NOT listed — it is // only a getter-time fallback (isEnableDynamoProxy) that a file value always // beats, so it never masks a saved value. @@ -543,6 +469,20 @@ export interface ConfigUpdateResult extends ConfigReloadResult { envOverridden: string[]; } +// v1 shipped two engines. v2 ships one, so `engine: "localstack"` (from a file +// or from LSS_ENGINE) cannot be honoured and must not be ignored either. +export function assertNoLocalStackEngine(value: string | undefined, source: string): void { + if (!value) return; + const kind = value.toLowerCase(); + if (kind === 'localstack') { + throw new Error( + `${source} is set to "localstack", which LSS v2 no longer supports — the self engine is the only engine. ` + + 'Remove the setting (and any localstack* keys) from your configuration. ' + + 'See docs/MIGRATION-v2.md.', + ); + } +} + export class ConfigManager { private static instance: ConfigManager; private config: LSSConfig = {}; @@ -583,15 +523,19 @@ export class ConfigManager { this.config = JSON.parse(content); this.configPath = candidate; console.log(`✅ Configuration loaded from ${candidate}`); - break; } catch (error) { console.warn(`⚠️ Failed to parse config file ${candidate}:`, error instanceof Error ? error.message : 'Unknown error'); + continue; } + // Outside the try: a v1 `engine` value is a migration error the user + // must see, not a parse warning to swallow. + assertNoLocalStackEngine(this.config.engine, `"engine" in ${candidate}`); + break; } } - // Environment variables override file values so secrets like LOCALSTACK_AUTH_TOKEN - // can be injected without committing them to disk. + // Environment variables override file values, so an instance can be + // retargeted (ports, engine data dir, region) without touching the file. this.loadFromEnv(); } @@ -601,33 +545,6 @@ export class ConfigManager { /* istanbul ignore next: the enclosing if guarantees one of these is truthy, so the `|| ''` fallback is unreachable */ this.config.serverPort = parseInt(process.env.LSS_DASHBOARD_PORT || process.env.PORT || '', 10); } - if (process.env.LSS_LOCALSTACK_PORT) { - this.config.localstackPort = parseInt(process.env.LSS_LOCALSTACK_PORT, 10); - } - if (process.env.LSS_LOCALSTACK_ENDPOINT) { - this.config.localstackEndpoint = process.env.LSS_LOCALSTACK_ENDPOINT; - } - if (process.env.LSS_LOCALSTACK_MODE) { - const mode = process.env.LSS_LOCALSTACK_MODE.toLowerCase(); - if (mode === 'managed' || mode === 'external') { - this.config.mode = mode; - } - } - if (process.env.LSS_LOCALSTACK_EDITION) { - const edition = process.env.LSS_LOCALSTACK_EDITION.toLowerCase(); - if (edition === 'community' || edition === 'pro') { - this.config.localstackEdition = edition; - } - } - if (process.env.LSS_LOCALSTACK_VERSION) { - this.config.localstackVersion = process.env.LSS_LOCALSTACK_VERSION; - } - if (process.env.LSS_LOCALSTACK_IMAGE) { - this.config.localstackImage = process.env.LSS_LOCALSTACK_IMAGE; - } - if (process.env.LOCALSTACK_AUTH_TOKEN) { - this.config.localstackAuthToken = process.env.LOCALSTACK_AUTH_TOKEN; - } if (process.env.LSS_ENABLE_DYNAMO_PROXY) { this.config.enableDynamoProxy = process.env.LSS_ENABLE_DYNAMO_PROXY === 'true' || process.env.LSS_ENABLE_DYNAMO_PROXY === '1'; } @@ -637,9 +554,6 @@ export class ConfigManager { if (process.env.AWS_REGION) { this.config.region = process.env.AWS_REGION; } - if (process.env.LSS_SERVICES) { - this.config.services = process.env.LSS_SERVICES.split(','); - } if (process.env.LSS_PERSISTENCE) { this.config.persistence = process.env.LSS_PERSISTENCE === 'true' || process.env.LSS_PERSISTENCE === '1'; } @@ -685,12 +599,10 @@ export class ConfigManager { invokeHost: process.env.LSS_INVOKE_HOST, }; } - if (process.env.LSS_ENGINE) { - const engine = process.env.LSS_ENGINE.toLowerCase(); - if (engine === 'localstack' || engine === 'self') { - this.config.engine = engine; - } - } + // v1 chose a backend with LSS_ENGINE / `engine`. v2 has one engine, so a + // leftover "localstack" is a loud, actionable error rather than a silent + // no-op that would quietly run against the wrong thing. + assertNoLocalStackEngine(process.env.LSS_ENGINE, 'LSS_ENGINE'); if (process.env.LSS_ENGINE_PORT) { this.config.selfEngine = { ...this.config.selfEngine, @@ -721,46 +633,6 @@ export class ConfigManager { return this.getServerPort(); } - getLocalStackPort(): number { - return this.config.localstackPort ?? 4566; - } - - getLocalStackEndpoint(): string { - if (this.config.localstackEndpoint) { - return this.config.localstackEndpoint; - } - const port = this.getLocalStackPort(); - return `http://localhost:${port}`; - } - - getMode(): LocalStackMode { - return this.config.mode ?? 'managed'; - } - - isExternal(): boolean { - return this.getMode() === 'external'; - } - - getLocalStackEdition(): LocalStackEdition { - return this.config.localstackEdition ?? 'community'; - } - - getLocalStackVersion(): string { - return this.config.localstackVersion ?? 'latest'; - } - - getLocalStackImage(): string { - if (this.config.localstackImage) { - return this.config.localstackImage; - } - const repo = this.getLocalStackEdition() === 'pro' ? 'localstack/localstack-pro' : 'localstack/localstack'; - return `${repo}:${this.getLocalStackVersion()}`; - } - - getLocalStackAuthToken(): string | undefined { - return this.config.localstackAuthToken; - } - isEnableDynamoProxy(): boolean { if (this.config.enableDynamoProxy !== undefined) { return this.config.enableDynamoProxy; @@ -777,10 +649,6 @@ export class ConfigManager { return this.config.region ?? (process.env.AWS_REGION || 'us-east-1'); } - getServices(): string[] { - return this.config.services ?? ['dynamodb', 'sqs', 'sns', 's3', 'lambda', 'events']; - } - isPersistence(): boolean { if (this.config.persistence !== undefined) { return this.config.persistence; @@ -889,9 +757,9 @@ export class ConfigManager { if (this.config.lambdaRuntime?.invokeHost) { return this.config.lambdaRuntime.invokeHost; } - // Self engine: nothing runs inside Docker, so callbacks into the invoke - // listeners resolve on the loopback directly. - return this.isSelfEngine() ? '127.0.0.1' : 'host.docker.internal'; + // Nothing runs inside a container, so callbacks into the invoke listeners + // resolve on the loopback directly. + return '127.0.0.1'; } /** @@ -916,21 +784,13 @@ export class ConfigManager { }; } - getEngineKind(): EngineKind { - return this.config.engine ?? 'localstack'; - } - - isSelfEngine(): boolean { - return this.getEngineKind() === 'self'; - } - getSelfEngineConfig(): ResolvedSelfEngineConfig { const selfEngine = this.config.selfEngine ?? {}; const stateDir = this.getStateDir(); const rawDataDir = selfEngine.dataDir ?? (stateDir ? path.join(stateDir, 'engine') : this.homeStateDir('engine')); return { - port: selfEngine.port ?? 14566, + port: selfEngine.port ?? DEFAULT_ENGINE_PORT, dataDir: path.isAbsolute(rawDataDir) ? rawDataDir : path.resolve(process.cwd(), rawDataDir), account: selfEngine.account ?? '000000000000', idleUnloadMs: selfEngine.idleUnloadMs ?? 300000, @@ -942,22 +802,6 @@ export class ConfigManager { }; } - getAossSidecarConfig(): ResolvedAossSidecarConfig { - // The self engine serves aoss natively — the sidecar must never run there. - const enabled = !this.isSelfEngine() && this.config.aossSidecar?.enabled !== false; - const port = this.config.aossSidecar?.port ?? 14567; - const stateDir = this.getStateDir(); - return { - enabled, - port, - endpoint: `http://localhost:${port}`, - // Mirrors the self-engine default so both persistence roots sit side by - // side (/aoss for test isolation, else the per-project dir - // under ~/.lss). - dataDir: stateDir ? path.join(stateDir, 'aoss') : this.homeStateDir('aoss'), - }; - } - // Fallback state root when the config declares no stateDir. Scoped to this // project: a flat ~/.lss/ meant every project on the machine shared one // set of DynamoDB tables, queues and OpenSearch indices, so opening a second @@ -967,12 +811,11 @@ export class ConfigManager { } // The AWS endpoint every SDK-based consumer (provisioner, explorers, seeds) - // should target for the active engine. + // targets. Reads the port directly rather than through getSelfEngineConfig(), + // which would also resolve the data dir — needless work for a URL, and it + // drags the project-root lookup into every caller that only wants an endpoint. getEngineEndpoint(): string { - if (this.isSelfEngine()) { - return `http://localhost:${this.getSelfEngineConfig().port}`; - } - return this.getLocalStackEndpoint(); + return `http://localhost:${this.config.selfEngine?.port ?? DEFAULT_ENGINE_PORT}`; } getConfigPath(): string { @@ -1060,26 +903,16 @@ export class ConfigManager { // (per request/registration/seed run) and follows a reload immediately. private resolvedBootValues(): Record { const selfEngine = this.getSelfEngineConfig(); - const aossSidecar = this.getAossSidecarConfig(); return { serverPort: this.getServerPort(), - localstackPort: this.getLocalStackPort(), - localstackEndpoint: this.getLocalStackEndpoint(), - mode: this.getMode(), - localstackEdition: this.getLocalStackEdition(), - localstackVersion: this.getLocalStackVersion(), - localstackImage: this.getLocalStackImage(), enableDynamoProxy: this.isEnableDynamoProxy(), dynamoProxyPort: this.getDynamoProxyPort(), region: this.getRegion(), - services: this.getServices(), persistence: this.isPersistence(), debug: this.isDebug(), stateDir: this.getStateDir(), - engine: this.getEngineKind(), - // Only the block's OWN settings: region/persistence (self engine) and the - // stateDir-derived dataDir (aoss) are tracked under their own keys above, - // so one change never flags two entries. + // Only the block's OWN settings: region/persistence are tracked under + // their own keys above, so one change never flags two entries. selfEngine: { port: selfEngine.port, dataDir: selfEngine.dataDir, @@ -1089,7 +922,6 @@ export class ConfigManager { fsync: selfEngine.fsync, fallbackEndpoint: selfEngine.fallbackEndpoint, }, - aossSidecar: { enabled: aossSidecar.enabled, port: aossSidecar.port }, }; } @@ -1229,28 +1061,17 @@ export class ConfigManager { printSummary(): void { console.log('\n📋 Configuration Summary:'); console.log(` Server Port: ${this.getServerPort()} (http://localhost:${this.getServerPort()})`); - console.log(` Engine: ${this.getEngineKind()}`); - if (this.isSelfEngine()) { - const selfEngine = this.getSelfEngineConfig(); - console.log(` Self Engine Port: ${selfEngine.port} (http://localhost:${selfEngine.port})`); - console.log(` Self Engine Data Dir: ${selfEngine.dataDir}`); - if (selfEngine.fallbackEndpoint) { - console.log(` Self Engine Fallback: ${selfEngine.fallbackEndpoint}`); - } - } else { - console.log(` LocalStack Mode: ${this.getMode()}`); - console.log(` LocalStack Port: ${this.getLocalStackPort()} (${this.getLocalStackEndpoint()})`); - if (!this.isExternal()) { - console.log(` LocalStack Image: ${this.getLocalStackImage()} (${this.getLocalStackEdition()})`); - console.log(` LocalStack Auth Token: ${this.getLocalStackAuthToken() ? 'set' : 'not set'}`); - } + const selfEngine = this.getSelfEngineConfig(); + console.log(` Self Engine Port: ${selfEngine.port} (http://localhost:${selfEngine.port})`); + console.log(` Self Engine Data Dir: ${selfEngine.dataDir}`); + if (selfEngine.fallbackEndpoint) { + console.log(` Self Engine Fallback: ${selfEngine.fallbackEndpoint}`); } console.log(` DynamoDB Proxy Enabled: ${this.isEnableDynamoProxy()}`); if (this.isEnableDynamoProxy()) { console.log(` DynamoDB Proxy Port: ${this.getDynamoProxyPort()}`); } console.log(` AWS Region: ${this.getRegion()}`); - console.log(` Services: ${this.getServices().join(', ')}`); console.log(` Persistence: ${this.isPersistence()}`); console.log(` Seeds Dir: ${this.getSeedsDir()}`); const secretSeedCount = Object.keys(this.getSecretSeeds()).length; diff --git a/src/server/services/dynamo-explorer.ts b/src/server/services/dynamo-explorer.ts index e23fb55..0037664 100644 --- a/src/server/services/dynamo-explorer.ts +++ b/src/server/services/dynamo-explorer.ts @@ -16,7 +16,7 @@ import { type LocalSecondaryIndexDescription, } from '@aws-sdk/client-dynamodb'; import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; export interface TtlInfo { enabled: boolean; @@ -77,7 +77,7 @@ export class DynamoExplorer { // LssClient and a bare curl all hit that path; only the dashboard was safe // because it always sends the region it read from /api/config. private constructor() { - const region = LocalStackManager.getInstance().getConfig().region; + const region = EngineManager.getInstance().getConfig().region; if (region) this.defaultRegion = region; } @@ -94,7 +94,7 @@ export class DynamoExplorer { const r = region || this.defaultRegion; let client = this.clients.get(r); if (!client) { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); client = new DynamoDBClient({ ...baseConfig, region: r }); this.clients.set(r, client); } diff --git a/src/server/services/localstack-manager.ts b/src/server/services/localstack-manager.ts deleted file mode 100644 index 75fcacc..0000000 --- a/src/server/services/localstack-manager.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Deprecated facade kept so the ~10 existing call sites (provisioner, -// explorers, seeds, dynamo-proxy, routes) stay untouched: they keep importing -// LocalStackManager, but the active provider may be the LocalStack container -// OR the in-process self engine — EngineManager decides from the config. -// New code should use EngineManager directly. - -import { EngineManager } from '../engine/engine-manager.js'; - -export class LocalStackManager { - private static instance: LocalStackManager; - - static getInstance(): LocalStackManager { - if (!LocalStackManager.instance) { - LocalStackManager.instance = new LocalStackManager(); - } - return LocalStackManager.instance; - } - - async start(): Promise { - return EngineManager.getInstance().start(); - } - - async stop(): Promise { - return EngineManager.getInstance().stop(); - } - - isRunning(): boolean { - return EngineManager.getInstance().isRunning(); - } - - getEndpoint(): string { - return EngineManager.getInstance().getEndpoint(); - } - - getConfig(): { endpoint: string; region: string; credentials: { accessKeyId: string; secretAccessKey: string } } { - return EngineManager.getInstance().getConfig(); - } -} diff --git a/src/server/services/opensearch-explorer.ts b/src/server/services/opensearch-explorer.ts index 2564e8f..76cf6a1 100644 --- a/src/server/services/opensearch-explorer.ts +++ b/src/server/services/opensearch-explorer.ts @@ -2,9 +2,7 @@ import { OpenSearchServerlessClient, ListCollectionsCommand, } from '@aws-sdk/client-opensearchserverless'; -import { LocalStackManager } from './localstack-manager.js'; -import { ConfigManager } from './config-manager.js'; -import { aossEndpoint } from './resource-provisioner.js'; +import { EngineManager } from '../engine/engine-manager.js'; export interface OpenSearchCollectionSummary { name: string; @@ -57,7 +55,7 @@ export class OpenSearchExplorer { // (CLI, LssClient, curl) still reads the project's own region — see the // matching note in DynamoExplorer. private constructor() { - const region = LocalStackManager.getInstance().getConfig().region; + const region = EngineManager.getInstance().getConfig().region; if (region) this.defaultRegion = region; } @@ -70,19 +68,18 @@ export class OpenSearchExplorer { if (region) this.defaultRegion = region; } - // aoss does not answer on the engine endpoint when the sidecar runs (no - // LocalStack edition provides aoss). Both planes target the base - // aossEndpoint() picks: the sidecar when enabled, else the engine itself - // (the self engine serves aoss natively). + // The engine serves the aoss control plane and the OpenSearch data plane + // natively, both on its own endpoint — v1 needed a sidecar here only because + // no LocalStack edition provides aoss at all. private aossBase(): string { - return aossEndpoint(ConfigManager.getInstance(), LocalStackManager.getInstance().getConfig().endpoint); + return EngineManager.getInstance().getConfig().endpoint; } private clientFor(region?: string): OpenSearchServerlessClient { const r = region || this.defaultRegion; let client = this.clients.get(r); if (!client) { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); client = new OpenSearchServerlessClient({ ...baseConfig, region: r, endpoint: this.aossBase() }); this.clients.set(r, client); } diff --git a/src/server/services/queue-inspector.ts b/src/server/services/queue-inspector.ts index 1ac78f4..58d2c6a 100644 --- a/src/server/services/queue-inspector.ts +++ b/src/server/services/queue-inspector.ts @@ -14,7 +14,7 @@ import { ListEventSourceMappingsCommand, UpdateEventSourceMappingCommand, } from '@aws-sdk/client-lambda'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; export interface QueueConsumer { functionName: string; @@ -111,7 +111,7 @@ export class QueueInspector { private defaultRegion = 'us-east-1'; private constructor() { - const region = LocalStackManager.getInstance().getConfig().region; + const region = EngineManager.getInstance().getConfig().region; if (region) this.defaultRegion = region; } @@ -130,7 +130,7 @@ export class QueueInspector { const r = region || this.defaultRegion; let client = this.sqsClients.get(r); if (!client) { - const base = LocalStackManager.getInstance().getConfig(); + const base = EngineManager.getInstance().getConfig(); client = new SQSClient({ ...base, region: r }); this.sqsClients.set(r, client); } @@ -141,7 +141,7 @@ export class QueueInspector { const r = region || this.defaultRegion; let client = this.lambdaClients.get(r); if (!client) { - const base = LocalStackManager.getInstance().getConfig(); + const base = EngineManager.getInstance().getConfig(); client = new LambdaClient({ ...base, region: r }); this.lambdaClients.set(r, client); } diff --git a/src/server/services/resource-provisioner.ts b/src/server/services/resource-provisioner.ts index 5f7daa6..9acaa12 100644 --- a/src/server/services/resource-provisioner.ts +++ b/src/server/services/resource-provisioner.ts @@ -31,7 +31,7 @@ import { DeleteCollectionCommand, ListCollectionsCommand, } from '@aws-sdk/client-opensearchserverless'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; import { ConfigManager } from './config-manager.js'; import { SeedManager } from './seed-manager.js'; import { resolveGeneratedSecretString } from './secret-value.js'; @@ -53,14 +53,6 @@ import AdmZip from 'adm-zip'; // logs) must target: the in-process sidecar when it is enabled — no LocalStack // edition provides aoss — else the active engine (the self engine serves aoss // natively). Exported so tests can pin the choice directly. -export function aossEndpoint( - config: Pick, - engineEndpoint: string, -): string { - const sidecar = config.getAossSidecarConfig(); - return sidecar.enabled ? sidecar.endpoint : engineEndpoint; -} - export class ResourceProvisioner { private static instance: ResourceProvisioner; private dynamoClient!: DynamoDBClient; @@ -91,7 +83,7 @@ export class ResourceProvisioner { } private initializeClients(region: string): void { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); const config = { ...baseConfig, region: region, @@ -108,7 +100,6 @@ export class ResourceProvisioner { // aoss lives on the sidecar when enabled, not on the engine endpoint. this.openSearchClient = new OpenSearchServerlessClient({ ...config, - endpoint: aossEndpoint(ConfigManager.getInstance(), baseConfig.endpoint), }); } @@ -754,7 +745,7 @@ export const handler = async (event, context) => { ); // The same base the client above targeted, so the logged data-plane URL // is the one that actually answers. - const base = aossEndpoint(ConfigManager.getInstance(), LocalStackManager.getInstance().getConfig().endpoint); + const base = EngineManager.getInstance().getConfig().endpoint; const endpoint = `${base}/_aoss/${resource.name}`; console.log(` ✓ Created OpenSearch collection: ${resource.name} (endpoint: ${endpoint})`); } catch (error: any) { @@ -1070,7 +1061,7 @@ export const handler = async (event, context) => { buckets: string[]; collections: string[]; }> { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); const config = region ? { ...baseConfig, region } : { ...baseConfig, region: this.currentRegion }; const dynamo = region && region !== this.currentRegion ? new DynamoDBClient(config) : this.dynamoClient; const sqs = region && region !== this.currentRegion ? new SQSClient(config) : this.sqsClient; @@ -1081,8 +1072,7 @@ export const handler = async (event, context) => { const aoss = region && region !== this.currentRegion ? new OpenSearchServerlessClient({ ...config, - endpoint: aossEndpoint(ConfigManager.getInstance(), baseConfig.endpoint), - }) + }) : this.openSearchClient; const [tables, queues, topics, buckets, collections] = await Promise.all([ diff --git a/src/server/services/s3-explorer.ts b/src/server/services/s3-explorer.ts index f0927a5..9678108 100644 --- a/src/server/services/s3-explorer.ts +++ b/src/server/services/s3-explorer.ts @@ -11,7 +11,7 @@ import { DeleteObjectCommand, HeadObjectCommand, } from '@aws-sdk/client-s3'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; export interface BucketSnapshot { name: string; @@ -52,7 +52,7 @@ export class S3Explorer { private defaultRegion = 'us-east-1'; private constructor() { - const region = LocalStackManager.getInstance().getConfig().region; + const region = EngineManager.getInstance().getConfig().region; if (region) this.defaultRegion = region; } @@ -71,7 +71,7 @@ export class S3Explorer { const r = region || this.defaultRegion; let client = this.clients.get(r); if (!client) { - const base = LocalStackManager.getInstance().getConfig(); + const base = EngineManager.getInstance().getConfig(); // forcePathStyle is required so LocalStack receives the bucket name in // the URL path instead of as a virtual-host subdomain. client = new S3Client({ ...base, region: r, forcePathStyle: true }); diff --git a/src/server/services/secrets-explorer.ts b/src/server/services/secrets-explorer.ts index 021964e..313f0cf 100644 --- a/src/server/services/secrets-explorer.ts +++ b/src/server/services/secrets-explorer.ts @@ -12,7 +12,7 @@ import { GetSecretValueCommand, type SecretListEntry, } from '@aws-sdk/client-secrets-manager'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; export interface SecretSummary { name: string; @@ -51,7 +51,7 @@ export class SecretsExplorer { // (CLI, LssClient, curl) still reads the project's own region — see the // matching note in DynamoExplorer. private constructor() { - const region = LocalStackManager.getInstance().getConfig().region; + const region = EngineManager.getInstance().getConfig().region; if (region) this.defaultRegion = region; } @@ -68,7 +68,7 @@ export class SecretsExplorer { const r = region || this.defaultRegion; let client = this.clients.get(r); if (!client) { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); client = new SecretsManagerClient({ ...baseConfig, region: r }); this.clients.set(r, client); } diff --git a/src/server/services/seed-manager.ts b/src/server/services/seed-manager.ts index c9006e1..86576ae 100644 --- a/src/server/services/seed-manager.ts +++ b/src/server/services/seed-manager.ts @@ -15,7 +15,7 @@ import { CreateSecretCommand, DescribeSecretCommand, } from '@aws-sdk/client-secrets-manager'; -import { LocalStackManager } from './localstack-manager.js'; +import { EngineManager } from '../engine/engine-manager.js'; import { ConfigManager } from './config-manager.js'; import { normalizeSecretSeed, resolveGeneratedSecretString, type SecretSeedValue } from './secret-value.js'; @@ -70,7 +70,7 @@ export class SeedManager { const r = region || this.defaultRegion; let client = this.clients.get(r); if (!client) { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); client = new DynamoDBClient({ ...baseConfig, region: r }); this.clients.set(r, client); } @@ -83,7 +83,7 @@ export class SeedManager { const r = region || this.defaultRegion; let client = this.secretsClients.get(r); if (!client) { - const baseConfig = LocalStackManager.getInstance().getConfig(); + const baseConfig = EngineManager.getInstance().getConfig(); client = new SecretsManagerClient({ ...baseConfig, region: r }); this.secretsClients.set(r, client); } @@ -95,7 +95,7 @@ export class SeedManager { // are explicit deletes — verify the endpoint hostname every time and refuse // anything that isn't loopback/local before issuing a DeleteRequest. private assertLocalEndpoint(): void { - const endpoint = LocalStackManager.getInstance().getEndpoint(); + const endpoint = EngineManager.getInstance().getEndpoint(); let hostname: string; try { hostname = new URL(endpoint).hostname.toLowerCase(); @@ -230,7 +230,7 @@ export class SeedManager { tableName: entry.tableName, inserted: 0, skipped: true, - reason: 'table does not exist in LocalStack', + reason: 'table does not exist in the engine', } as SeedResult; } try { @@ -298,7 +298,7 @@ export class SeedManager { tableName: entry.tableName, deleted: 0, skipped: true, - reason: 'table does not exist in LocalStack', + reason: 'table does not exist in the engine', }); continue; } diff --git a/src/ui/package.json b/src/ui/package.json index 07662c5..9599430 100644 --- a/src/ui/package.json +++ b/src/ui/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "dependencies": { - "@treeui/vue": "^0.23.0", + "@treeui/vue": "^0.25.0", "vue": "^3.5.13", "vue-router": "^4.6.4" }, diff --git a/src/ui/src/App.vue b/src/ui/src/App.vue index d7afc3e..f0379a7 100644 --- a/src/ui/src/App.vue +++ b/src/ui/src/App.vue @@ -7,7 +7,6 @@ import { } from '@treeui/vue'; import type { TNavMenuItem } from '@treeui/vue'; import { currentRegion, regionOptions, applyConfiguredRegion } from './services/region'; -import { applyEngineKind, engineLabel } from './services/engine'; import { api } from './services/api'; import type { HealthInfo } from './services/api'; import { branding, loadBranding, applyTheme } from './services/branding'; @@ -17,7 +16,7 @@ const router = useRouter(); const health = ref({ status: 'unknown', - localstack: false, + engineRunning: false, dynamoProxy: { enabled: false, running: false, port: 8000 }, }); const theme = ref<'dark' | 'light'>( @@ -63,15 +62,12 @@ function onMenuSelect(value: string) { async function checkHealth() { try { health.value = await api.checkHealth(); - applyEngineKind(health.value.engine?.kind); } catch (error) { console.error('Health check failed:', error); } } -// `localstack` is the deprecated alias; prefer engineRunning when the server -// is new enough to send it. -const engineRunning = computed(() => health.value.engineRunning ?? health.value.localstack); +const engineRunning = computed(() => health.value.engineRunning); onMounted(async () => { checkHealth(); @@ -80,10 +76,7 @@ onMounted(async () => { // but a region the user picks while /api/config is in flight must stick. const regionAtMount = currentRegion.value; api.getConfig() - .then((config) => { - applyConfiguredRegion(config.region, currentRegion.value !== regionAtMount); - applyEngineKind(config.engine.kind); - }) + .then((config) => applyConfiguredRegion(config.region, currentRegion.value !== regionAtMount)) .catch(() => { /* keep stored/default region */ }); await loadBranding(); theme.value = @@ -124,7 +117,7 @@ onBeforeUnmount(() => { :tone="engineRunning ? 'success' : 'danger'" variant="soft" > - {{ engineLabel }}: {{ engineRunning ? 'Running' : 'Offline' }} + Engine: {{ engineRunning ? 'Running' : 'Offline' }} ([]); @@ -64,7 +64,7 @@ function openDetail(name: string) { router.push(`/queues/${encodeURIComponent(name)}`); } -function activityTone(queue: QueueSnapshot): TreeBadgeTone { +function activityTone(queue: QueueSnapshot): TBadgeTone { if (queue.available > 0) return 'warning'; if (queue.inFlight > 0) return 'info'; if (queue.consumers.some(c => c.enabled)) return 'success'; @@ -136,7 +136,7 @@ onBeforeUnmount(() => { diff --git a/src/ui/src/components/ServicesList.vue b/src/ui/src/components/ServicesList.vue index 1f90caf..7cf99c1 100644 --- a/src/ui/src/components/ServicesList.vue +++ b/src/ui/src/components/ServicesList.vue @@ -4,7 +4,7 @@ import { TCard, TButton, TInput, TFormField, TBadge, TTable, TEmptyState, TStack, TModal, TConfirmDialog, TSpinner, TTag, TText, TIcon, TLink, TCodeBlock, useToast, } from '@treeui/vue'; -import type { TreeBadgeTone } from '@treeui/vue'; +import type { TBadgeTone } from '@treeui/vue'; interface TableColumn { key: string; @@ -15,7 +15,7 @@ interface TableColumn { } import { api } from '../services/api'; import type { ServiceSummary } from '../services/api'; -import { engineLabel } from '../services/engine'; +import { ENGINE_LABEL } from '../services/engine'; const toast = useToast(); const services = ref([]); @@ -151,7 +151,7 @@ function formatDate(timestamp: number): string { return new Date(timestamp).toLocaleString(); } -function statusTone(status: string): TreeBadgeTone { +function statusTone(status: string): TBadgeTone { switch (status) { case 'running': return 'success'; case 'registered': return 'warning'; @@ -344,7 +344,7 @@ onBeforeUnmount(() => { ([]); @@ -106,7 +106,7 @@ onBeforeUnmount(() => { diff --git a/src/ui/src/components/dynamo/DynamoTablesList.vue b/src/ui/src/components/dynamo/DynamoTablesList.vue index 816bbc7..409f65d 100644 --- a/src/ui/src/components/dynamo/DynamoTablesList.vue +++ b/src/ui/src/components/dynamo/DynamoTablesList.vue @@ -10,7 +10,10 @@ import type { DynamoTableSummary, SeedFileEntry } from '../../services/api'; const emit = defineEmits<{ (e: 'open', name: string): void }>(); +// TTable's `rows` prop is Record[]; the index signature keeps +// the concrete row type usable there without casting at every call site. interface TableRow { + [key: string]: unknown; name: string; status?: string; itemCount: number; diff --git a/src/ui/src/components/lambdas/LambdaDetail.vue b/src/ui/src/components/lambdas/LambdaDetail.vue index 0169afa..42c9c7b 100644 --- a/src/ui/src/components/lambdas/LambdaDetail.vue +++ b/src/ui/src/components/lambdas/LambdaDetail.vue @@ -6,7 +6,7 @@ import { TCard, TCodeBlock, TTag, TEmptyState, TGrid, TStat, TTable, TTextarea, TFormField, TSelect, TDivider, TText, TIcon, useToast, } from '@treeui/vue'; -import type { TreeBadgeTone } from '@treeui/vue'; +import type { TBadgeTone } from '@treeui/vue'; import { api } from '../../services/api'; import type { InvokeResult, LambdaDetailInfo, LambdaInvocationRecord } from '../../services/api'; @@ -168,7 +168,7 @@ function toggleLogs(idx: number) { expandedLogs.value[idx] = !expandedLogs.value[idx]; } -function statusTone(status?: string): TreeBadgeTone { +function statusTone(status?: string): TBadgeTone { switch (status) { case 'online': return 'success'; case 'starting': return 'info'; @@ -177,7 +177,7 @@ function statusTone(status?: string): TreeBadgeTone { } } -function methodTone(method: string): TreeBadgeTone { +function methodTone(method: string): TBadgeTone { return method === 'ANY' ? 'info' : 'neutral'; } diff --git a/src/ui/src/components/lambdas/LambdasList.vue b/src/ui/src/components/lambdas/LambdasList.vue index a6e7e73..1f7de8e 100644 --- a/src/ui/src/components/lambdas/LambdasList.vue +++ b/src/ui/src/components/lambdas/LambdasList.vue @@ -2,10 +2,10 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue'; import { RouterLink } from 'vue-router'; import { - TCard, TButton, TBadge, TTable, TEmptyState, TStack, TGrid, TStat, + TCard, TBadge, TTable, TEmptyState, TStack, TGrid, TStat, TTag, TSpinner, TAlert, TText, TLink, } from '@treeui/vue'; -import type { TreeBadgeTone } from '@treeui/vue'; +import type { TBadgeTone } from '@treeui/vue'; import { api } from '../../services/api'; import type { LambdaSummary } from '../../services/api'; @@ -45,7 +45,7 @@ async function loadLambdas() { } } -function statusTone(status: string): TreeBadgeTone { +function statusTone(status: string): TBadgeTone { switch (status) { case 'online': return 'success'; case 'starting': return 'info'; diff --git a/src/ui/src/components/opensearch/OpenSearchCollectionView.vue b/src/ui/src/components/opensearch/OpenSearchCollectionView.vue index 7176064..4dad428 100644 --- a/src/ui/src/components/opensearch/OpenSearchCollectionView.vue +++ b/src/ui/src/components/opensearch/OpenSearchCollectionView.vue @@ -219,7 +219,7 @@ watch(() => props.name, load); diff --git a/src/ui/src/components/opensearch/OpenSearchCollectionsList.vue b/src/ui/src/components/opensearch/OpenSearchCollectionsList.vue index 65fed32..c726878 100644 --- a/src/ui/src/components/opensearch/OpenSearchCollectionsList.vue +++ b/src/ui/src/components/opensearch/OpenSearchCollectionsList.vue @@ -6,7 +6,7 @@ import { TSpinner, TAlert, TTag, TTable, TText, TInput, } from '@treeui/vue'; import { api } from '../../services/api'; -import type { OpenSearchCollectionSummary } from '../../services/api'; +import type { OpenSearchCollectionSummary, ResourceOwnersResponse } from '../../services/api'; const emit = defineEmits<{ (e: 'open', name: string): void }>(); @@ -53,7 +53,7 @@ async function load() { try { const [list, owners] = await Promise.all([ api.listOpenSearchCollections(), - api.listResourceOwners().catch(() => ({ tables: [], queues: [], topics: [], buckets: [] })), + api.listResourceOwners().catch((): ResourceOwnersResponse => ({ tables: [], queues: [], topics: [], buckets: [], collections: [] })), ]); collections.value = list.collections; const map: Record = {}; diff --git a/src/ui/src/components/queues/QueueDetail.vue b/src/ui/src/components/queues/QueueDetail.vue index 1711b18..dfe2dd1 100644 --- a/src/ui/src/components/queues/QueueDetail.vue +++ b/src/ui/src/components/queues/QueueDetail.vue @@ -3,7 +3,7 @@ import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { TButton, TBadge, TStack, TTabs, TTabList, TTab, TTabPanel, TSpinner, TAlert, - TCard, TTag, TEmptyState, TGrid, TStat, TProgress, TDivider, + TCard, TTag, TEmptyState, TGrid, TStat, TProgress, TText, TIcon, TDescriptionList, TDescriptionItem, useToast, } from '@treeui/vue'; import { api } from '../../services/api'; diff --git a/src/ui/src/pages/OverviewPage.vue b/src/ui/src/pages/OverviewPage.vue index 8bb3238..0a8b138 100644 --- a/src/ui/src/pages/OverviewPage.vue +++ b/src/ui/src/pages/OverviewPage.vue @@ -6,7 +6,6 @@ import { } from '@treeui/vue'; import { RouterLink } from 'vue-router'; import { api } from '../services/api'; -import { engineLabel, isSelfEngine } from '../services/engine'; import type { HealthInfo, LambdaSummary, LssConfigSnapshot, PortEntry, ServiceApiInfo, ServiceSummary, } from '../services/api'; @@ -57,15 +56,11 @@ const totalServices = computed(() => services.value.length); const lambdasOnline = computed(() => lambdas.value.filter(l => l.status === 'online').length); const totalLambdas = computed(() => lambdas.value.length); const apiRoutesTotal = computed(() => apis.value.reduce((s, a) => s + a.routes.length, 0)); -// `localstack` is the deprecated alias for engineRunning; both mean "the -// ACTIVE engine is healthy", which on this stack may well be the self engine. -const engineRunning = computed(() => health.value?.engineRunning ?? health.value?.localstack ?? false); +const engineRunning = computed(() => health.value?.engineRunning ?? false); const engineTone = computed(() => (engineRunning.value ? 'success' : 'danger')); -const tagline = computed(() => - isSelfEngine.value - ? 'Every AWS service in one process. No Docker, no token.' - : 'One LocalStack. Every microservice. Zero docker juggling.', -); +// What the engine reports it answers for — the truth, rather than a configured +// wish list (v1 read it from a configured service allow-list). +const emulatedServices = computed(() => health.value?.engine?.services ?? []); const proxyEnabled = computed(() => Boolean(health.value?.dynamoProxy?.enabled)); const proxyRunning = computed(() => Boolean(health.value?.dynamoProxy?.running)); const autoPackage = computed(() => Boolean(config.value?.autoPackage)); @@ -74,7 +69,6 @@ const persistence = computed(() => Boolean(config.value?.persistence)); const portKindTone: Record = { orchestrator: 'info', engine: 'success', - sidecar: 'info', proxy: 'warning', 'service-api': 'info', 'service-invoke': 'neutral', @@ -82,7 +76,6 @@ const portKindTone: Record = { orchestrator: 'orchestrator', engine: 'engine', - sidecar: 'sidecar', proxy: 'proxy', 'service-api': 'HTTP API', 'service-invoke': 'invoke', @@ -134,18 +127,18 @@ onBeforeUnmount(() => { Local Serverless Stack - {{ tagline }} + Every AWS service in one process. No Docker, no token.

A single control plane for your local serverless workflow. Register a Serverless Framework project - and LSS parses its CloudFormation template, provisions the resources on the shared - {{ engineLabel }}, wires up event-source mappings, and gives you live visibility into every - queue, table, and topic — without one emulator per service. + and LSS parses its CloudFormation template, provisions the resources on the in-process + engine, wires up event-source mappings, and gives you live visibility into every queue, + table, and topic — without one emulator per service.

- {{ engineLabel }} {{ engineRunning ? 'running' : 'offline' }} + Engine {{ engineRunning ? 'running' : 'offline' }} { Server status - + {{ engineRunning ? 'Running' : 'Offline' }} @@ -185,17 +178,7 @@ onBeforeUnmount(() => { {{ config?.engine?.endpoint || '—' }} - - - + this process — no Docker @@ -247,15 +230,10 @@ onBeforeUnmount(() => {
- + {{ svc }} - + diff --git a/src/ui/src/pages/ServiceDetailPage.vue b/src/ui/src/pages/ServiceDetailPage.vue index b083019..695a1f5 100644 --- a/src/ui/src/pages/ServiceDetailPage.vue +++ b/src/ui/src/pages/ServiceDetailPage.vue @@ -6,10 +6,10 @@ import { TTag, TEmptyState, TModal, TConfirmDialog, TText, TIcon, TCodeBlock, useToast, TDescriptionList, TDescriptionItem, } from '@treeui/vue'; -import type { TreeBadgeTone } from '@treeui/vue'; +import type { TBadgeTone } from '@treeui/vue'; import { api } from '../services/api'; import type { ServiceDetail, ServiceResource } from '../services/api'; -import { engineLabel } from '../services/engine'; +import { ENGINE_LABEL } from '../services/engine'; const props = defineProps<{ serviceName: string }>(); const router = useRouter(); @@ -114,7 +114,7 @@ async function confirmDelete() { } } -function statusTone(status?: string): TreeBadgeTone { +function statusTone(status?: string): TBadgeTone { switch (status) { case 'running': return 'success'; case 'registered': return 'warning'; @@ -403,7 +403,7 @@ watch(() => props.serviceName, load); (null); const restartKeys = ref([]); const envMasked = ref([]); -const engineOptions = [ - { value: 'localstack', label: 'LocalStack' }, - { value: 'self', label: 'Self engine' }, -]; -const modeOptions = [ - { value: 'managed', label: 'Managed' }, - { value: 'external', label: 'External' }, -]; -const editionOptions = [ - { value: 'community', label: 'Community' }, - { value: 'pro', label: 'Pro' }, -]; const executionOptions = [ { value: 'auto', label: 'Auto' }, { value: 'artifact', label: 'Artifact' }, @@ -54,15 +42,6 @@ const form = reactive({ region: 'us-east-1', persistence: true, debug: false, - engine: 'localstack', - mode: 'managed', - edition: 'community', - version: '', - image: '', - endpoint: '', - localstackPort: 4566, - aossEnabled: true, - aossPort: 14567, sePort: 14566, seAccount: '000000000000', seMemoryBudgetMb: 128, @@ -80,7 +59,6 @@ const form = reactive({ packageCommand: '', packageTimeoutMs: 300000, seedsDir: '', - servicesCsv: '', brTitle: '', brSubtitle: '', brTheme: 'dark', @@ -99,15 +77,6 @@ function applySnapshot(s: LssConfigSnapshot) { form.region = s.region; form.persistence = s.persistence; form.debug = s.debug; - form.engine = s.engine.kind; - form.mode = s.localstack.mode; - form.edition = s.localstack.edition; - form.version = s.localstack.version; - form.image = s.localstack.image; - form.endpoint = s.localstack.endpoint; - form.localstackPort = s.localstack.port; - form.aossEnabled = s.aossSidecar.enabled; - form.aossPort = s.aossSidecar.port; form.sePort = s.selfEngine.port; form.seAccount = s.selfEngine.account; form.seMemoryBudgetMb = s.selfEngine.memoryBudgetMb; @@ -125,7 +94,6 @@ function applySnapshot(s: LssConfigSnapshot) { form.packageCommand = s.packageCommand; form.packageTimeoutMs = s.packageTimeoutMs; form.seedsDir = s.seedsDir; - form.servicesCsv = s.services.join(', '); form.brTitle = s.branding.title; form.brSubtitle = s.branding.subtitle; form.brTheme = s.branding.defaultTheme; @@ -176,30 +144,12 @@ function buildPatch(): { patch: LssConfigUpdate; errors: string[] } { if (dirty.has('region')) patch.region = form.region; if (dirty.has('persistence')) patch.persistence = form.persistence; if (dirty.has('debug')) patch.debug = form.debug; - if (dirty.has('engine')) patch.engine = form.engine as 'localstack' | 'self'; - if (dirty.has('mode')) patch.mode = form.mode as 'managed' | 'external'; - if (dirty.has('edition')) patch.localstackEdition = form.edition as 'community' | 'pro'; - if (dirty.has('version')) patch.localstackVersion = orNull(form.version); - if (dirty.has('image')) patch.localstackImage = orNull(form.image); - if (dirty.has('endpoint')) patch.localstackEndpoint = orNull(form.endpoint); - if (dirty.has('localstackPort')) patch.localstackPort = asPort(form.localstackPort, 'LocalStack port'); if (dirty.has('proxyEnabled')) patch.enableDynamoProxy = form.proxyEnabled; if (dirty.has('proxyPort')) patch.dynamoProxyPort = asPort(form.proxyPort, 'Dynamo proxy port'); if (dirty.has('autoPackage')) patch.autoPackage = form.autoPackage; if (dirty.has('packageCommand')) patch.packageCommand = orNull(form.packageCommand); if (dirty.has('packageTimeoutMs')) patch.packageTimeoutMs = asPositive(form.packageTimeoutMs, 'Package timeout'); if (dirty.has('seedsDir')) patch.seedsDir = orNull(form.seedsDir); - if (dirty.has('servicesCsv')) { - const list = form.servicesCsv.split(',').map(s => s.trim()).filter(Boolean); - patch.services = list.length ? list : null; - } - - if (dirty.has('aossEnabled') || dirty.has('aossPort')) { - patch.aossSidecar = { - ...(dirty.has('aossEnabled') ? { enabled: form.aossEnabled } : {}), - ...(dirty.has('aossPort') ? { port: asPort(form.aossPort, 'aoss sidecar port') } : {}), - }; - } const selfEngine: NonNullable = {}; if (dirty.has('sePort')) selfEngine.port = asPort(form.sePort, 'Self engine port'); @@ -385,69 +335,31 @@ onMounted(load); - - - - - + + + + + + + + Data dir: {{ snapshot.selfEngine.dataDir }} @@ -478,15 +390,9 @@ onMounted(load); - - - - - - diff --git a/src/ui/src/services/api.ts b/src/ui/src/services/api.ts index af3967b..e54aded 100644 --- a/src/ui/src/services/api.ts +++ b/src/ui/src/services/api.ts @@ -188,13 +188,12 @@ export interface SeedClearResult { export interface HealthInfo { status: string; - /** @deprecated reads "localstack" even on the self engine — use engineRunning. */ - localstack: boolean; - engineRunning?: boolean; + engineRunning: boolean; engine?: { - kind: 'localstack' | 'self'; + kind: 'self'; running: boolean; endpoint: string; + services?: string[]; }; dynamoProxy: { enabled: boolean; @@ -259,30 +258,15 @@ export interface ServiceRuntimeInfo { export interface LssConfigSnapshot { serverPort: number; engine: { - kind: 'localstack' | 'self'; + kind: 'self'; endpoint: string; }; - localstack: { - mode: string; - endpoint: string; - port: number; - edition: string; - version: string; - image: string; - hasAuthToken: boolean; - }; selfEngine: SelfEngineInfo; - aossSidecar: { - enabled: boolean; - port: number; - endpoint: string; - }; dynamoProxy: { enabled: boolean; port: number; }; region: string; - services: string[]; persistence: boolean; debug: boolean; seedsDir: string; @@ -307,16 +291,9 @@ export interface LssConfigSnapshot { // the file; object blocks merge one level deep and a null subkey deletes it. export interface LssConfigUpdate { serverPort?: number; - localstackPort?: number; - localstackEndpoint?: string | null; - mode?: 'managed' | 'external'; - localstackEdition?: 'community' | 'pro'; - localstackVersion?: string | null; - localstackImage?: string | null; enableDynamoProxy?: boolean; dynamoProxyPort?: number; region?: string; - services?: string[] | null; persistence?: boolean; debug?: boolean; seedsDir?: string | null; @@ -325,7 +302,6 @@ export interface LssConfigUpdate { packageCommand?: string | null; packageArgs?: string[]; packageTimeoutMs?: number; - engine?: 'localstack' | 'self'; lambdaRuntime?: { enabled?: boolean; execution?: 'auto' | 'artifact' | 'source'; @@ -344,10 +320,6 @@ export interface LssConfigUpdate { fsync?: boolean; fallbackEndpoint?: string | null; }; - aossSidecar?: { - enabled?: boolean; - port?: number; - }; branding?: { title?: string | null; subtitle?: string | null; @@ -372,7 +344,7 @@ export interface ConfigReloadResponse { export interface PortEntry { name: string; - kind: 'orchestrator' | 'engine' | 'sidecar' | 'proxy' | 'service-api' | 'service-invoke'; + kind: 'orchestrator' | 'engine' | 'proxy' | 'service-api' | 'service-invoke'; port: number; url: string; description: string; diff --git a/src/ui/src/services/engine.ts b/src/ui/src/services/engine.ts index da729a1..f2eed8c 100644 --- a/src/ui/src/services/engine.ts +++ b/src/ui/src/services/engine.ts @@ -1,20 +1,4 @@ -import { computed, ref } from 'vue'; - -// Which AWS engine this orchestrator is serving. The dashboard used to say -// "LocalStack" everywhere — header badge, Overview cards, empty states, delete -// confirmations — regardless of the active engine, so a self-engine user (no -// Docker, no container, no token anywhere in the stack) was told they were -// running LocalStack. Every one of those strings now reads from here. - -export type EngineKind = 'localstack' | 'self'; - -export const engineKind = ref('localstack'); - -export function applyEngineKind(kind: EngineKind | undefined): void { - if (kind) engineKind.value = kind; -} - -export const isSelfEngine = computed(() => engineKind.value === 'self'); - -/** Display name for the active engine — use in any user-facing string. */ -export const engineLabel = computed(() => (isSelfEngine.value ? 'Self engine' : 'LocalStack')); +// One source for every user-facing mention of the engine — header badge, +// Overview cards, empty states, delete confirmations. A named export rather +// than a literal sprinkled through templates, so renaming it is one edit. +export const ENGINE_LABEL = 'self engine'; diff --git a/src/ui/tsconfig.json b/src/ui/tsconfig.json index 0472bc6..8e12a71 100644 --- a/src/ui/tsconfig.json +++ b/src/ui/tsconfig.json @@ -12,6 +12,12 @@ "src/**/*.tsx", "src/**/*.vue" ], + // The root tsconfig excludes "src/ui" (so the server/client projects never + // pull the dashboard in), and `exclude` is INHERITED by every config that + // extends it — with paths resolved against the ROOT file. Left alone, that + // excluded this whole directory from its own project and `vue-tsc --noEmit` + // silently checked nothing. Reset it here. + "exclude": ["node_modules", "dist"], "references": [ { "path": "./tsconfig.node.json" diff --git a/tests/integration/apigw-raw-routes.test.ts b/tests/integration/apigw-raw-routes.test.ts index 0bd6277..e4b0d0e 100644 --- a/tests/integration/apigw-raw-routes.test.ts +++ b/tests/integration/apigw-raw-routes.test.ts @@ -1,5 +1,5 @@ // End-to-end validation of raw cross-stack AWS::ApiGatewayV2 routes against the -// localstack-free example: `gateway-stack` owns NO Lambdas and declares its +// apigw-raw fixture: `gateway-stack` owns NO Lambdas and declares its // ::Api/::Route/::Integration/::Authorizer (+ Lambda::Permission) purely under // CFN `resources:`, all targeting users-service's functions by ARN. // @@ -8,10 +8,9 @@ // service boundary, and NOTHING falls back to an /api/{proxy+} or $default // catch-all. // -// Requires Docker + LOCALSTACK_AUTH_TOKEN *and* an installed example -// (`npm run setup` inside examples/localstack-free, which each service needs for -// `serverless package`). The suite skips cleanly when either is missing, so it -// never fails a token-less or un-provisioned checkout. +// Runs on the self engine — no Docker, no auth token. It still needs the fixture +// services installed (`npm install` in each, which `serverless package` requires), +// so it skips cleanly on a checkout where they are not. import { exec } from 'child_process'; import { promisify } from 'util'; import path from 'path'; @@ -19,21 +18,20 @@ import fs from 'fs'; const execAsync = promisify(exec); const REPO_ROOT = path.resolve(__dirname, '../..'); -const EXAMPLE = path.join(REPO_ROOT, 'examples/localstack-free'); -const CONFIG = path.join(EXAMPLE, 'lss.config.json'); -const BASE = 'http://localhost:3120'; +const FIXTURE = path.join(REPO_ROOT, 'tests/integration/fixtures/apigw-raw'); +const CONFIG = path.join(FIXTURE, 'lss.config.json'); +const BASE = 'http://localhost:3397'; const GATEWAY_API = 'http://localhost:3613'; -const USERS_PATH = path.join(EXAMPLE, 'users-service'); -const GATEWAY_PATH = path.join(EXAMPLE, 'gateway-stack'); +const USERS_PATH = path.join(FIXTURE, 'users-service'); +const GATEWAY_PATH = path.join(FIXTURE, 'gateway-stack'); const LIST_USERS_ARN = 'arn:aws:lambda:sa-east-1:000000000000:function:users-service-dev-listUsers'; -// The example must be installed for `serverless package` to run in each service. -const EXAMPLE_READY = fs.existsSync(path.join(USERS_PATH, 'node_modules')) +// The fixture services must be installed for `serverless package` to run. +const FIXTURE_READY = fs.existsSync(path.join(USERS_PATH, 'node_modules')) && fs.existsSync(path.join(GATEWAY_PATH, 'node_modules')); -const HAS_TOKEN = Boolean(process.env.LOCALSTACK_AUTH_TOKEN); -const suite = HAS_TOKEN && EXAMPLE_READY ? describe : describe.skip; +const suite = FIXTURE_READY ? describe : describe.skip; function cli(args: string) { return execAsync(`node bin/cli.js ${args}`, { cwd: REPO_ROOT, env: process.env }); @@ -69,8 +67,8 @@ suite('raw cross-stack ApiGatewayV2 routes (integration)', () => { await cli(`start --config ${CONFIG}`); await waitFor(async () => { const res = await fetch(`${BASE}/api/health`); - const j = await res.json() as { localstack?: boolean }; - return j.localstack === true; + const j = await res.json() as { engineRunning?: boolean }; + return j.engineRunning === true; }, 150000); // Register the GATEWAY FIRST, while its target Lambdas are still unknown — diff --git a/tests/integration/client.test.ts b/tests/integration/client.test.ts index 1faf98c..2a186c1 100644 --- a/tests/integration/client.test.ts +++ b/tests/integration/client.test.ts @@ -1,6 +1,6 @@ // End-to-end validation of the programmatic client (LssClient), driven entirely -// through the client itself — it boots its OWN isolated LSS + LocalStack via -// `lifecycle.start()` (distinct ports/stateDir from features.test.ts), registers +// through the client itself — it boots its OWN isolated LSS on the self engine +// via `lifecycle.start()` (distinct ports/stateDir from features.test.ts), registers // the fixture service (tests/integration/fixtures/sample-microservice), and // exercises every namespace against the live stack, then tears down via // `lifecycle.stop()`. @@ -9,8 +9,8 @@ // would — so it validates the compiled output + public surface, not the TS source. // Run `npm run build` before `npm run test:integration`. // -// Requires Docker + a LOCALSTACK_AUTH_TOKEN (community images >= 2026.5 need it). -// Skipped when no token is present, like features.test.ts. +// No Docker and no auth token: the engine runs in the orchestrator process, so +// this suite executes anywhere, like features.test.ts. import { exec } from 'child_process'; import { promisify } from 'util'; import path from 'path'; @@ -24,8 +24,7 @@ const SERVICE_PATH = path.join(REPO_ROOT, 'tests/integration/fixtures/sample-mic const QUEUE = 'sample-microservice-OrderProcessing'; const BUCKET = 'sample-microservice-uploads'; -const HAS_TOKEN = Boolean(process.env.LOCALSTACK_AUTH_TOKEN); -const suite = HAS_TOKEN ? describe : describe.skip; +const suite = describe; async function waitFor(cond: () => Promise, timeoutMs: number, intervalMs = 1000): Promise { const start = Date.now(); @@ -40,10 +39,9 @@ suite('LssClient (integration, built lib)', () => { const lss = new LssClient({ configPath: CONFIG, cwd: REPO_ROOT }); beforeAll(async () => { - if (!HAS_TOKEN) return; await lss.lifecycle.stop().catch(() => undefined); await lss.lifecycle.start(); - await lss.lifecycle.waitUntilReady({ timeoutMs: 150000, intervalMs: 2000 }); + await lss.lifecycle.waitUntilReady({ timeoutMs: 60000, intervalMs: 250 }); // Provision the fixture service by registering it through the client. const reg = (await lss.services.register({ servicePath: SERVICE_PATH, invokePort: 3997 })) as { success?: boolean; @@ -52,10 +50,7 @@ suite('LssClient (integration, built lib)', () => { }, 240000); afterAll(async () => { - if (!HAS_TOKEN) return; await lss.lifecycle.stop().catch(() => undefined); - await execAsync('docker rm -f $(docker ps -aq --filter name=lss-localstack-4598) 2>/dev/null || true').catch(() => undefined); - await execAsync('docker volume rm lss-localstack-4598-data 2>/dev/null || true').catch(() => undefined); await execAsync('rm -rf tests/.lss-client-integration 2>/dev/null || true').catch(() => undefined); }, 60000); @@ -65,15 +60,14 @@ suite('LssClient (integration, built lib)', () => { }); it('reports healthy via health.get() and RUNNING via lifecycle.status()', async () => { - expect((await lss.health.get()).localstack).toBe(true); + expect((await lss.health.get()).engineRunning).toBe(true); expect((await lss.lifecycle.status()).running).toBe(true); }); - it('exposes the isolated config snapshot (no token leak)', async () => { - const cfg = (await lss.config.get()) as { serverPort: number; localstack: { port: number } }; + it('exposes the isolated config snapshot', async () => { + const cfg = (await lss.config.get()) as { serverPort: number; engine: { kind: string; endpoint: string } }; expect(cfg.serverPort).toBe(3398); - expect(cfg.localstack.port).toBe(4598); - expect(JSON.stringify(cfg)).not.toContain(process.env.LOCALSTACK_AUTH_TOKEN); + expect(cfg.engine).toEqual({ kind: 'self', endpoint: 'http://localhost:14598' }); }); it('returns a non-empty log tail via lifecycle.logs()', async () => { diff --git a/tests/integration/features.test.ts b/tests/integration/features.test.ts index 8f894df..48250b5 100644 --- a/tests/integration/features.test.ts +++ b/tests/integration/features.test.ts @@ -1,12 +1,11 @@ // End-to-end validation of LSS's promised features (see docs/FEATURES.md). -// Boots an ISOLATED LSS + LocalStack instance (own ports + stateDir, managed -// mode, token from LOCALSTACK_AUTH_TOKEN), provisions the fixture service -// (tests/integration/fixtures/sample-microservice), and asserts each capability -// against the live HTTP API. +// Boots an ISOLATED LSS instance on the self engine (own ports + stateDir), +// provisions the fixture service (tests/integration/fixtures/sample-microservice), +// and asserts each capability against the live HTTP API. // -// Requires Docker + a LOCALSTACK_AUTH_TOKEN (community images >= 2026.5 need it). -// The whole suite is skipped when no token is present, so it never fails a -// token-less local run or a CI job without the secret. +// No Docker, no auth token, nothing to gate on: the engine runs in the +// orchestrator process, so this suite executes on every machine and in every CI +// job. That is the point of v2. import { exec } from 'child_process'; import { promisify } from 'util'; import path from 'path'; @@ -22,8 +21,7 @@ const STATE_PID = path.join(REPO_ROOT, 'tests/.lss-integration/orchestrator.pid' const QUEUE = 'sample-microservice-OrderProcessing'; const BUCKET = 'sample-microservice-uploads'; -const HAS_TOKEN = Boolean(process.env.LOCALSTACK_AUTH_TOKEN); -const suite = HAS_TOKEN ? describe : describe.skip; +const suite = describe; function cli(args: string) { return execAsync(`node bin/cli.js ${args}`, { cwd: REPO_ROOT, env: process.env }); @@ -55,38 +53,33 @@ async function waitFor(cond: () => Promise, timeoutMs: number, interval suite('LSS promised features (integration)', () => { beforeAll(async () => { - if (!HAS_TOKEN) return; await cli(`stop --config ${CONFIG}`).catch(() => undefined); await cli(`start --config ${CONFIG}`); - // Wait for the orchestrator + LocalStack to come up. + // Wait for the orchestrator to come up (self engine boots in milliseconds). await waitFor(async () => { const res = await fetch(`${BASE}/api/health`); const j = await res.json(); - return j.localstack === true; - }, 150000); + return j.engineRunning === true; + }, 60000, 250); // Register the fixture service — provisioning runs within the request. const reg = await api('POST', '/api/services/register', { servicePath: SERVICE_PATH, invokePort: 3998 }); expect(reg.status).toBe(200); }, 240000); afterAll(async () => { - if (!HAS_TOKEN) return; await cli(`stop --config ${CONFIG}`).catch(() => undefined); - // Remove the main LocalStack container AND any Lambda child containers it spawned - // (named lss-localstack-4599-lambda-…), plus the scoped volume. - await execAsync('docker rm -f $(docker ps -aq --filter name=lss-localstack-4599) 2>/dev/null || true').catch(() => undefined); - await execAsync('docker volume rm lss-localstack-4599-data 2>/dev/null || true').catch(() => undefined); + // Nothing to reap but the state dir: no container, no volume, no image. await execAsync('rm -rf tests/.lss-integration 2>/dev/null || true').catch(() => undefined); }, 60000); describe('config & isolation', () => { - it('exposes the isolated instance config (no token leak)', async () => { + it('exposes the isolated instance config', async () => { const { status, data } = await api('GET', '/api/config'); expect(status).toBe(200); expect(data.serverPort).toBe(3399); - expect(data.localstack.port).toBe(4599); + expect(data.engine.kind).toBe('self'); + expect(data.engine.endpoint).toBe('http://localhost:14599'); expect(data.configPath).toContain('lss.integration.config.json'); - expect(JSON.stringify(data)).not.toContain(process.env.LOCALSTACK_AUTH_TOKEN); }); it('keeps PID/log under the stateDir, not /tmp', () => { diff --git a/examples/localstack-free/gateway-stack/package.json b/tests/integration/fixtures/apigw-raw/gateway-stack/package.json similarity index 100% rename from examples/localstack-free/gateway-stack/package.json rename to tests/integration/fixtures/apigw-raw/gateway-stack/package.json diff --git a/examples/localstack-free/gateway-stack/serverless.yml b/tests/integration/fixtures/apigw-raw/gateway-stack/serverless.yml similarity index 99% rename from examples/localstack-free/gateway-stack/serverless.yml rename to tests/integration/fixtures/apigw-raw/gateway-stack/serverless.yml index 7f54740..34b9186 100644 --- a/examples/localstack-free/gateway-stack/serverless.yml +++ b/tests/integration/fixtures/apigw-raw/gateway-stack/serverless.yml @@ -32,7 +32,7 @@ custom: accountId: '000000000000' orchestrator: enabled: true - orchestratorUrl: http://localhost:3120 + orchestratorUrl: http://localhost:3397 lss: apiPort: 3613 invokePort: 13613 diff --git a/tests/integration/fixtures/apigw-raw/lss.config.json b/tests/integration/fixtures/apigw-raw/lss.config.json new file mode 100644 index 0000000..27e877b --- /dev/null +++ b/tests/integration/fixtures/apigw-raw/lss.config.json @@ -0,0 +1,11 @@ +{ + "serverPort": 3397, + "engine": "self", + "selfEngine": { "port": 14572 }, + "stateDir": "tests/.lss-apigw-integration", + "persistence": false, + "region": "sa-east-1", + "autoPackage": true, + "packageCommand": "npx serverless package", + "packageTimeoutMs": 300000 +} diff --git a/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-create-stack.json b/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-create-stack.json new file mode 100644 index 0000000..85ca881 --- /dev/null +++ b/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-create-stack.json @@ -0,0 +1,82 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "The AWS CloudFormation template for this Serverless application", + "Resources": { + "ServerlessDeploymentBucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + } + }, + "ServerlessDeploymentBucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Effect": "Deny", + "Principal": "*", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + } + ] + ] + } + ], + "Condition": { + "Bool": { + "aws:SecureTransport": false + } + } + } + ] + } + } + } + }, + "Outputs": { + "ServerlessDeploymentBucketName": { + "Value": { + "Ref": "ServerlessDeploymentBucket" + } + } + } +} \ No newline at end of file diff --git a/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-update-stack.json b/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-update-stack.json new file mode 100644 index 0000000..0f5b279 --- /dev/null +++ b/tests/integration/fixtures/apigw-raw/users-service/.serverless/cloudformation-template-update-stack.json @@ -0,0 +1,905 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "The AWS CloudFormation template for this Serverless application", + "Resources": { + "ServerlessDeploymentBucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + } + }, + "ServerlessDeploymentBucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Effect": "Deny", + "Principal": "*", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + } + ] + ] + } + ], + "Condition": { + "Bool": { + "aws:SecureTransport": false + } + } + } + ] + } + } + }, + "SessionAuthorizerV2LocalLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-sessionAuthorizerV2Local" + } + }, + "ListUsersLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-listUsers" + } + }, + "CreateUserLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-createUser" + } + }, + "GetUserLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-getUser" + } + }, + "IamRoleLambdaExecution": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Policies": [ + { + "PolicyName": { + "Fn::Join": [ + "-", + [ + "users-service", + "dev", + "lambda" + ] + ] + }, + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogStream", + "logs:CreateLogGroup", + "logs:TagResource" + ], + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/users-service-dev*:*" + } + ] + }, + { + "Effect": "Allow", + "Action": [ + "logs:PutLogEvents" + ], + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/users-service-dev*:*:*" + } + ] + } + ] + } + } + ], + "Path": "/", + "RoleName": { + "Fn::Join": [ + "-", + [ + "users-service", + "dev", + { + "Ref": "AWS::Region" + }, + "lambdaRole" + ] + ] + } + } + }, + "SessionAuthorizerV2LocalLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/session-authorizer-v2.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-sessionAuthorizerV2Local", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "SessionAuthorizerV2LocalLogGroup" + ] + }, + "ListUsersLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/listUsers.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-listUsers", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "ListUsersLogGroup" + ] + }, + "CreateUserLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/createUser.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-createUser", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "CreateUserLogGroup" + ] + }, + "GetUserLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/getUser.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-getUser", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "GetUserLogGroup" + ] + }, + "SessionAuthorizerV2LocalLambdaVersionXh5eIlcqIDemHeeNRXOawlrJktoeZillFv7xjj8": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "SessionAuthorizerV2LocalLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "ListUsersLambdaVersion8a6gaNEdPeZkKQmkUjDmsIVSOfD9RUhJ6A9SB1eyvA": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "ListUsersLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "GetUserLambdaVersionKkjIhfFQsoDWCLcwsLsWlMcfzVeSN0jfvHJrcxG0": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "GetUserLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "CreateUserLambdaVersionlvQnAcvOoUVQ6eAW9hi1DyaPdYsB3Rk9tOtxaQBT6g": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "CreateUserLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "HttpApi": { + "Type": "AWS::ApiGatewayV2::Api", + "Properties": { + "Name": "dev-users-service", + "ProtocolType": "HTTP", + "CorsConfiguration": { + "AllowHeaders": [ + "Content-Type", + "X-Amz-Date", + "Authorization", + "X-Api-Key", + "X-Amz-Security-Token", + "X-Amz-User-Agent", + "X-Amzn-Trace-Id" + ], + "AllowMethods": [ + "OPTIONS", + "GET", + "POST" + ], + "AllowOrigins": [ + "*" + ] + } + } + }, + "HttpApiStage": { + "Type": "AWS::ApiGatewayV2::Stage", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "StageName": "$default", + "AutoDeploy": true, + "DefaultRouteSettings": { + "DetailedMetricsEnabled": false + } + } + }, + "SessionAuthorizerV2LambdaAuthorizerPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "SessionAuthorizerV2LocalLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiAuthorizerSessionAuthorizerV2": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "Name": "sessionAuthorizerV2", + "IdentitySource": [ + "$request.header.authorization" + ], + "AuthorizerType": "REQUEST", + "EnableSimpleResponses": true, + "AuthorizerResultTtlInSeconds": 3600, + "AuthorizerPayloadFormatVersion": "2.0", + "AuthorizerUri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "SessionAuthorizerV2LocalLambdaFunction", + "Arn" + ] + }, + "/invocations" + ] + ] + } + } + }, + "ListUsersLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "ListUsersLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationListUsers": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "ListUsersLambdaFunction", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRouteGetUsers": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /users", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationListUsers" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationListUsers" + }, + "CreateUserLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "CreateUserLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationCreateUser": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "CreateUserLambdaFunction", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRoutePostUsers": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "POST /users", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationCreateUser" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationCreateUser" + }, + "GetUserLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "GetUserLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationGetUser": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "Fn::GetAtt": [ + "GetUserLambdaFunction", + "Arn" + ] + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRouteGetUsersIdVar": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /users/{id}", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationGetUser" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationGetUser" + }, + "UsersTable": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "TableName": "users-Users", + "BillingMode": "PAY_PER_REQUEST", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + } + }, + "SpacesIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ListUsersLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesWriteIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CreateUserLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesGetRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "SpacesPostRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "POST /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesWriteIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "IdentitySpacesAuthorizer": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "Name": "identitySpacesAuthorizer", + "AuthorizerType": "REQUEST", + "AuthorizerPayloadFormatVersion": "2.0", + "EnableSimpleResponses": true, + "AuthorizerResultTtlInSeconds": 3600, + "IdentitySource": [ + "$request.header.authorization" + ], + "AuthorizerUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SessionAuthorizerV2LocalLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "ListUsersLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + }, + "SpacesWriteInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "CreateUserLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + } + }, + "Outputs": { + "ServerlessDeploymentBucketName": { + "Value": { + "Ref": "ServerlessDeploymentBucket" + }, + "Export": { + "Name": "sls-users-service-dev-ServerlessDeploymentBucketName" + } + }, + "SessionAuthorizerV2LocalLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "SessionAuthorizerV2LocalLambdaVersionXh5eIlcqIDemHeeNRXOawlrJktoeZillFv7xjj8" + }, + "Export": { + "Name": "sls-users-service-dev-SessionAuthorizerV2LocalLambdaFunctionQualifiedArn" + } + }, + "ListUsersLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "ListUsersLambdaVersion8a6gaNEdPeZkKQmkUjDmsIVSOfD9RUhJ6A9SB1eyvA" + }, + "Export": { + "Name": "sls-users-service-dev-ListUsersLambdaFunctionQualifiedArn" + } + }, + "GetUserLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "GetUserLambdaVersionKkjIhfFQsoDWCLcwsLsWlMcfzVeSN0jfvHJrcxG0" + }, + "Export": { + "Name": "sls-users-service-dev-GetUserLambdaFunctionQualifiedArn" + } + }, + "CreateUserLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "CreateUserLambdaVersionlvQnAcvOoUVQ6eAW9hi1DyaPdYsB3Rk9tOtxaQBT6g" + }, + "Export": { + "Name": "sls-users-service-dev-CreateUserLambdaFunctionQualifiedArn" + } + }, + "HttpApiId": { + "Description": "Id of the HTTP API", + "Value": { + "Ref": "HttpApi" + }, + "Export": { + "Name": "sls-users-service-dev-HttpApiId" + } + }, + "HttpApiUrl": { + "Description": "URL of the HTTP API", + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "HttpApi" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Export": { + "Name": "sls-users-service-dev-HttpApiUrl" + } + } + } +} \ No newline at end of file diff --git a/tests/integration/fixtures/apigw-raw/users-service/.serverless/serverless-state.json b/tests/integration/fixtures/apigw-raw/users-service/.serverless/serverless-state.json new file mode 100644 index 0000000..8dfaff0 --- /dev/null +++ b/tests/integration/fixtures/apigw-raw/users-service/.serverless/serverless-state.json @@ -0,0 +1,1272 @@ +{ + "service": { + "service": "users-service", + "serviceObject": { + "name": "users-service" + }, + "provider": { + "name": "aws", + "runtime": "nodejs20.x", + "region": "sa-east-1", + "stage": "dev", + "environment": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + }, + "httpApi": { + "cors": true, + "authorizers": { + "sessionAuthorizerV2": { + "type": "request", + "functionName": "sessionAuthorizerV2Local", + "identitySource": "$request.header.authorization", + "resultTtlInSeconds": 3600, + "enableSimpleResponses": true, + "payloadVersion": "2.0" + } + } + }, + "versionFunctions": true, + "compiledCloudFormationTemplate": { + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "The AWS CloudFormation template for this Serverless application", + "Resources": { + "ServerlessDeploymentBucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + } + }, + "ServerlessDeploymentBucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Effect": "Deny", + "Principal": "*", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + } + ] + ] + } + ], + "Condition": { + "Bool": { + "aws:SecureTransport": false + } + } + } + ] + } + } + }, + "SessionAuthorizerV2LocalLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-sessionAuthorizerV2Local" + } + }, + "ListUsersLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-listUsers" + } + }, + "CreateUserLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-createUser" + } + }, + "GetUserLogGroup": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": "/aws/lambda/users-service-dev-getUser" + } + }, + "IamRoleLambdaExecution": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Policies": [ + { + "PolicyName": { + "Fn::Join": [ + "-", + [ + "users-service", + "dev", + "lambda" + ] + ] + }, + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogStream", + "logs:CreateLogGroup", + "logs:TagResource" + ], + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/users-service-dev*:*" + } + ] + }, + { + "Effect": "Allow", + "Action": [ + "logs:PutLogEvents" + ], + "Resource": [ + { + "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/users-service-dev*:*:*" + } + ] + } + ] + } + } + ], + "Path": "/", + "RoleName": { + "Fn::Join": [ + "-", + [ + "users-service", + "dev", + { + "Ref": "AWS::Region" + }, + "lambdaRole" + ] + ] + } + } + }, + "SessionAuthorizerV2LocalLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/session-authorizer-v2.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-sessionAuthorizerV2Local", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "SessionAuthorizerV2LocalLogGroup" + ] + }, + "ListUsersLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/listUsers.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-listUsers", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "ListUsersLogGroup" + ] + }, + "CreateUserLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/createUser.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-createUser", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "CreateUserLogGroup" + ] + }, + "GetUserLambdaFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "S3Key": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z/users-service.zip" + }, + "Handler": "src/handlers/getUser.handler", + "Runtime": "nodejs20.x", + "FunctionName": "users-service-dev-getUser", + "MemorySize": 1024, + "Timeout": 6, + "Environment": { + "Variables": { + "USERS_TABLE": "users-Users", + "SESSION_SECRET": "lss-secret", + "EVENT_BUS_NAME": "domain-events", + "AWS_ENDPOINT": "http://localhost:4572" + } + }, + "Role": { + "Fn::GetAtt": [ + "IamRoleLambdaExecution", + "Arn" + ] + } + }, + "DependsOn": [ + "GetUserLogGroup" + ] + }, + "SessionAuthorizerV2LocalLambdaVersionXh5eIlcqIDemHeeNRXOawlrJktoeZillFv7xjj8": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "SessionAuthorizerV2LocalLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "ListUsersLambdaVersion8a6gaNEdPeZkKQmkUjDmsIVSOfD9RUhJ6A9SB1eyvA": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "ListUsersLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "GetUserLambdaVersionKkjIhfFQsoDWCLcwsLsWlMcfzVeSN0jfvHJrcxG0": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "GetUserLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "CreateUserLambdaVersionlvQnAcvOoUVQ6eAW9hi1DyaPdYsB3Rk9tOtxaQBT6g": { + "Type": "AWS::Lambda::Version", + "DeletionPolicy": "Retain", + "Properties": { + "FunctionName": { + "Ref": "CreateUserLambdaFunction" + }, + "CodeSha256": "9HjNUJcOipmzsUFVli79zryxnpiRIFKla+EUnBqsaD0=" + } + }, + "HttpApi": { + "Type": "AWS::ApiGatewayV2::Api", + "Properties": { + "Name": "dev-users-service", + "ProtocolType": "HTTP", + "CorsConfiguration": { + "AllowHeaders": [ + "Content-Type", + "X-Amz-Date", + "Authorization", + "X-Api-Key", + "X-Amz-Security-Token", + "X-Amz-User-Agent", + "X-Amzn-Trace-Id" + ], + "AllowMethods": [ + "OPTIONS", + "GET", + "POST" + ], + "AllowOrigins": [ + "*" + ] + } + } + }, + "HttpApiStage": { + "Type": "AWS::ApiGatewayV2::Stage", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "StageName": "$default", + "AutoDeploy": true, + "DefaultRouteSettings": { + "DetailedMetricsEnabled": false + } + } + }, + "SessionAuthorizerV2LambdaAuthorizerPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "SessionAuthorizerV2LocalLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiAuthorizerSessionAuthorizerV2": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "Name": "sessionAuthorizerV2", + "IdentitySource": [ + "$request.header.authorization" + ], + "AuthorizerType": "REQUEST", + "EnableSimpleResponses": true, + "AuthorizerResultTtlInSeconds": 3600, + "AuthorizerPayloadFormatVersion": "2.0", + "AuthorizerUri": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + { + "Fn::GetAtt": [ + "SessionAuthorizerV2LocalLambdaFunction", + "Arn" + ] + }, + "/invocations" + ] + ] + } + } + }, + "ListUsersLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "ListUsersLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationListUsers": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "$ref": "$[\"service\"][\"provider\"][\"compiledCloudFormationTemplate\"][\"Resources\"][\"ListUsersLambdaPermissionHttpApi\"][\"Properties\"][\"FunctionName\"]" + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRouteGetUsers": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /users", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationListUsers" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationListUsers" + }, + "CreateUserLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "CreateUserLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationCreateUser": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "$ref": "$[\"service\"][\"provider\"][\"compiledCloudFormationTemplate\"][\"Resources\"][\"CreateUserLambdaPermissionHttpApi\"][\"Properties\"][\"FunctionName\"]" + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRoutePostUsers": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "POST /users", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationCreateUser" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationCreateUser" + }, + "GetUserLambdaPermissionHttpApi": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Fn::GetAtt": [ + "GetUserLambdaFunction", + "Arn" + ] + }, + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "HttpApi" + }, + "/*" + ] + ] + } + } + }, + "HttpApiIntegrationGetUser": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "IntegrationUri": { + "$ref": "$[\"service\"][\"provider\"][\"compiledCloudFormationTemplate\"][\"Resources\"][\"GetUserLambdaPermissionHttpApi\"][\"Properties\"][\"FunctionName\"]" + }, + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000 + } + }, + "HttpApiRouteGetUsersIdVar": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /users/{id}", + "Target": { + "Fn::Join": [ + "/", + [ + "integrations", + { + "Ref": "HttpApiIntegrationGetUser" + } + ] + ] + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "HttpApiAuthorizerSessionAuthorizerV2" + } + }, + "DependsOn": "HttpApiIntegrationGetUser" + }, + "UsersTable": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "TableName": "users-Users", + "BillingMode": "PAY_PER_REQUEST", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + } + }, + "SpacesIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ListUsersLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesWriteIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CreateUserLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesGetRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "SpacesPostRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "POST /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesWriteIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "IdentitySpacesAuthorizer": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "Name": "identitySpacesAuthorizer", + "AuthorizerType": "REQUEST", + "AuthorizerPayloadFormatVersion": "2.0", + "EnableSimpleResponses": true, + "AuthorizerResultTtlInSeconds": 3600, + "IdentitySource": [ + "$request.header.authorization" + ], + "AuthorizerUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SessionAuthorizerV2LocalLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "ListUsersLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + }, + "SpacesWriteInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "CreateUserLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + } + }, + "Outputs": { + "ServerlessDeploymentBucketName": { + "Value": { + "Ref": "ServerlessDeploymentBucket" + }, + "Export": { + "Name": "sls-users-service-dev-ServerlessDeploymentBucketName" + } + }, + "SessionAuthorizerV2LocalLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "SessionAuthorizerV2LocalLambdaVersionXh5eIlcqIDemHeeNRXOawlrJktoeZillFv7xjj8" + }, + "Export": { + "Name": "sls-users-service-dev-SessionAuthorizerV2LocalLambdaFunctionQualifiedArn" + } + }, + "ListUsersLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "ListUsersLambdaVersion8a6gaNEdPeZkKQmkUjDmsIVSOfD9RUhJ6A9SB1eyvA" + }, + "Export": { + "Name": "sls-users-service-dev-ListUsersLambdaFunctionQualifiedArn" + } + }, + "GetUserLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "GetUserLambdaVersionKkjIhfFQsoDWCLcwsLsWlMcfzVeSN0jfvHJrcxG0" + }, + "Export": { + "Name": "sls-users-service-dev-GetUserLambdaFunctionQualifiedArn" + } + }, + "CreateUserLambdaFunctionQualifiedArn": { + "Description": "Current Lambda function version", + "Value": { + "Ref": "CreateUserLambdaVersionlvQnAcvOoUVQ6eAW9hi1DyaPdYsB3Rk9tOtxaQBT6g" + }, + "Export": { + "Name": "sls-users-service-dev-CreateUserLambdaFunctionQualifiedArn" + } + }, + "HttpApiId": { + "Description": "Id of the HTTP API", + "Value": { + "Ref": "HttpApi" + }, + "Export": { + "Name": "sls-users-service-dev-HttpApiId" + } + }, + "HttpApiUrl": { + "Description": "URL of the HTTP API", + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "HttpApi" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + } + ] + ] + }, + "Export": { + "Name": "sls-users-service-dev-HttpApiUrl" + } + } + } + }, + "coreCloudFormationTemplate": { + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "The AWS CloudFormation template for this Serverless application", + "Resources": { + "ServerlessDeploymentBucket": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + } + } + }, + "ServerlessDeploymentBucketPolicy": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "ServerlessDeploymentBucket" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Effect": "Deny", + "Principal": "*", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + }, + "/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":s3:::", + { + "Ref": "ServerlessDeploymentBucket" + } + ] + ] + } + ], + "Condition": { + "Bool": { + "aws:SecureTransport": false + } + } + } + ] + } + } + } + }, + "Outputs": { + "ServerlessDeploymentBucketName": { + "Value": { + "Ref": "ServerlessDeploymentBucket" + } + } + } + }, + "vpc": {} + }, + "custom": { + "orchestrator": { + "enabled": true, + "orchestratorUrl": "http://localhost:3120" + }, + "lss": { + "apiPort": 3610, + "invokePort": 13610 + } + }, + "plugins": [ + "serverless-lss" + ], + "pluginsData": {}, + "functions": { + "sessionAuthorizerV2Local": { + "handler": "src/handlers/session-authorizer-v2.handler", + "events": [], + "name": "users-service-dev-sessionAuthorizerV2Local", + "package": {}, + "memory": 1024, + "timeout": 6, + "runtime": "nodejs20.x", + "vpc": {}, + "versionLogicalId": "SessionAuthorizerV2LocalLambdaVersionXh5eIlcqIDemHeeNRXOawlrJktoeZillFv7xjj8" + }, + "listUsers": { + "handler": "src/handlers/listUsers.handler", + "events": [ + { + "httpApi": { + "path": "/users", + "method": "get", + "authorizer": { + "name": "sessionAuthorizerV2" + } + }, + "resolvedMethod": "GET", + "resolvedPath": "/users" + } + ], + "name": "users-service-dev-listUsers", + "package": {}, + "memory": 1024, + "timeout": 6, + "runtime": "nodejs20.x", + "vpc": {}, + "versionLogicalId": "ListUsersLambdaVersion8a6gaNEdPeZkKQmkUjDmsIVSOfD9RUhJ6A9SB1eyvA" + }, + "createUser": { + "handler": "src/handlers/createUser.handler", + "events": [ + { + "httpApi": { + "path": "/users", + "method": "post", + "authorizer": { + "name": "sessionAuthorizerV2" + } + }, + "resolvedMethod": "POST", + "resolvedPath": "/users" + } + ], + "name": "users-service-dev-createUser", + "package": {}, + "memory": 1024, + "timeout": 6, + "runtime": "nodejs20.x", + "vpc": {}, + "versionLogicalId": "CreateUserLambdaVersionlvQnAcvOoUVQ6eAW9hi1DyaPdYsB3Rk9tOtxaQBT6g" + }, + "getUser": { + "handler": "src/handlers/getUser.handler", + "events": [ + { + "httpApi": { + "path": "/users/{id}", + "method": "get", + "authorizer": { + "name": "sessionAuthorizerV2" + } + }, + "resolvedMethod": "GET", + "resolvedPath": "/users/{id}" + } + ], + "name": "users-service-dev-getUser", + "package": {}, + "memory": 1024, + "timeout": 6, + "runtime": "nodejs20.x", + "vpc": {}, + "versionLogicalId": "GetUserLambdaVersionKkjIhfFQsoDWCLcwsLsWlMcfzVeSN0jfvHJrcxG0" + } + }, + "resources": { + "Resources": { + "UsersTable": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "TableName": "users-Users", + "BillingMode": "PAY_PER_REQUEST", + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ] + } + }, + "SpacesIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ListUsersLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesWriteIntegration": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "IntegrationType": "AWS_PROXY", + "PayloadFormatVersion": "2.0", + "TimeoutInMillis": 30000, + "IntegrationUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CreateUserLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesGetRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "GET /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "SpacesPostRoute": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "RouteKey": "POST /api/identity/spaces", + "Target": { + "Fn::Sub": "integrations/${SpacesWriteIntegration}" + }, + "AuthorizationType": "CUSTOM", + "AuthorizerId": { + "Ref": "IdentitySpacesAuthorizer" + } + } + }, + "IdentitySpacesAuthorizer": { + "Type": "AWS::ApiGatewayV2::Authorizer", + "Properties": { + "ApiId": { + "Ref": "HttpApi" + }, + "Name": "identitySpacesAuthorizer", + "AuthorizerType": "REQUEST", + "AuthorizerPayloadFormatVersion": "2.0", + "EnableSimpleResponses": true, + "AuthorizerResultTtlInSeconds": 3600, + "IdentitySource": [ + "$request.header.authorization" + ], + "AuthorizerUri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SessionAuthorizerV2LocalLambdaFunction.Arn}/invocations" + } + } + }, + "SpacesInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "ListUsersLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + }, + "SpacesWriteInvokePermission": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { + "Ref": "CreateUserLambdaFunction" + }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*" + } + } + } + }, + "Outputs": {} + }, + "configValidationMode": "error", + "serviceFilename": "serverless.yml", + "initialServerlessConfig": { + "service": "users-service", + "frameworkVersion": ">=3", + "provider": { + "$ref": "$[\"service\"][\"provider\"]" + }, + "plugins": { + "$ref": "$[\"service\"][\"plugins\"]" + }, + "custom": { + "$ref": "$[\"service\"][\"custom\"]" + }, + "functions": { + "$ref": "$[\"service\"][\"functions\"]" + }, + "resources": { + "$ref": "$[\"service\"][\"resources\"]" + }, + "package": { + "individually": false, + "artifactsS3KeyDirname": "serverless/users-service/dev/code-artifacts", + "artifact": "/workspaces/local-serverless-stack/examples/localstack-free/users-service/.serverless/users-service.zip", + "artifactDirectoryName": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z" + } + }, + "layers": {}, + "artifact": "/workspaces/local-serverless-stack/examples/localstack-free/users-service/.serverless/users-service.zip" + }, + "package": { + "individually": false, + "artifactDirectoryName": "serverless/users-service/dev/1784393000924-2026-07-18T16:43:20.924Z", + "artifact": "users-service.zip" + } +} \ No newline at end of file diff --git a/tests/integration/fixtures/apigw-raw/users-service/.serverless/users-service.zip b/tests/integration/fixtures/apigw-raw/users-service/.serverless/users-service.zip new file mode 100644 index 0000000000000000000000000000000000000000..212d6dc8f1f560981e3d2ec24aa22f20b07f15b5 GIT binary patch literal 2971801 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ξ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

cu>wvOYcL>L96l!7 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�sX)NPYcsy}ZBv3QZ%Ki*86G%Nj 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 z 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�w+P|cOlLt{Ry1vz- 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

#mBu+<|WL*^;v0<`sMjZm5v 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