Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
ebcc5ba
feat: Refactor engine handling and improve UI messaging
Viserion77 Jul 30, 2026
dee4ee8
feat(mcp): add TypeScript configuration and initial server implementa…
Viserion77 Jul 31, 2026
c70b040
Refactor tests to replace LocalStackManager with EngineManager
Viserion77 Jul 31, 2026
d6c8577
refactor: unify server and self-engine ports to 14566
Viserion77 Jul 31, 2026
6dda981
refactor: remove serverless-lss plugin references and update service …
Viserion77 Jul 31, 2026
a02f74b
feat: add install and package endpoints for service management
Viserion77 Jul 31, 2026
22e9381
feat(i18n): integrate localization into ServiceDetailPage and Setting…
Viserion77 Jul 31, 2026
8f74e94
feat(i18n): integrate internationalization into DynamoTableSettings a…
Viserion77 Jul 31, 2026
d697293
refactor: enhance scan warnings with structured messages and localiza…
Viserion77 Jul 31, 2026
b9906c4
feat: add Overview activity panel to monitor Lambda runtime load
Viserion77 Jul 31, 2026
6c77b98
feat: integrate AWS service icons into the UI
Viserion77 Jul 31, 2026
0abd230
chore: update fast-uri package to version 3.1.4 across multiple services
Viserion77 Jul 31, 2026
b721c4b
feat: update versioning and description for LSS v2 migration
Viserion77 Jul 31, 2026
1280e31
fix: update release documentation and dependencies
Viserion77 Jul 31, 2026
528d36a
refactor: update documentation and comments to reflect version change…
Viserion77 Jul 31, 2026
49e35ec
Add unit tests for bind-host service and enhance config-manager tests
Viserion77 Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
{
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:4": {
"version": "4.0.0",
"resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:4fa87399214366e320d489991769c4f3f461e1ffe461f54eea78a41b34945bb5",
"integrity": "sha256:4fa87399214366e320d489991769c4f3f461e1ffe461f54eea78a41b34945bb5"
}
}
"features": {}
}
67 changes: 21 additions & 46 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,33 @@
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:4": {},
},
"runArgs": [
"--net=host"
],
// REGRA: com --net=host todos os devcontainers da máquina compartilham a rede
// do host — porta nova aqui deve evitar faixas já usadas por outros containers.
// Convenção DESTE repo: gateways dos exemplos 36xx (invoke = apiPort + 10000
// → 136xx), serverless-offline 3002-3003, dashboards dos exemplos 31xx,
// consoles de validação dos exemplos 8620-8622, LocalStack 4567/4571-4572,
// self engine 14566. Os defaults de produto (3100/4566/8000) continuam no
// código, mas o dev neste container usa os overrides do lss.config.json da
// raiz (3101/4567/8001) — por isso os defaults não são forwardados aqui.
// No features: nothing in this repo shells out to Docker — not the
// orchestrator, not the engine, not the test suites (`npm run
// test:integration` boots a real stack in-process).
//
// 14566 LSS — dashboard, REST API and AWS wire, all one listener
// 3101 Vite dev server for the dashboard (dev only)
// 8001 DynamoDB proxy (opt-in via enableDynamoProxy)
// 36xx per-service HTTP APIs · 136xx their invoke listeners
// 8622 validation console of examples/self-hosted (npm run console)
"forwardPorts": [
// Core (dev deste repo)
3101, // Dashboard/API (lss.config.json raiz) e UI Vite dev
14566, // Self engine (AWS wire)
4567, // LocalStack (lss.config.json raiz)
8001, // Proxy DynamoDB (lss.config.json raiz, opt-in)
// serverless-offline (localstack-ultimate)
3002, 3003,
// Lambda API por serviço (exemplos)
3610, 3611, 3612, // localstack-free
3631, 3632, 3633, 3634, // self-hosted
// Lambda Invoke por serviço (apiPort + 10000)
13610, 13611, 13612, // localstack-free
13631, 13632, 13633, 13634, // self-hosted
// Dashboards dos exemplos (serverPort de cada lss.config.json)
3111, 3120, 3140,
// Consoles de validação dos exemplos (npm run console)
8620, 8621, 8622,
// LocalStack dos exemplos
4571, 4572
14566,
3101,
8001,
3631, 3632, 3633, 3634,
13631, 13632, 13633, 13634,
8622
],
"portsAttributes": {
"3101": { "label": "LSS Dashboard/API (dev) / UI Vite" },
"14566": { "label": "Self Engine (AWS wire)" },
"4567": { "label": "LocalStack (config raiz)" },
"8001": { "label": "DynamoDB Proxy (config raiz)" },
"3002-3003": { "label": "serverless-offline (localstack-ultimate)" },
"3610-3612": { "label": "Lambda API (localstack-free)" },
"3631-3634": { "label": "Lambda API (self-hosted)" },
"13610-13612": { "label": "Lambda Invoke (localstack-free)" },
"13631-13634": { "label": "Lambda Invoke (self-hosted)" },
"3111": { "label": "LSS Dashboard (localstack-ultimate)" },
"3120": { "label": "LSS Dashboard (localstack-free)" },
"3140": { "label": "LSS Dashboard (self-hosted)" },
"8620": { "label": "Console de validação (localstack-free)" },
"8621": { "label": "Console de validação (localstack-ultimate)" },
"8622": { "label": "Console de validação (self-hosted)" },
"4571-4572": { "label": "LocalStack (exemplos)" }
"14566": { "label": "LSS (dashboard + API + AWS wire)" },
"3101": { "label": "UI Vite dev server" },
"8001": { "label": "DynamoDB Proxy (opt-in)" },
"3631-3634": { "label": "Lambda API (example self-hosted)" },
"13631-13634": { "label": "Lambda Invoke (example self-hosted)" },
"8622": { "label": "Validation console (example self-hosted)" }
}
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
Expand Down
180 changes: 180 additions & 0 deletions .github/workflows/pr-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
name: PR Preview Release

# Publishes every push on a pull request to npm under a per-PR dist-tag, so a
# reviewer can install the branch instead of building it. The version is the
# manifest version plus the PR number and the run number
# (1.0.0 -> 1.0.0-pr.42.17), which is a semver PRERELEASE: it sorts BELOW the
# real 1.0.0 and no default range (`^1.0.0`) will ever resolve to it.
#
# `latest` is never touched. `npm publish` writes the `latest` dist-tag unless
# `--tag` is given, and it does NOT infer a different tag from a prerelease
# version string — the explicit `--tag` below is the only thing keeping a
# preview out of `npm i local-serverless-stack`.
#
# NOT `pull_request_target`, deliberately. That trigger runs the BASE repo's
# workflow with access to secrets while checking out PR code, which would hand
# NPM_TOKEN to anyone who can open a pull request. With plain `pull_request`,
# GitHub withholds secrets from fork PRs — so the fork case is gated explicitly
# below and skips with a clear reason instead of failing on a missing token.

# `labeled`/`unlabeled` are in the list because the `publish-preview` label is
# what gates this workflow: without them, applying the label would sit there
# doing nothing until someone happened to push again.
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled, closed]

# One preview in flight per PR. Each run composes a unique version, so
# cancelling a superseded run only means that version never lands.
concurrency:
group: pr-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

jobs:
publish:
name: Publish preview to npm
# Two gates:
# - Same-repo branches only: a fork PR has no NPM_TOKEN by design.
# - The `publish-preview` label. Opt-in rather than every-push, because npm
# versions are PERMANENT — `npm unpublish` is restricted to the first 72
# hours, so a 30-push PR would otherwise leave 30 versions on the
# package's public list forever.
# The last clause keeps an unrelated label ("bug", "wontfix") from
# triggering a republish: on a `labeled` event, only the label we care about
# counts. On push/open/reopen the clause is vacuously true.
if: >-
github.event.action != 'closed'
&& github.event.action != 'unlabeled'
&& github.event.pull_request.head.repo.full_name == github.repository
&& contains(github.event.pull_request.labels.*.name, 'publish-preview')
&& (github.event.action != 'labeled' || github.event.label.name == 'publish-preview')
runs-on: ubuntu-latest
steps:
- name: Checkout PR head
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'

- name: Compose the preview version
id: version
run: |
set -euo pipefail
BASE=$(jq -r '.version' package.json)
# Drop any prerelease already on the manifest (1.0.0-rc.1 -> 1.0.0) so
# the suffix cannot stack into 1.0.0-rc.1-pr.42.17, which is a
# different — and confusingly lower — semver ordering.
BASE="${BASE%%-*}"
VERSION="${BASE}-pr.${{ github.event.pull_request.number }}.${{ github.run_number }}"
TAG="pr-${{ github.event.pull_request.number }}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Publishing $VERSION under dist-tag $TAG"

# Before the version is stamped: `npm ci` reconciles package.json against
# the lockfile, and the stamped preview version exists in neither.
- name: Install dependencies
run: npm ci

- name: Stamp the preview version
run: npm pkg set version="${{ steps.version.outputs.version }}"

# `prepublishOnly` builds again on publish; running it here first turns a
# build failure into its own red step instead of burying it in the
# publish log.
- name: Build project
run: npm run build

- name: Publish to npm
run: npm publish --access public --tag "${{ steps.version.outputs.tag }}"
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Comment the published version on the PR
uses: actions/github-script@v7
env:
PREVIEW_VERSION: ${{ steps.version.outputs.version }}
PREVIEW_TAG: ${{ steps.version.outputs.tag }}
with:
script: |
// One sticky comment per PR, edited in place — a comment per push
// would bury the review conversation.
const marker = '<!-- pr-preview-release -->';
const { PREVIEW_VERSION, PREVIEW_TAG } = process.env;
const sha = context.payload.pull_request.head.sha.slice(0, 7);

const body = [
marker,
`📦 **Published \`local-serverless-stack@${PREVIEW_VERSION}\`** for homologation.`,
'',
'```bash',
`npm i local-serverless-stack@${PREVIEW_TAG} # always the newest build of this PR`,
`npm i local-serverless-stack@${PREVIEW_VERSION} # pin this exact build`,
'```',
'',
`Built from ${sha} · dist-tag \`${PREVIEW_TAG}\` · **not** \`latest\`.`,
'The tag is dropped when this PR closes or the `publish-preview` label is removed —',
'the versions themselves stay on npm and remain installable by their exact number.',
].join('\n');

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
per_page: 100,
});
const existing = comments.find((c) => c.body?.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body,
});
}

cleanup:
name: Drop the preview dist-tag
# The label is the switch, so turning it off retires the preview too —
# otherwise `@pr-42` would keep resolving to a build nobody is maintaining.
if: >-
github.event.pull_request.head.repo.full_name == github.repository
&& (
github.event.action == 'closed'
|| (github.event.action == 'unlabeled' && github.event.label.name == 'publish-preview')
)
runs-on: ubuntu-latest
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

# Non-fatal: a PR closed without ever publishing has no tag to remove.
# Removing the tag does not unpublish anything — the versions stay
# installable by their exact number.
- name: Remove the per-PR dist-tag
run: |
npm dist-tag rm local-serverless-stack "pr-${{ github.event.pull_request.number }}" \
|| echo "No dist-tag pr-${{ github.event.pull_request.number }} to remove."
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
70 changes: 0 additions & 70 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ on:
- main
paths:
- 'package.json'
- 'packages/*/package.json'

jobs:
check-version:
name: Check Version Changes
runs-on: ubuntu-latest
outputs:
root-changed: ${{ steps.check-root.outputs.changed }}
plugin-changed: ${{ steps.check-plugin.outputs.changed }}
root-version: ${{ steps.get-root-version.outputs.version }}
plugin-version: ${{ steps.get-plugin-version.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -36,54 +33,13 @@ jobs:
echo "⏭️ Root package version unchanged: $CURRENT"
fi

- name: Check plugin package version change
id: check-plugin
run: |
CURRENT=$(git show HEAD:packages/serverless-plugin/package.json | jq -r '.version')
PREVIOUS=$(git show HEAD~1:packages/serverless-plugin/package.json | jq -r '.version' || echo "0.0.0")
if [ "$CURRENT" != "$PREVIOUS" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "✅ Plugin package version changed: $PREVIOUS -> $CURRENT"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "⏭️ Plugin package version unchanged: $CURRENT"
fi

- name: Get root package version
id: get-root-version
run: |
VERSION=$(jq -r '.version' package.json)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Root version: $VERSION"

- name: Get plugin package version
id: get-plugin-version
run: |
VERSION=$(jq -r '.version' packages/serverless-plugin/package.json)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Plugin version: $VERSION"

# Skip integration tests - require Docker/LocalStack (not available in GitHub Actions)
# Tests are run locally with: npm run test:coverage
# test:
# name: Run Tests
# needs: check-version
# if: needs.check-version.outputs.root-changed == 'true' || needs.check-version.outputs.plugin-changed == 'true'
# runs-on: ubuntu-latest
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# - name: Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: '18'
# - name: Install dependencies
# run: npm ci
# - name: Build project
# run: npm run build
# - name: Run tests
# run: npm test

publish-root:
name: Publish Root Package
needs: check-version
Expand All @@ -109,29 +65,3 @@ jobs:
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

publish-plugin:
name: Publish Plugin Package
needs: check-version
if: needs.check-version.outputs.plugin-changed == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
run: npm ci

- name: Build plugin
run: npm run build -w packages/serverless-plugin

- name: Publish plugin to NPM
run: npm publish -w packages/serverless-plugin --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Loading
Loading