local-serverless-stack 0.0.13 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/README.md +6 -6
- package/bin/cli.js +54 -29
- package/dist/server/index.js +11 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/buckets.d.ts +3 -0
- package/dist/server/routes/buckets.d.ts.map +1 -0
- package/dist/server/routes/buckets.js +128 -0
- package/dist/server/routes/buckets.js.map +1 -0
- package/dist/server/routes/config.d.ts +3 -0
- package/dist/server/routes/config.d.ts.map +1 -0
- package/dist/server/routes/config.js +35 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/queues.d.ts.map +1 -1
- package/dist/server/routes/queues.js +89 -19
- package/dist/server/routes/queues.js.map +1 -1
- package/dist/server/routes/resources.d.ts.map +1 -1
- package/dist/server/routes/resources.js +51 -0
- package/dist/server/routes/resources.js.map +1 -1
- package/dist/server/routes/services.d.ts.map +1 -1
- package/dist/server/routes/services.js +27 -4
- package/dist/server/routes/services.js.map +1 -1
- package/dist/server/services/cloudformation-parser.d.ts +19 -1
- package/dist/server/services/cloudformation-parser.d.ts.map +1 -1
- package/dist/server/services/cloudformation-parser.js +55 -1
- package/dist/server/services/cloudformation-parser.js.map +1 -1
- package/dist/server/services/config-manager.js +1 -1
- package/dist/server/services/config-manager.js.map +1 -1
- package/dist/server/services/localstack-manager.d.ts.map +1 -1
- package/dist/server/services/localstack-manager.js +13 -4
- package/dist/server/services/localstack-manager.js.map +1 -1
- package/dist/server/services/queue-inspector.d.ts +46 -4
- package/dist/server/services/queue-inspector.d.ts.map +1 -1
- package/dist/server/services/queue-inspector.js +126 -22
- package/dist/server/services/queue-inspector.js.map +1 -1
- package/dist/server/services/resource-provisioner.d.ts +12 -1
- package/dist/server/services/resource-provisioner.d.ts.map +1 -1
- package/dist/server/services/resource-provisioner.js +265 -44
- package/dist/server/services/resource-provisioner.js.map +1 -1
- package/dist/server/services/s3-explorer.d.ts +60 -0
- package/dist/server/services/s3-explorer.d.ts.map +1 -0
- package/dist/server/services/s3-explorer.js +170 -0
- package/dist/server/services/s3-explorer.js.map +1 -0
- package/dist/ui/assets/BucketDetailPage-DQU5IfHZ.js +1 -0
- package/dist/ui/assets/BucketsPage-FDb9r2GE.js +1 -0
- package/dist/ui/assets/DynamoPage-D0Q2SOCV.js +1 -0
- package/dist/ui/assets/DynamoTablePage-D2-tvZSS.js +3 -0
- package/dist/ui/assets/OverviewPage-CwLnw4VW.css +1 -0
- package/dist/ui/assets/OverviewPage-DKpsGNi-.js +1 -0
- package/dist/ui/assets/QueueDetailPage-m_Ux1JRb.js +1 -0
- package/dist/ui/assets/QueuesPage-CEfnzK5n.js +1 -0
- package/dist/ui/assets/ServiceDetailPage-DMgYxag6.js +2 -0
- package/dist/ui/assets/ServicesPage-Dl9Md68f.js +2 -0
- package/dist/ui/assets/{index-BZ8sqKTK.css → index-EYnsoJOq.css} +1 -1
- package/dist/ui/assets/index-xSUtPJWt.js +36 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -1
- package/dist/ui/assets/index-iqHgjD5V.js +0 -30
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,103 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.0] - 2026-05-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **S3 bucket support, end-to-end**: LSS now parses `AWS::S3::Bucket` from CloudFormation, provisions buckets in LocalStack, and (when present) wires `NotificationConfiguration.LambdaConfigurations` to a Lambda proxy that forwards into `serverless-offline`. Versioning, `Filter.S3Key.Rules` (prefix/suffix), and multiple lambda configurations per bucket are honored.
|
|
12
|
+
- **New service** `src/server/services/s3-explorer.ts` exposing `listBuckets`, `getBucket`, `listObjects`, `getObject`, `headObject`, `putObject`, `deleteObject`. Per-region client cache mirrors `QueueInspector`/`DynamoExplorer`. Client uses `forcePathStyle: true` so LocalStack receives the bucket name in the URL path rather than as a virtual-host subdomain.
|
|
13
|
+
- **New REST routes** under `/api/buckets`:
|
|
14
|
+
- `GET /api/buckets` — list buckets with enriched metadata (`objectCount`, `totalSize`, `region`, `createdAt`).
|
|
15
|
+
- `GET /api/buckets/:name` — describe a bucket (versioning, notifications count, object/size totals, region).
|
|
16
|
+
- `GET /api/buckets/:name/objects` — list objects with `prefix`, `delimiter`, `maxKeys`, `continuationToken` query params.
|
|
17
|
+
- `GET /api/buckets/:name/objects/content?key=...&download=0|1` — stream an object back. Sets `Content-Type` from the object's stored mime; `?download=1` flips to an attachment disposition. Used by the UI for preview and download.
|
|
18
|
+
- `POST /api/buckets/:name/objects` — upload `{ key, body, contentType?, encoding? }` (encoding `base64` flips the body decoder for binary uploads).
|
|
19
|
+
- `DELETE /api/buckets/:name/objects?key=...` — delete a single object.
|
|
20
|
+
- **New dashboard tab "S3"** in `App.vue` between Queues and DynamoDB.
|
|
21
|
+
- **`/buckets`** — lazy-loaded `BucketsPage.vue` wraps `BucketsView.vue`. Shows three stats (buckets, objects, total size), a service-owner column (links back to `/services/:name`), versioning + notifications counters, and refreshes every 10s.
|
|
22
|
+
- **`/buckets/:name`** — lazy-loaded `BucketDetailPage.vue` wraps `BucketDetail.vue`. Shows the four bucket stats, an **Upload object** card (key, optional content-type, free-form body) that POSTs through `/api/buckets/:name/objects`, and an **Objects** table with prefix filter, per-row open-in-tab preview, download, and delete (behind a confirm).
|
|
23
|
+
- **`@aws-sdk/client-s3`** added to the main package.
|
|
24
|
+
- **`/api/resources`** now returns `{ tables, queues, topics, buckets }` and **`/api/resources/owners`** returns a `buckets` array of `{ name, service }` pairs.
|
|
25
|
+
- **`GET /api/services`** `resourceBreakdown` now includes `buckets` count (rendered as `🪣` chip in `ServicesList.vue`).
|
|
26
|
+
- **Overview page** got a fifth stat column for S3 buckets and the **S3 Buckets** entry in "What's covered" is now `Supported` and links to `/buckets`.
|
|
27
|
+
- **Service detail page** got a Buckets stat and a clickable bucket list that navigates to `/buckets/:name`.
|
|
28
|
+
- `S3Resource` interface in `cloudformation-parser.ts` carries `versioningEnabled` and an array of `S3NotificationConfig { functionRef, events, filterPrefix?, filterSuffix? }`.
|
|
29
|
+
|
|
30
|
+
- **`pro-sample-microservice` example**: same surface as `sample-microservice` (Users/Sessions/Orders tables, OrderProcessing queue, OrderEvents topic, uploads bucket with S3 → Lambda notification, full handler set) but pointed at `localstack/localstack-pro:latest`. Lives on its own ports (LSS `3111`, LocalStack `4571`, offline `3010 / 3011`) so it can run side by side with the community example and an external LocalStack on `4566`. Ships with `.env.example` documenting the required `LOCALSTACK_AUTH_TOKEN` and npm scripts wrapped in `dotenv-cli` so secrets reach both LSS and `serverless-offline` without polluting the shell.
|
|
31
|
+
|
|
32
|
+
- **`.env` support in `sample-microservice`**: matching `.env.example` (with a note that recent community images ≥ 2026.5 also require a token), `.env` / `.env.local` added to `.gitignore`, and every npm script (`lss:start|stop|status|logs|seed*`, `package`, `offline`, `deploy`) wrapped in `dotenv -- ...` via the new `dotenv-cli` devDep.
|
|
33
|
+
|
|
34
|
+
- **`sample-microservice` S3 handlers**: `aws.js` now exports an `S3Client` (with `forcePathStyle: true`), and three new handlers exercise the round-trip:
|
|
35
|
+
- `uploadFile.js` — `POST /uploads` → puts an object under `incoming/{filename}` (supports `encoding: "base64"`).
|
|
36
|
+
- `listUploads.js` — `GET /uploads?prefix=` → lists objects with metadata.
|
|
37
|
+
- `onUpload.js` — bound to the bucket's `s3:ObjectCreated:*` notification under the `incoming/` prefix; reads the object back and writes a synthetic row into the `Orders` table (`userId=s3-upload`) so the trigger is visible from the DynamoDB explorer.
|
|
38
|
+
- `serverless.yml` declares the bucket, the notification (with `Filter.S3Key.Rules` prefix), and adds the three corresponding `functions:`. Env var `UPLOADS_BUCKET` injected for the handlers.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- **`bin/cli.js` PID and log files are now scoped to `serverPort`**: `/tmp/lss-orchestrator-{serverPort}.{pid,log}` instead of the previous global `/tmp/lss-orchestrator.{pid,log}`. The legacy global path is still used when `serverPort` is the default `3100`, so existing single-project setups keep working. This removes the old "PID file is global across all working directories" gotcha — multiple LSS instances (one per example/project) can now coexist on the same machine.
|
|
42
|
+
- **`LocalStackManager` container and volume are scoped to the LocalStack port**: container name is `lss-localstack` for the default `4566` and `lss-localstack-{port}` otherwise; the persistence volume follows the same scheme (`{containerName}-data`). Two examples no longer collide on either the Docker container name or the persistence volume.
|
|
43
|
+
- **Removed the hardcoded `-p 4571:4571` extra port binding** from the LocalStack Docker invocation. It clashed with examples whose LocalStack port is `4571`, and the legacy "edge" port it exposed is obsolete in modern LocalStack (everything flows through the primary port).
|
|
44
|
+
- **`sample-microservice` ports moved off the defaults**: LSS dashboard now on `3110` (was `3101`), LocalStack now on `4570` (was `4566`). Avoids colliding with an external LocalStack on `4566`. The `serverless-offline` ports (`3000`/`3001`) are unchanged.
|
|
45
|
+
- **`sample-microservice` package.json**: added `dotenv-cli` to `devDependencies`; every script wrapped in `dotenv -- ...`. Updated description to mention S3.
|
|
46
|
+
- **Resource breakdown / owner types** in `src/ui/src/services/api.ts` gained the `buckets` fields. The `ServiceResource.type` union now includes `'s3'`, `ResourceBreakdown` includes `buckets: number`, and `ResourceOwnersResponse` includes `buckets: ResourceOwner[]`. Existing `.catch(() => ({...}))` fallbacks in `QueuesView.vue` and `DynamoTablesList.vue` were widened to include the new field.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
- **`resolveLambdaName` now reads `FunctionName` straight from the parsed CFN** instead of hand-crafting `${service}-api-${shortName}`. The old heuristic only worked when the user's stage happened to be `api`; for any other stage (e.g. the default `dev`) the LocalStack proxy would forward to a name `serverless-offline` doesn't recognize and the invocation 404'd with `Function does not exist`. Both the LocalStack proxy and its invoke URL now use the same fully-qualified name (`pro-sample-microservice-dev-onUpload`) that `serverless-offline` exposes on its `lambdaPort`. The old `resolveLambdaFunctionName` helper was removed; `shortFunctionName` is kept only as a last-resort fallback when a logical id isn't present in the parsed CFN.
|
|
50
|
+
- **Event source ARN resolution uses CFN `logicalId` instead of kebab-casing**: `Fn::GetAtt: [OrderProcessingQueue, Arn]` now looks up `OrderProcessingQueue` directly in a logical-id → resource map populated from the parsed template, then derives the real ARN from the resource's actual `QueueName` / `TableName` / `TopicName`. The previous kebab-case match (`order-processing-queue` vs `service-OrderProcessing`) silently failed whenever the user set an explicit `QueueName`/`TableName`, leaving SQS and DynamoDB stream consumers completely unwired.
|
|
51
|
+
- **DynamoDB stream ARN is now fetched via `DescribeTable.LatestStreamArn`** (with up to 5 × 300ms retries while the stream provisions), rather than hand-crafting `arn:aws:dynamodb:...:table/X/stream/NEW_AND_OLD_IMAGES` — the real ARN has a timestamp suffix and the hand-crafted one was always rejected with `Stream not found`.
|
|
52
|
+
- **`CreateEventSourceMappingCommand` now sets `StartingPosition: 'TRIM_HORIZON'` for stream sources** (any resolved ARN starting with `arn:aws:dynamodb:` or `arn:aws:kinesis:`). DynamoDB Streams and Kinesis require this field; SQS forbids it, so the flag is `undefined` for SQS mappings.
|
|
53
|
+
- **CloudFormation parser detects DynamoDB streams via `StreamViewType`** (the field that actually lives in `AWS::DynamoDB::Table.StreamSpecification`) instead of the non-existent `StreamEnabled` boolean. Before, every parsed table came back with `streamEnabled: false`, which meant LSS created the table without streams even when CFN asked for them.
|
|
54
|
+
- **S3 `PutBucketNotificationConfiguration` now passes `SkipDestinationValidation: true`**. LocalStack Pro implements the same synchronous test-invoke validation real S3 does, and was rejecting our config with `Unable to validate the following destination configurations` because the `lambda:InvokeFunction` permission for `s3.amazonaws.com` hadn't fully propagated by the time we wrote the notification. The flag tells S3 to trust the permission we just added rather than probing the destination. (Community LocalStack was lax about this; Pro isn't.)
|
|
55
|
+
- **`ServerlessDeploymentBucket` is now skipped at parse time**. Serverless Framework injects this `AWS::S3::Bucket` for its own deployment artifacts; its name lives behind CloudFormation pseudo-parameters LSS doesn't resolve, so every registration was logging `Failed to provision s3:ServerlessDeploymentBucket: The specified bucket is not valid`. It isn't useful for local dev and is now filtered before provisioning ever runs.
|
|
56
|
+
- **`provisionResources` rebuilds the logical-id map on each call**, so the fixes above don't leak resource lookups across services when the same `ResourceProvisioner` singleton is reused for multiple registrations.
|
|
57
|
+
|
|
58
|
+
### Documentation
|
|
59
|
+
- **`README.md`**: feature list now mentions S3, LocalStack `SERVICES` example updated to `dynamodb,sqs,sns,s3,lambda`, and the "CLI Implementation Details" section reflects the per-port PID/log paths.
|
|
60
|
+
- **`docs/CONFIGURATION.md`**: default `services` array now includes `s3`, examples updated.
|
|
61
|
+
- **`examples/sample-microservice/README.md`**: replaced the "PID file is global" warning with the new ports table; added an S3 section to the HTTP examples and the "Things to play with in the UI" tour.
|
|
62
|
+
- **`examples/pro-sample-microservice/README.md`**: brand-new walkthrough — prerequisites, token setup, port table, run/reset commands, diff summary against the community example.
|
|
63
|
+
- **Example configs** (`lss.config.json`, `lss.config.json.example`) now list `s3` in the default services array.
|
|
64
|
+
|
|
65
|
+
## [0.0.15] - 2026-05-21
|
|
66
|
+
|
|
67
|
+
### Added
|
|
68
|
+
- **Queue detail page with AWS-style send/receive workflow**: clicking a queue in `/queues` now opens `/queues/:name` (lazy-loaded, follows the same routed-page + tabs pattern as the DynamoDB explorer) instead of the old read-only modal. The new page exposes three tabs:
|
|
69
|
+
- **Send & receive** — the headline upgrade. Send arbitrary messages (body, optional `DelaySeconds`, message attributes with `String`/`Number`/`Binary` types). For FIFO queues the form auto-switches to `MessageGroupId` + optional `MessageDeduplicationId` and hides the `DelaySeconds` field (FIFO rejects it). Poll the queue with configurable `MaxNumberOfMessages` (1–10), `VisibilityTimeout`, and `WaitTimeSeconds` (long polling, 0–20). Received messages appear in a table with body preview, message ID, `SentTimestamp`, attribute count, and expandable JSON pretty-print of the full body plus AWS-side attributes (sender, receive count, etc.) and message attributes. Each row supports **Copy body** to clipboard and **Delete** by `ReceiptHandle`. A **Purge queue** action lives under the poll panel, behind a `TConfirmDialog` (warns about the AWS 60s rate limit).
|
|
70
|
+
- **Consumers** — the existing Lambda event-source mapping list, promoted to a dedicated tab.
|
|
71
|
+
- **Attributes** — Identity (queue URL + ARN), Configuration (FIFO, visibility timeout, retention, delayed counter, created/last-polled timestamps), and a Throughput card with the processed-share progress bar and the **Reset processed counter** action that used to live in the modal footer.
|
|
72
|
+
- **`POST /api/queues/:name/messages`**: send a message. Body is `{ body, delaySeconds?, messageAttributes?: [{ name, type, value }], messageGroupId?, messageDeduplicationId? }`. Validates `delaySeconds` is 0–900, ignores it for FIFO queues, and auto-injects `messageGroupId: 'default'` when the queue is FIFO and the field is omitted.
|
|
73
|
+
- **`POST /api/queues/:name/messages/receive`**: poll. Body is `{ maxNumberOfMessages?, visibilityTimeout?, waitTimeSeconds? }` (clamped server-side to 1–10 and 0–20). Returns `{ messages: SqsMessage[] }` with `messageId`, `receiptHandle`, `body`, `md5OfBody`, AWS `attributes` (`SentTimestamp`, `ApproximateReceiveCount`, etc.) and `messageAttributes`.
|
|
74
|
+
- **`POST /api/queues/:name/messages/delete`**: delete a single message by `receiptHandle`.
|
|
75
|
+
- **`POST /api/queues/:name/purge`**: PurgeQueue passthrough.
|
|
76
|
+
- API client helpers `sendQueueMessage`, `receiveQueueMessages`, `deleteQueueMessage`, `purgeQueue` in `src/ui/src/services/api.ts`, plus the supporting `SendQueueMessageInput` / `ReceiveQueueMessagesInput` / `SqsMessage` / `SqsMessageAttributeInput` types.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
- `QueueInspector` now keeps a per-region cache of `SQSClient` and `LambdaClient` instances (same pattern `DynamoExplorer` already uses). `listQueues`, `getQueue`, and the new send/receive/delete/purge methods all accept an optional `region` argument, and every `/api/queues/*` route forwards `?region=` through. Background metric polling still uses the default region.
|
|
80
|
+
- `QueuesView.vue` row click and the trailing **Details** button now navigate to `/queues/:name` instead of opening the in-page modal. The modal, the local `selectedQueueName` state, and the modal-only "Reset processed counter" button were removed from the list view; the reset action lives on the new Attributes tab.
|
|
81
|
+
|
|
82
|
+
## [0.0.14] - 2026-05-20
|
|
83
|
+
|
|
84
|
+
### Added
|
|
85
|
+
- **Full-screen dashboard with URL-based navigation**: the Vue dashboard now uses `vue-router` instead of a single in-memory tab state. Every section is a real URL — `/`, `/services`, `/services/:name`, `/queues`, `/dynamo`, `/dynamo/:name` — so views are bookmarkable, shareable, and the browser back/forward buttons work as expected. DynamoDB table sub-tabs (Items / Indexes / Settings / Seed) are persisted via `?tab=...` so deep links land on the exact sub-view. Pages are code-split (lazy-loaded) so the initial bundle stays small.
|
|
86
|
+
- **Landing-style Overview page**: replaces the old "Resources" tab. Shows a project pitch hero, a live "Server status" card (LocalStack running, Dynamo Proxy enabled/listening, Auto-package on/off, Persistence on/off), an "LESC configuration" card (default region, server port, enabled LocalStack services, seeds dir, active config file path), four totalizers (services running/total, tables, queues, topics) and a "What's covered" panel listing supported resource types — `✓ SNS Topics`, `✓ SQS Queues`, `✓ DynamoDB Tables`, `⏳ S3 Buckets` (planned).
|
|
87
|
+
- **`/services/:name` detail page**: lifecycle controls (Start / Stop / Logs / Delete / Refresh), metadata block (path, region, invoke port, PID, last updated), and resources grouped by type (Lambda functions, DynamoDB tables, SQS queues, SNS topics, event-source mappings). Each declared DynamoDB table or SQS queue is a clickable tag that navigates to its detail view.
|
|
88
|
+
- **"Service" column on the Queues and DynamoDB lists**: each row now shows which microservice declared that queue/table, with a tag that links back to the service detail page. Resources not declared by any registered service render as `unmanaged` / `—`. Powered by a new `GET /api/resources/owners` endpoint that joins the cached CloudFormation templates and filters by region.
|
|
89
|
+
- **Seeds embedded in the DynamoDB explorer**: the standalone "Seeds" tab is gone. Tables that exist only as a seed file (no live table yet) now appear as **ghost rows** in the DynamoDB tables list (reduced opacity, `Not created` badge, "Register service to provision" hint). When a table has a matching seed file, its detail view gets a new **"Seed" sub-tab** with three actions: **Apply** (insert seed items), **Redo** (purge + re-apply, behind a confirmation), and **Purge** (delete every item in the table). Each destructive action goes through a `TConfirmDialog`.
|
|
90
|
+
- **`GET /api/config`**: exposes the runtime LSS configuration snapshot to the UI — `serverPort`, `localstack` (mode/endpoint/port/edition/version/image and `hasAuthToken: boolean`), `dynamoProxy.enabled/port`, `region`, `services`, `persistence`, `debug`, `seedsDir`, `autoPackage`, `packageCommand`, `packageTimeoutMs`, and `configPath`. The actual LocalStack auth token is never returned, only whether one is set.
|
|
91
|
+
- **`GET /api/resources/owners`**: returns `{ tables, queues, topics }` where each entry is `{ name, service }`, computed by parsing each cached CloudFormation template. Respects `?region=` and filters owner mappings to services registered in the requested region.
|
|
92
|
+
- `GET /api/services` now includes `resourceBreakdown: { lambdas, tables, queues, topics }` so the Services table can render per-type chips (`λ`/`🗄`/`📨`/`📣`) instead of a single opaque resource count.
|
|
93
|
+
- `GET /api/health` response now includes a `dynamoProxy: { enabled, running, port }` block so the navbar and Overview can show whether the proxy is actually listening, not just whether it was configured.
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
- **Dashboard uses the full viewport width**. The old `<TContainer size="xl">` cap (~1200px) is gone — wide monitors no longer waste half the screen on margins. A sticky secondary nav bar sits under the navbar with `RouterLink`s for the top-level sections.
|
|
97
|
+
- The DynamoDB tables view was refactored from a 2-column card grid to a denser **table layout** to accommodate the new Service and Seed columns and the ghost-row affordance.
|
|
98
|
+
- The DynamoDB Proxy status is now surfaced as a soft badge in the navbar (when enabled) alongside the existing LocalStack status badge.
|
|
99
|
+
- `Service` typing in the UI moved from inline `interface Service` to the shared `ServiceSummary` / `ServiceDetail` / `ResourceBreakdown` / `ResourceOwner` types in `src/ui/src/services/api.ts`, and the API client gained `getConfig()`, `listResourceOwners()` helpers.
|
|
100
|
+
|
|
101
|
+
### Removed
|
|
102
|
+
- The standalone **"Seeds" tab** and its top-level dashboard entry. All seed actions are now reached from inside the relevant DynamoDB table's detail view, and unprovisioned seeds are visible as ghost rows in the DynamoDB tables list.
|
|
103
|
+
- `src/ui/src/components/ResourcesOverview.vue`, `src/ui/src/components/SeedsPanel.vue`, and `src/ui/src/components/dynamo/DynamoTab.vue` — replaced by the new routed pages (`pages/OverviewPage.vue`, `pages/DynamoPage.vue` + `pages/DynamoTablePage.vue`) and the new `components/dynamo/DynamoSeedPanel.vue`.
|
|
104
|
+
|
|
8
105
|
## [0.0.13] - 2026-05-19
|
|
9
106
|
|
|
10
107
|
### Added
|
|
@@ -12,6 +109,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
12
109
|
|
|
13
110
|
### Changed
|
|
14
111
|
- `POST /api/services/register` now returns a clear `400` with an actionable message (`"CloudFormation template not found at ... Run 'serverless package' in the service directory, or enable autoPackage in lss.config.json."`) when the template is missing and `autoPackage` is disabled, instead of leaking the underlying `ENOENT` stack trace as a `500`.
|
|
112
|
+
- Auto-package failures now log the full stdout/stderr of the package command to the orchestrator log (`/tmp/lss-orchestrator.log`) with delimiter lines, so failures from `serverless-webpack`, stage validators, missing params, etc. are diagnosable. The HTTP response now points users to the orchestrator log for the full transcript.
|
|
15
113
|
- The configuration summary printed at startup now includes the active `autoPackage` and (when enabled) `packageCommand` values.
|
|
16
114
|
|
|
17
115
|
## [0.0.12] - 2026-05-19
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ LSS provides a unified local development environment for serverless microservice
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Centralized LocalStack**: Single LocalStack instance manages DynamoDB, SQS, SNS, and Lambda
|
|
11
|
+
- **Centralized LocalStack**: Single LocalStack instance manages DynamoDB, SQS, SNS, S3, and Lambda
|
|
12
12
|
- **Auto-provisioning**: Parses CloudFormation templates from `sls package` and provisions resources automatically
|
|
13
13
|
- **Event source mappings**: Automatically connects SQS queues to Lambda handlers via LocalStack
|
|
14
14
|
- **Lambda proxies**: Generated proxy functions forward events to serverless-offline invoke endpoints
|
|
@@ -218,7 +218,7 @@ local-serverless-stack/
|
|
|
218
218
|
### LocalStack Settings
|
|
219
219
|
|
|
220
220
|
LocalStack is configured with:
|
|
221
|
-
- Services: `dynamodb,sqs,sns,lambda`
|
|
221
|
+
- Services: `dynamodb,sqs,sns,s3,lambda`
|
|
222
222
|
- Persistence: Enabled (volume: `lss-localstack-data`)
|
|
223
223
|
- Lambda executor: `local` (no Docker-in-Docker required)
|
|
224
224
|
- Docker socket: Mounted from host
|
|
@@ -482,15 +482,15 @@ sequenceDiagram
|
|
|
482
482
|
The `npx lss` CLI is implemented in `/bin/cli.js` and provides:
|
|
483
483
|
|
|
484
484
|
- **Background Process Management**: Uses `spawn` with `detached: true` to run orchestrator independently
|
|
485
|
-
- **PID File**: Stores process ID in `/tmp/lss-orchestrator.pid`
|
|
486
|
-
- **Log File**: Redirects stdout/stderr to `/tmp/lss-orchestrator.log`
|
|
485
|
+
- **PID File**: Stores process ID in `/tmp/lss-orchestrator-{serverPort}.pid` (or `/tmp/lss-orchestrator.pid` when serverPort is the default 3100). The port-scoped path lets multiple LSS instances coexist — one per project — without trampling each other.
|
|
486
|
+
- **Log File**: Redirects stdout/stderr to `/tmp/lss-orchestrator-{serverPort}.log` (or `/tmp/lss-orchestrator.log` for the default port).
|
|
487
487
|
- **Process Monitoring**: Checks if process is alive before starting/stopping
|
|
488
488
|
- **Clean Shutdown**: Sends SIGTERM for graceful termination
|
|
489
489
|
|
|
490
490
|
### Files
|
|
491
491
|
|
|
492
|
-
- **PID File**: `/tmp/lss-orchestrator.pid`
|
|
493
|
-
- **Log File**: `/tmp/lss-orchestrator.log`
|
|
492
|
+
- **PID File**: `/tmp/lss-orchestrator-{serverPort}.pid`
|
|
493
|
+
- **Log File**: `/tmp/lss-orchestrator-{serverPort}.log`
|
|
494
494
|
|
|
495
495
|
## Troubleshooting
|
|
496
496
|
|
package/bin/cli.js
CHANGED
|
@@ -5,8 +5,27 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Default paths used when no config is present. The actual paths are derived
|
|
9
|
+
// per-invocation by runtimePaths() below, scoped to the configured serverPort
|
|
10
|
+
// so multiple examples (each with their own lss.config.json) can run in parallel.
|
|
11
|
+
const DEFAULT_PID_FILE = path.join(os.tmpdir(), 'lss-orchestrator.pid');
|
|
12
|
+
const DEFAULT_LOG_FILE = path.join(os.tmpdir(), 'lss-orchestrator.log');
|
|
13
|
+
|
|
14
|
+
// PID/log file paths scoped to the cwd's serverPort. Multiple examples sitting
|
|
15
|
+
// in different folders no longer trample each other.
|
|
16
|
+
function runtimePaths() {
|
|
17
|
+
const cfg = getConfig(loadConfig());
|
|
18
|
+
const port = cfg.serverPort;
|
|
19
|
+
// Keep the legacy global path when the default port is in use so existing
|
|
20
|
+
// installations don't lose their running process across an upgrade.
|
|
21
|
+
if (!port || port === 3100) {
|
|
22
|
+
return { pidFile: DEFAULT_PID_FILE, logFile: DEFAULT_LOG_FILE };
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
pidFile: path.join(os.tmpdir(), `lss-orchestrator-${port}.pid`),
|
|
26
|
+
logFile: path.join(os.tmpdir(), `lss-orchestrator-${port}.log`),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
10
29
|
|
|
11
30
|
/**
|
|
12
31
|
* Load configuration from lss.config.json or .lssrc
|
|
@@ -82,8 +101,10 @@ function getOrchestratorPath() {
|
|
|
82
101
|
}
|
|
83
102
|
|
|
84
103
|
function startOrchestrator() {
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
const { pidFile, logFile } = runtimePaths();
|
|
105
|
+
|
|
106
|
+
if (fs.existsSync(pidFile)) {
|
|
107
|
+
const pid = fs.readFileSync(pidFile, 'utf8').trim();
|
|
87
108
|
try {
|
|
88
109
|
process.kill(pid, 0);
|
|
89
110
|
const config = loadConfig();
|
|
@@ -96,7 +117,7 @@ function startOrchestrator() {
|
|
|
96
117
|
}
|
|
97
118
|
return;
|
|
98
119
|
} catch (e) {
|
|
99
|
-
fs.unlinkSync(
|
|
120
|
+
fs.unlinkSync(pidFile);
|
|
100
121
|
}
|
|
101
122
|
}
|
|
102
123
|
|
|
@@ -112,7 +133,7 @@ function startOrchestrator() {
|
|
|
112
133
|
process.exit(1);
|
|
113
134
|
}
|
|
114
135
|
|
|
115
|
-
const logFd = fs.openSync(
|
|
136
|
+
const logFd = fs.openSync(logFile, 'a');
|
|
116
137
|
|
|
117
138
|
// Load config
|
|
118
139
|
const config = loadConfig();
|
|
@@ -167,57 +188,59 @@ function startOrchestrator() {
|
|
|
167
188
|
child.unref();
|
|
168
189
|
|
|
169
190
|
fs.closeSync(logFd);
|
|
170
|
-
fs.writeFileSync(
|
|
171
|
-
|
|
191
|
+
fs.writeFileSync(pidFile, child.pid.toString());
|
|
192
|
+
|
|
172
193
|
console.log('🚀 LSS Orchestrator started (PID:', child.pid + ')');
|
|
173
194
|
console.log(`📊 Server: http://localhost:${cfg.serverPort}`);
|
|
174
195
|
console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort} (mode: ${mode}, edition: ${edition})`);
|
|
175
196
|
if (enableDynamoProxy) {
|
|
176
197
|
console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`);
|
|
177
198
|
}
|
|
178
|
-
console.log('📝 Logs:',
|
|
179
|
-
|
|
199
|
+
console.log('📝 Logs:', logFile);
|
|
200
|
+
|
|
180
201
|
setTimeout(() => {
|
|
181
202
|
try {
|
|
182
203
|
process.kill(child.pid, 0);
|
|
183
204
|
console.log('✅ Service is running');
|
|
184
205
|
} catch (e) {
|
|
185
|
-
console.error('❌ Service failed to start. Check logs:',
|
|
186
|
-
if (fs.existsSync(
|
|
187
|
-
fs.unlinkSync(
|
|
206
|
+
console.error('❌ Service failed to start. Check logs:', logFile);
|
|
207
|
+
if (fs.existsSync(pidFile)) {
|
|
208
|
+
fs.unlinkSync(pidFile);
|
|
188
209
|
}
|
|
189
210
|
}
|
|
190
211
|
}, 2000);
|
|
191
212
|
}
|
|
192
213
|
|
|
193
214
|
function stopOrchestrator() {
|
|
194
|
-
|
|
215
|
+
const { pidFile } = runtimePaths();
|
|
216
|
+
if (!fs.existsSync(pidFile)) {
|
|
195
217
|
console.log('⚠️ LSS Orchestrator is not running');
|
|
196
218
|
return;
|
|
197
219
|
}
|
|
198
220
|
|
|
199
|
-
const pid = fs.readFileSync(
|
|
200
|
-
|
|
221
|
+
const pid = fs.readFileSync(pidFile, 'utf8').trim();
|
|
222
|
+
|
|
201
223
|
try {
|
|
202
224
|
process.kill(pid, 'SIGTERM');
|
|
203
|
-
fs.unlinkSync(
|
|
225
|
+
fs.unlinkSync(pidFile);
|
|
204
226
|
console.log('🛑 LSS Orchestrator stopped (PID:', pid + ')');
|
|
205
227
|
} catch (e) {
|
|
206
228
|
console.error('❌ Failed to stop process:', e.message);
|
|
207
|
-
if (fs.existsSync(
|
|
208
|
-
fs.unlinkSync(
|
|
229
|
+
if (fs.existsSync(pidFile)) {
|
|
230
|
+
fs.unlinkSync(pidFile);
|
|
209
231
|
}
|
|
210
232
|
}
|
|
211
233
|
}
|
|
212
234
|
|
|
213
235
|
function showStatus() {
|
|
214
|
-
|
|
236
|
+
const { pidFile, logFile } = runtimePaths();
|
|
237
|
+
if (!fs.existsSync(pidFile)) {
|
|
215
238
|
console.log('⚪ LSS Orchestrator: NOT RUNNING');
|
|
216
239
|
return;
|
|
217
240
|
}
|
|
218
241
|
|
|
219
|
-
const pid = fs.readFileSync(
|
|
220
|
-
|
|
242
|
+
const pid = fs.readFileSync(pidFile, 'utf8').trim();
|
|
243
|
+
|
|
221
244
|
try {
|
|
222
245
|
process.kill(pid, 0);
|
|
223
246
|
const config = loadConfig();
|
|
@@ -228,10 +251,10 @@ function showStatus() {
|
|
|
228
251
|
if (cfg.enableDynamoProxy) {
|
|
229
252
|
console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`);
|
|
230
253
|
}
|
|
231
|
-
console.log('📝 Logs:',
|
|
254
|
+
console.log('📝 Logs:', logFile);
|
|
232
255
|
} catch (e) {
|
|
233
256
|
console.log('⚪ LSS Orchestrator: NOT RUNNING (stale PID file)');
|
|
234
|
-
fs.unlinkSync(
|
|
257
|
+
fs.unlinkSync(pidFile);
|
|
235
258
|
}
|
|
236
259
|
}
|
|
237
260
|
|
|
@@ -276,7 +299,8 @@ function postJson(path, body) {
|
|
|
276
299
|
}
|
|
277
300
|
|
|
278
301
|
function ensureRunningOrExit() {
|
|
279
|
-
|
|
302
|
+
const { pidFile } = runtimePaths();
|
|
303
|
+
if (!fs.existsSync(pidFile)) {
|
|
280
304
|
console.error('❌ LSS Orchestrator is not running. Start it with: npx lss start');
|
|
281
305
|
process.exit(1);
|
|
282
306
|
}
|
|
@@ -392,14 +416,15 @@ Examples:
|
|
|
392
416
|
}
|
|
393
417
|
|
|
394
418
|
function showLogs() {
|
|
395
|
-
|
|
419
|
+
const { logFile } = runtimePaths();
|
|
420
|
+
if (!fs.existsSync(logFile)) {
|
|
396
421
|
console.log('⚠️ No logs found');
|
|
397
422
|
return;
|
|
398
423
|
}
|
|
399
|
-
|
|
400
|
-
console.log('📝 Logs from:',
|
|
424
|
+
|
|
425
|
+
console.log('📝 Logs from:', logFile);
|
|
401
426
|
console.log('---');
|
|
402
|
-
const logs = fs.readFileSync(
|
|
427
|
+
const logs = fs.readFileSync(logFile, 'utf8');
|
|
403
428
|
const lines = logs.split('\n');
|
|
404
429
|
const lastLines = lines.slice(-50).join('\n');
|
|
405
430
|
console.log(lastLines);
|
package/dist/server/index.js
CHANGED
|
@@ -5,8 +5,10 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
import { servicesRouter, processManager } from './routes/services.js';
|
|
6
6
|
import { resourcesRouter } from './routes/resources.js';
|
|
7
7
|
import { queuesRouter } from './routes/queues.js';
|
|
8
|
+
import { bucketsRouter } from './routes/buckets.js';
|
|
8
9
|
import { seedsRouter } from './routes/seeds.js';
|
|
9
10
|
import { dynamoRouter } from './routes/dynamo.js';
|
|
11
|
+
import { configRouter } from './routes/config.js';
|
|
10
12
|
import { LocalStackManager } from './services/localstack-manager.js';
|
|
11
13
|
import { ConfigManager } from './services/config-manager.js';
|
|
12
14
|
import { QueueInspector } from './services/queue-inspector.js';
|
|
@@ -16,6 +18,7 @@ const __dirname = path.dirname(__filename);
|
|
|
16
18
|
const app = express();
|
|
17
19
|
const configManager = ConfigManager.getInstance();
|
|
18
20
|
const PORT = configManager.getDashboardPort();
|
|
21
|
+
let dynamoProxyServer = null;
|
|
19
22
|
// Middleware
|
|
20
23
|
app.use(cors());
|
|
21
24
|
app.use(express.json());
|
|
@@ -23,13 +26,20 @@ app.use(express.json());
|
|
|
23
26
|
app.use('/api/services', servicesRouter);
|
|
24
27
|
app.use('/api/resources', resourcesRouter);
|
|
25
28
|
app.use('/api/queues', queuesRouter);
|
|
29
|
+
app.use('/api/buckets', bucketsRouter);
|
|
26
30
|
app.use('/api/seeds', seedsRouter);
|
|
27
31
|
app.use('/api/dynamo', dynamoRouter);
|
|
32
|
+
app.use('/api/config', configRouter);
|
|
28
33
|
// Health check
|
|
29
34
|
app.get('/api/health', (_req, res) => {
|
|
30
35
|
res.json({
|
|
31
36
|
status: 'ok',
|
|
32
37
|
localstack: LocalStackManager.getInstance().isRunning(),
|
|
38
|
+
dynamoProxy: {
|
|
39
|
+
enabled: configManager.isEnableDynamoProxy(),
|
|
40
|
+
running: Boolean(dynamoProxyServer?.listening),
|
|
41
|
+
port: configManager.getDynamoProxyPort(),
|
|
42
|
+
},
|
|
33
43
|
});
|
|
34
44
|
});
|
|
35
45
|
// Serve frontend build (fallback for SPA)
|
|
@@ -54,7 +64,7 @@ async function start() {
|
|
|
54
64
|
// Optional DynamoDB proxy
|
|
55
65
|
if (configManager.isEnableDynamoProxy()) {
|
|
56
66
|
const proxyPort = configManager.getDynamoProxyPort();
|
|
57
|
-
startDynamoProxy(localstack.getEndpoint(), proxyPort);
|
|
67
|
+
dynamoProxyServer = startDynamoProxy(localstack.getEndpoint(), proxyPort);
|
|
58
68
|
}
|
|
59
69
|
// Print configuration summary
|
|
60
70
|
configManager.printSummary();
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buckets.d.ts","sourceRoot":"","sources":["../../../src/server/routes/buckets.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA+HxB,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { S3Explorer } from '../services/s3-explorer.js';
|
|
3
|
+
const router = Router();
|
|
4
|
+
const explorer = S3Explorer.getInstance();
|
|
5
|
+
// S3 bucket name rules are stricter than DNS, but the only constraints we enforce here
|
|
6
|
+
// are anti-traversal — actual validation happens server-side at LocalStack.
|
|
7
|
+
function isValidBucketName(name) {
|
|
8
|
+
return (typeof name === 'string' &&
|
|
9
|
+
name.length > 0 &&
|
|
10
|
+
name.length <= 63 &&
|
|
11
|
+
!name.includes('/') &&
|
|
12
|
+
!name.includes('..') &&
|
|
13
|
+
!name.includes('\\'));
|
|
14
|
+
}
|
|
15
|
+
function isValidObjectKey(key) {
|
|
16
|
+
return typeof key === 'string' && key.length > 0 && key.length <= 1024 && !key.includes('..');
|
|
17
|
+
}
|
|
18
|
+
function fail(res, error, status = 500) {
|
|
19
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
20
|
+
return res.status(status).json({ error: message });
|
|
21
|
+
}
|
|
22
|
+
function getRegion(req) {
|
|
23
|
+
const r = req.query.region;
|
|
24
|
+
return typeof r === 'string' && r ? r : undefined;
|
|
25
|
+
}
|
|
26
|
+
router.get('/', async (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
const buckets = await explorer.listBuckets(getRegion(req));
|
|
29
|
+
res.json(buckets);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
fail(res, error);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
router.get('/:name', async (req, res) => {
|
|
36
|
+
const name = req.params.name;
|
|
37
|
+
if (!isValidBucketName(name))
|
|
38
|
+
return fail(res, new Error('Invalid bucket name'), 400);
|
|
39
|
+
try {
|
|
40
|
+
const bucket = await explorer.getBucket(name, getRegion(req));
|
|
41
|
+
if (!bucket)
|
|
42
|
+
return res.status(404).json({ error: 'Bucket not found' });
|
|
43
|
+
return res.json(bucket);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return fail(res, error);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
router.get('/:name/objects', async (req, res) => {
|
|
50
|
+
const name = req.params.name;
|
|
51
|
+
if (!isValidBucketName(name))
|
|
52
|
+
return fail(res, new Error('Invalid bucket name'), 400);
|
|
53
|
+
const prefix = typeof req.query.prefix === 'string' ? req.query.prefix : undefined;
|
|
54
|
+
const continuationToken = typeof req.query.continuationToken === 'string' ? req.query.continuationToken : undefined;
|
|
55
|
+
const delimiter = typeof req.query.delimiter === 'string' ? req.query.delimiter : undefined;
|
|
56
|
+
const maxKeysRaw = req.query.maxKeys;
|
|
57
|
+
const maxKeys = typeof maxKeysRaw === 'string' ? parseInt(maxKeysRaw, 10) : undefined;
|
|
58
|
+
try {
|
|
59
|
+
const result = await explorer.listObjects(name, { prefix, continuationToken, maxKeys, delimiter }, getRegion(req));
|
|
60
|
+
return res.json(result);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
return fail(res, error);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// Fetch the raw object body. Used by the UI to preview text or download files.
|
|
67
|
+
router.get('/:name/objects/content', async (req, res) => {
|
|
68
|
+
const name = req.params.name;
|
|
69
|
+
if (!isValidBucketName(name))
|
|
70
|
+
return fail(res, new Error('Invalid bucket name'), 400);
|
|
71
|
+
const key = req.query.key;
|
|
72
|
+
if (!isValidObjectKey(key))
|
|
73
|
+
return fail(res, new Error('Invalid object key'), 400);
|
|
74
|
+
try {
|
|
75
|
+
const obj = await explorer.getObject(name, key, getRegion(req));
|
|
76
|
+
if (!obj)
|
|
77
|
+
return res.status(404).json({ error: 'Object not found' });
|
|
78
|
+
// ?download=1 forces an attachment disposition; otherwise inline view.
|
|
79
|
+
const wantDownload = req.query.download === '1' || req.query.download === 'true';
|
|
80
|
+
if (obj.contentType)
|
|
81
|
+
res.setHeader('Content-Type', obj.contentType);
|
|
82
|
+
if (wantDownload) {
|
|
83
|
+
const fname = key.split('/').pop() || 'download';
|
|
84
|
+
res.setHeader('Content-Disposition', `attachment; filename="${fname}"`);
|
|
85
|
+
}
|
|
86
|
+
res.setHeader('Content-Length', String(obj.size));
|
|
87
|
+
return res.send(obj.body);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return fail(res, error);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
router.post('/:name/objects', async (req, res) => {
|
|
94
|
+
const name = req.params.name;
|
|
95
|
+
if (!isValidBucketName(name))
|
|
96
|
+
return fail(res, new Error('Invalid bucket name'), 400);
|
|
97
|
+
const { key, body, contentType, encoding } = req.body ?? {};
|
|
98
|
+
if (!isValidObjectKey(key))
|
|
99
|
+
return fail(res, new Error('key (string) is required'), 400);
|
|
100
|
+
if (typeof body !== 'string')
|
|
101
|
+
return fail(res, new Error('body (string) is required'), 400);
|
|
102
|
+
// encoding="base64" lets the UI upload binary content via a JSON body.
|
|
103
|
+
const payload = encoding === 'base64' ? Buffer.from(body, 'base64') : body;
|
|
104
|
+
try {
|
|
105
|
+
await explorer.putObject(name, { key, body: payload, contentType }, getRegion(req));
|
|
106
|
+
return res.json({ success: true });
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
return fail(res, error, 400);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
router.delete('/:name/objects', async (req, res) => {
|
|
113
|
+
const name = req.params.name;
|
|
114
|
+
if (!isValidBucketName(name))
|
|
115
|
+
return fail(res, new Error('Invalid bucket name'), 400);
|
|
116
|
+
const key = req.query.key;
|
|
117
|
+
if (!isValidObjectKey(key))
|
|
118
|
+
return fail(res, new Error('Invalid object key'), 400);
|
|
119
|
+
try {
|
|
120
|
+
await explorer.deleteObject(name, key, getRegion(req));
|
|
121
|
+
return res.json({ success: true });
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
return fail(res, error, 400);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
export { router as bucketsRouter };
|
|
128
|
+
//# sourceMappingURL=buckets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buckets.js","sourceRoot":"","sources":["../../../src/server/routes/buckets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/server/routes/config.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAiCxB,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { ConfigManager } from '../services/config-manager.js';
|
|
3
|
+
const router = Router();
|
|
4
|
+
// Public-safe LSS configuration snapshot for the UI overview.
|
|
5
|
+
// Never expose the LocalStack auth token — only whether it's set.
|
|
6
|
+
router.get('/', (_req, res) => {
|
|
7
|
+
const cm = ConfigManager.getInstance();
|
|
8
|
+
res.json({
|
|
9
|
+
serverPort: cm.getServerPort(),
|
|
10
|
+
localstack: {
|
|
11
|
+
mode: cm.getMode(),
|
|
12
|
+
endpoint: cm.getLocalStackEndpoint(),
|
|
13
|
+
port: cm.getLocalStackPort(),
|
|
14
|
+
edition: cm.getLocalStackEdition(),
|
|
15
|
+
version: cm.getLocalStackVersion(),
|
|
16
|
+
image: cm.getLocalStackImage(),
|
|
17
|
+
hasAuthToken: Boolean(cm.getLocalStackAuthToken()),
|
|
18
|
+
},
|
|
19
|
+
dynamoProxy: {
|
|
20
|
+
enabled: cm.isEnableDynamoProxy(),
|
|
21
|
+
port: cm.getDynamoProxyPort(),
|
|
22
|
+
},
|
|
23
|
+
region: cm.getRegion(),
|
|
24
|
+
services: cm.getServices(),
|
|
25
|
+
persistence: cm.isPersistence(),
|
|
26
|
+
debug: cm.isDebug(),
|
|
27
|
+
seedsDir: cm.getSeedsDir(),
|
|
28
|
+
autoPackage: cm.isAutoPackage(),
|
|
29
|
+
packageCommand: cm.getPackageCommand(),
|
|
30
|
+
packageTimeoutMs: cm.getPackageTimeoutMs(),
|
|
31
|
+
configPath: cm.getConfigPath(),
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
export { router as configRouter };
|
|
35
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/server/routes/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,8DAA8D;AAC9D,kEAAkE;AAClE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAC/C,MAAM,EAAE,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IACvC,GAAG,CAAC,IAAI,CAAC;QACP,UAAU,EAAE,EAAE,CAAC,aAAa,EAAE;QAC9B,UAAU,EAAE;YACV,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE;YAClB,QAAQ,EAAE,EAAE,CAAC,qBAAqB,EAAE;YACpC,IAAI,EAAE,EAAE,CAAC,iBAAiB,EAAE;YAC5B,OAAO,EAAE,EAAE,CAAC,oBAAoB,EAAE;YAClC,OAAO,EAAE,EAAE,CAAC,oBAAoB,EAAE;YAClC,KAAK,EAAE,EAAE,CAAC,kBAAkB,EAAE;YAC9B,YAAY,EAAE,OAAO,CAAC,EAAE,CAAC,sBAAsB,EAAE,CAAC;SACnD;QACD,WAAW,EAAE;YACX,OAAO,EAAE,EAAE,CAAC,mBAAmB,EAAE;YACjC,IAAI,EAAE,EAAE,CAAC,kBAAkB,EAAE;SAC9B;QACD,MAAM,EAAE,EAAE,CAAC,SAAS,EAAE;QACtB,QAAQ,EAAE,EAAE,CAAC,WAAW,EAAE;QAC1B,WAAW,EAAE,EAAE,CAAC,aAAa,EAAE;QAC/B,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE;QACnB,QAAQ,EAAE,EAAE,CAAC,WAAW,EAAE;QAC1B,WAAW,EAAE,EAAE,CAAC,aAAa,EAAE;QAC/B,cAAc,EAAE,EAAE,CAAC,iBAAiB,EAAE;QACtC,gBAAgB,EAAE,EAAE,CAAC,mBAAmB,EAAE;QAC1C,UAAU,EAAE,EAAE,CAAC,aAAa,EAAE;KAC/B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queues.d.ts","sourceRoot":"","sources":["../../../src/server/routes/queues.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"queues.d.ts","sourceRoot":"","sources":["../../../src/server/routes/queues.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAyHxB,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
|