local-serverless-stack 0.5.0 → 0.8.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.
Files changed (225) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +105 -17
  3. package/bin/cli.js +68 -5
  4. package/dist/server/engine/backends/localstack-backend.d.ts +25 -0
  5. package/dist/server/engine/backends/localstack-backend.d.ts.map +1 -0
  6. package/dist/server/engine/backends/localstack-backend.js +199 -0
  7. package/dist/server/engine/backends/localstack-backend.js.map +1 -0
  8. package/dist/server/engine/backends/self-backend.d.ts +32 -0
  9. package/dist/server/engine/backends/self-backend.d.ts.map +1 -0
  10. package/dist/server/engine/backends/self-backend.js +205 -0
  11. package/dist/server/engine/backends/self-backend.js.map +1 -0
  12. package/dist/server/engine/bus.d.ts +10 -0
  13. package/dist/server/engine/bus.d.ts.map +1 -0
  14. package/dist/server/engine/bus.js +24 -0
  15. package/dist/server/engine/bus.js.map +1 -0
  16. package/dist/server/engine/dispatch/dispatcher.d.ts +46 -0
  17. package/dist/server/engine/dispatch/dispatcher.d.ts.map +1 -0
  18. package/dist/server/engine/dispatch/dispatcher.js +312 -0
  19. package/dist/server/engine/dispatch/dispatcher.js.map +1 -0
  20. package/dist/server/engine/dispatch/scheduler.d.ts +47 -0
  21. package/dist/server/engine/dispatch/scheduler.d.ts.map +1 -0
  22. package/dist/server/engine/dispatch/scheduler.js +328 -0
  23. package/dist/server/engine/dispatch/scheduler.js.map +1 -0
  24. package/dist/server/engine/dispatch/sqs-poller.d.ts +25 -0
  25. package/dist/server/engine/dispatch/sqs-poller.d.ts.map +1 -0
  26. package/dist/server/engine/dispatch/sqs-poller.js +242 -0
  27. package/dist/server/engine/dispatch/sqs-poller.js.map +1 -0
  28. package/dist/server/engine/dispatch/stream-tailer.d.ts +22 -0
  29. package/dist/server/engine/dispatch/stream-tailer.d.ts.map +1 -0
  30. package/dist/server/engine/dispatch/stream-tailer.js +205 -0
  31. package/dist/server/engine/dispatch/stream-tailer.js.map +1 -0
  32. package/dist/server/engine/emulators/dynamodb/expressions/decimal.d.ts +5 -0
  33. package/dist/server/engine/emulators/dynamodb/expressions/decimal.d.ts.map +1 -0
  34. package/dist/server/engine/emulators/dynamodb/expressions/decimal.js +91 -0
  35. package/dist/server/engine/emulators/dynamodb/expressions/decimal.js.map +1 -0
  36. package/dist/server/engine/emulators/dynamodb/expressions/evaluate.d.ts +24 -0
  37. package/dist/server/engine/emulators/dynamodb/expressions/evaluate.d.ts.map +1 -0
  38. package/dist/server/engine/emulators/dynamodb/expressions/evaluate.js +183 -0
  39. package/dist/server/engine/emulators/dynamodb/expressions/evaluate.js.map +1 -0
  40. package/dist/server/engine/emulators/dynamodb/expressions/expression-types.d.ts +29 -0
  41. package/dist/server/engine/emulators/dynamodb/expressions/expression-types.d.ts.map +1 -0
  42. package/dist/server/engine/emulators/dynamodb/expressions/expression-types.js +12 -0
  43. package/dist/server/engine/emulators/dynamodb/expressions/expression-types.js.map +1 -0
  44. package/dist/server/engine/emulators/dynamodb/expressions/index.d.ts +13 -0
  45. package/dist/server/engine/emulators/dynamodb/expressions/index.d.ts.map +1 -0
  46. package/dist/server/engine/emulators/dynamodb/expressions/index.js +244 -0
  47. package/dist/server/engine/emulators/dynamodb/expressions/index.js.map +1 -0
  48. package/dist/server/engine/emulators/dynamodb/expressions/lexer.d.ts +11 -0
  49. package/dist/server/engine/emulators/dynamodb/expressions/lexer.d.ts.map +1 -0
  50. package/dist/server/engine/emulators/dynamodb/expressions/lexer.js +109 -0
  51. package/dist/server/engine/emulators/dynamodb/expressions/lexer.js.map +1 -0
  52. package/dist/server/engine/emulators/dynamodb/expressions/parser.d.ts +23 -0
  53. package/dist/server/engine/emulators/dynamodb/expressions/parser.d.ts.map +1 -0
  54. package/dist/server/engine/emulators/dynamodb/expressions/parser.js +541 -0
  55. package/dist/server/engine/emulators/dynamodb/expressions/parser.js.map +1 -0
  56. package/dist/server/engine/emulators/dynamodb/index.d.ts +46 -0
  57. package/dist/server/engine/emulators/dynamodb/index.d.ts.map +1 -0
  58. package/dist/server/engine/emulators/dynamodb/index.js +572 -0
  59. package/dist/server/engine/emulators/dynamodb/index.js.map +1 -0
  60. package/dist/server/engine/emulators/dynamodb/query.d.ts +12 -0
  61. package/dist/server/engine/emulators/dynamodb/query.d.ts.map +1 -0
  62. package/dist/server/engine/emulators/dynamodb/query.js +237 -0
  63. package/dist/server/engine/emulators/dynamodb/query.js.map +1 -0
  64. package/dist/server/engine/emulators/dynamodb/schema.d.ts +58 -0
  65. package/dist/server/engine/emulators/dynamodb/schema.d.ts.map +1 -0
  66. package/dist/server/engine/emulators/dynamodb/schema.js +284 -0
  67. package/dist/server/engine/emulators/dynamodb/schema.js.map +1 -0
  68. package/dist/server/engine/emulators/dynamodb/streams.d.ts +28 -0
  69. package/dist/server/engine/emulators/dynamodb/streams.d.ts.map +1 -0
  70. package/dist/server/engine/emulators/dynamodb/streams.js +100 -0
  71. package/dist/server/engine/emulators/dynamodb/streams.js.map +1 -0
  72. package/dist/server/engine/emulators/events/index.d.ts +53 -0
  73. package/dist/server/engine/emulators/events/index.d.ts.map +1 -0
  74. package/dist/server/engine/emulators/events/index.js +417 -0
  75. package/dist/server/engine/emulators/events/index.js.map +1 -0
  76. package/dist/server/engine/emulators/events/pattern.d.ts +3 -0
  77. package/dist/server/engine/emulators/events/pattern.d.ts.map +1 -0
  78. package/dist/server/engine/emulators/events/pattern.js +125 -0
  79. package/dist/server/engine/emulators/events/pattern.js.map +1 -0
  80. package/dist/server/engine/emulators/lambda-ctl/index.d.ts +55 -0
  81. package/dist/server/engine/emulators/lambda-ctl/index.d.ts.map +1 -0
  82. package/dist/server/engine/emulators/lambda-ctl/index.js +461 -0
  83. package/dist/server/engine/emulators/lambda-ctl/index.js.map +1 -0
  84. package/dist/server/engine/emulators/s3/index.d.ts +45 -0
  85. package/dist/server/engine/emulators/s3/index.d.ts.map +1 -0
  86. package/dist/server/engine/emulators/s3/index.js +591 -0
  87. package/dist/server/engine/emulators/s3/index.js.map +1 -0
  88. package/dist/server/engine/emulators/sns/index.d.ts +22 -0
  89. package/dist/server/engine/emulators/sns/index.d.ts.map +1 -0
  90. package/dist/server/engine/emulators/sns/index.js +135 -0
  91. package/dist/server/engine/emulators/sns/index.js.map +1 -0
  92. package/dist/server/engine/emulators/sqs/index.d.ts +66 -0
  93. package/dist/server/engine/emulators/sqs/index.d.ts.map +1 -0
  94. package/dist/server/engine/emulators/sqs/index.js +552 -0
  95. package/dist/server/engine/emulators/sqs/index.js.map +1 -0
  96. package/dist/server/engine/emulators/sqs/md5.d.ts +8 -0
  97. package/dist/server/engine/emulators/sqs/md5.d.ts.map +1 -0
  98. package/dist/server/engine/emulators/sqs/md5.js +36 -0
  99. package/dist/server/engine/emulators/sqs/md5.js.map +1 -0
  100. package/dist/server/engine/emulators/sqs/queue.d.ts +105 -0
  101. package/dist/server/engine/emulators/sqs/queue.d.ts.map +1 -0
  102. package/dist/server/engine/emulators/sqs/queue.js +371 -0
  103. package/dist/server/engine/emulators/sqs/queue.js.map +1 -0
  104. package/dist/server/engine/emulators/sts.d.ts +8 -0
  105. package/dist/server/engine/emulators/sts.d.ts.map +1 -0
  106. package/dist/server/engine/emulators/sts.js +23 -0
  107. package/dist/server/engine/emulators/sts.js.map +1 -0
  108. package/dist/server/engine/engine-backend.d.ts +17 -0
  109. package/dist/server/engine/engine-backend.d.ts.map +1 -0
  110. package/dist/server/engine/engine-backend.js +7 -0
  111. package/dist/server/engine/engine-backend.js.map +1 -0
  112. package/dist/server/engine/engine-manager.d.ts +22 -0
  113. package/dist/server/engine/engine-manager.d.ts.map +1 -0
  114. package/dist/server/engine/engine-manager.js +74 -0
  115. package/dist/server/engine/engine-manager.js.map +1 -0
  116. package/dist/server/engine/http/aws-chunked.d.ts +3 -0
  117. package/dist/server/engine/http/aws-chunked.d.ts.map +1 -0
  118. package/dist/server/engine/http/aws-chunked.js +50 -0
  119. package/dist/server/engine/http/aws-chunked.js.map +1 -0
  120. package/dist/server/engine/http/errors.d.ts +20 -0
  121. package/dist/server/engine/http/errors.d.ts.map +1 -0
  122. package/dist/server/engine/http/errors.js +43 -0
  123. package/dist/server/engine/http/errors.js.map +1 -0
  124. package/dist/server/engine/http/protocols/aws-json.d.ts +8 -0
  125. package/dist/server/engine/http/protocols/aws-json.d.ts.map +1 -0
  126. package/dist/server/engine/http/protocols/aws-json.js +42 -0
  127. package/dist/server/engine/http/protocols/aws-json.js.map +1 -0
  128. package/dist/server/engine/http/protocols/query-xml.d.ts +7 -0
  129. package/dist/server/engine/http/protocols/query-xml.d.ts.map +1 -0
  130. package/dist/server/engine/http/protocols/query-xml.js +35 -0
  131. package/dist/server/engine/http/protocols/query-xml.js.map +1 -0
  132. package/dist/server/engine/http/router.d.ts +8 -0
  133. package/dist/server/engine/http/router.d.ts.map +1 -0
  134. package/dist/server/engine/http/router.js +391 -0
  135. package/dist/server/engine/http/router.js.map +1 -0
  136. package/dist/server/engine/http/sigv4.d.ts +9 -0
  137. package/dist/server/engine/http/sigv4.d.ts.map +1 -0
  138. package/dist/server/engine/http/sigv4.js +33 -0
  139. package/dist/server/engine/http/sigv4.js.map +1 -0
  140. package/dist/server/engine/http/xml.d.ts +16 -0
  141. package/dist/server/engine/http/xml.d.ts.map +1 -0
  142. package/dist/server/engine/http/xml.js +92 -0
  143. package/dist/server/engine/http/xml.js.map +1 -0
  144. package/dist/server/engine/store/atomic.d.ts +4 -0
  145. package/dist/server/engine/store/atomic.d.ts.map +1 -0
  146. package/dist/server/engine/store/atomic.js +35 -0
  147. package/dist/server/engine/store/atomic.js.map +1 -0
  148. package/dist/server/engine/store/engine-store.d.ts +9 -0
  149. package/dist/server/engine/store/engine-store.d.ts.map +1 -0
  150. package/dist/server/engine/store/engine-store.js +218 -0
  151. package/dist/server/engine/store/engine-store.js.map +1 -0
  152. package/dist/server/engine/store/store-types.d.ts +37 -0
  153. package/dist/server/engine/store/store-types.d.ts.map +1 -0
  154. package/dist/server/engine/store/store-types.js +17 -0
  155. package/dist/server/engine/store/store-types.js.map +1 -0
  156. package/dist/server/engine/store/wal.d.ts +49 -0
  157. package/dist/server/engine/store/wal.d.ts.map +1 -0
  158. package/dist/server/engine/store/wal.js +328 -0
  159. package/dist/server/engine/store/wal.js.map +1 -0
  160. package/dist/server/engine/types.d.ts +137 -0
  161. package/dist/server/engine/types.d.ts.map +1 -0
  162. package/dist/server/engine/types.js +8 -0
  163. package/dist/server/engine/types.js.map +1 -0
  164. package/dist/server/index.js +12 -9
  165. package/dist/server/index.js.map +1 -1
  166. package/dist/server/routes/services.d.ts.map +1 -1
  167. package/dist/server/routes/services.js +2 -0
  168. package/dist/server/routes/services.js.map +1 -1
  169. package/dist/server/runtime/runtime-worker.js +34 -11
  170. package/dist/server/runtime/runtime-worker.js.map +1 -1
  171. package/dist/server/services/artifact-resolver.d.ts +2 -0
  172. package/dist/server/services/artifact-resolver.d.ts.map +1 -0
  173. package/dist/server/services/artifact-resolver.js +38 -0
  174. package/dist/server/services/artifact-resolver.js.map +1 -0
  175. package/dist/server/services/cloudformation-parser.d.ts +41 -2
  176. package/dist/server/services/cloudformation-parser.d.ts.map +1 -1
  177. package/dist/server/services/cloudformation-parser.js +96 -6
  178. package/dist/server/services/cloudformation-parser.js.map +1 -1
  179. package/dist/server/services/config-manager.d.ts +29 -0
  180. package/dist/server/services/config-manager.d.ts.map +1 -1
  181. package/dist/server/services/config-manager.js +75 -6
  182. package/dist/server/services/config-manager.js.map +1 -1
  183. package/dist/server/services/lambda-runtime-manager.d.ts.map +1 -1
  184. package/dist/server/services/lambda-runtime-manager.js +2 -19
  185. package/dist/server/services/lambda-runtime-manager.js.map +1 -1
  186. package/dist/server/services/localstack-manager.d.ts +0 -7
  187. package/dist/server/services/localstack-manager.d.ts.map +1 -1
  188. package/dist/server/services/localstack-manager.js +11 -173
  189. package/dist/server/services/localstack-manager.js.map +1 -1
  190. package/dist/server/services/resource-provisioner.d.ts +7 -0
  191. package/dist/server/services/resource-provisioner.d.ts.map +1 -1
  192. package/dist/server/services/resource-provisioner.js +244 -18
  193. package/dist/server/services/resource-provisioner.js.map +1 -1
  194. package/dist/server/services/service-registrar.d.ts.map +1 -1
  195. package/dist/server/services/service-registrar.js +22 -4
  196. package/dist/server/services/service-registrar.js.map +1 -1
  197. package/dist/ui/assets/ApisPage-a9i2qD0Z.js +1 -0
  198. package/dist/ui/assets/BucketDetailPage-Cz27N0KV.js +1 -0
  199. package/dist/ui/assets/BucketsPage-CZ7wGmUN.js +1 -0
  200. package/dist/ui/assets/{DynamoPage-B1__Rjr2.js → DynamoPage-BZMs1iW8.js} +1 -1
  201. package/dist/ui/assets/DynamoTablePage-BQsGkhtO.js +3 -0
  202. package/dist/ui/assets/LambdaDetailPage-DJb7xqRB.js +4 -0
  203. package/dist/ui/assets/LambdasPage-Ctg1l-Lg.js +1 -0
  204. package/dist/ui/assets/OverviewPage-DiijblCA.js +1 -0
  205. package/dist/ui/assets/QueueDetailPage-DRpSqost.js +1 -0
  206. package/dist/ui/assets/QueuesPage-CY0bDGwV.js +1 -0
  207. package/dist/ui/assets/ServiceDetailPage-CYTEdtts.js +2 -0
  208. package/dist/ui/assets/ServicesPage-OlV_rr-q.js +2 -0
  209. package/dist/ui/assets/index-C1KdKPDS.css +1 -0
  210. package/dist/ui/assets/index-DA_C1HOg.js +36 -0
  211. package/dist/ui/index.html +2 -2
  212. package/package.json +2 -1
  213. package/dist/ui/assets/ApisPage-DdgKjEdS.js +0 -1
  214. package/dist/ui/assets/BucketDetailPage-DZQGxm0y.js +0 -1
  215. package/dist/ui/assets/BucketsPage-xYXzxCvd.js +0 -1
  216. package/dist/ui/assets/DynamoTablePage-BCoxPdXW.js +0 -3
  217. package/dist/ui/assets/LambdaDetailPage-B85CA8tb.js +0 -4
  218. package/dist/ui/assets/LambdasPage-_TtxQMT_.js +0 -1
  219. package/dist/ui/assets/OverviewPage-CqTKTY64.js +0 -1
  220. package/dist/ui/assets/QueueDetailPage-BOr_sImA.js +0 -1
  221. package/dist/ui/assets/QueuesPage-DpByfcM5.js +0 -1
  222. package/dist/ui/assets/ServiceDetailPage-DsWgV-ad.js +0 -2
  223. package/dist/ui/assets/ServicesPage-CGlpsj98.js +0 -2
  224. package/dist/ui/assets/index-BWlB542w.js +0 -36
  225. package/dist/ui/assets/index-EYnsoJOq.css +0 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,82 @@ 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.8.0] - 2026-07-10
9
+
10
+ The self engine: an in-process AWS emulator that replaces LocalStack for the typical serverless dev loop — DynamoDB, SQS, S3, EventBridge, SNS (minimal), Lambda control plane and STS served by the orchestrator itself on one port. No Docker, no container, no auth token; boots in milliseconds; data persisted in local files. Opt-in (`engine: "self"` / `lss start --self-engine`) — LocalStack mode remains the default and fully supported. Design: `docs/PRD_SELF_ENGINE.md`; coverage matrix: `docs/SELF_ENGINE.md`.
11
+
12
+ ### Added
13
+ - **Engine selection**: `engine: "localstack" | "self"` and a `selfEngine` config block (`port` default 14566 — deliberately outside the 4566–4599 range a real LocalStack intercepts on some hosts —, `dataDir`, `account`, `idleUnloadMs`, `memoryBudgetMb`, `fsync`, `fallbackEndpoint`); env overrides `LSS_ENGINE`/`LSS_ENGINE_PORT`; CLI `lss start --self-engine` (rejected when combined with the LocalStack-only `--external`/`--pro`/`--localstack-token`).
14
+ - **AWS wire front door** (`src/server/engine/http/`): one `node:http` listener routing by SigV4 credential scope → `X-Amz-Target` → path heuristics; per-protocol error serialization (JSON `__type`, Query XML, S3 XML with body-less HEAD errors, Lambda REST + `x-amzn-ErrorType`); the `x-amzn-query-error` SQS compat header; `aws-chunked` request decoding (SDK v3 streaming PutObject); `x-amzn-RequestId` on every response; `/_localstack/health` alias so existing readiness polls keep working; `selfEngine.fallbackEndpoint` reverse-proxies any unimplemented service/operation verbatim to a LocalStack during migration — unsupported calls otherwise fail loudly, never silently succeed.
15
+ - **File-backed store** (`src/server/engine/store/`): JSONL snapshot + append-only WAL per data table (torn-tail-safe replay, seq-based compaction), atomic JSON catalogs for metadata, content-addressed blob storage for S3 bodies (never held in the heap); registration writes metadata only — data hydrates on first touch (streamed line-by-line) and dehydrates after `idleUnloadMs` or under the `memoryBudgetMb` LRU budget; debounced flushes (20 ms / 256 KB) with opt-in fsync.
16
+ - **DynamoDB emulator** with a hand-rolled expression engine (KeyCondition/Condition/Filter/Update/Projection: comparators, `BETWEEN`/`IN`, boolean precedence, document paths, `SET`/`REMOVE`/`ADD`/`DELETE` with exact decimal-string `N` arithmetic), GSI/LSI queries with projection and sparse-index semantics, `Limit`-before-filter parity, `LastEvaluatedKey` paging (including index LEKs), lazy TTL (filtered at read, purged at compaction with Service-identity stream REMOVEs), stream records (`INSERT`/`MODIFY`/`REMOVE` per `StreamViewType`), batch ops, and the full `DescribeTable` introspection shape (`LatestStreamArn` present immediately).
17
+ - **SQS emulator**: FIFO (per-group ordering, 5-minute dedup window), event-driven long polling (parked promises — no polling loops), visibility-timeout redelivery, live `ApproximateNumberOfMessages*` counters (QueueInspector `await-idle`/metrics work unchanged), `MD5OfMessageBody`/`MD5OfMessageAttributes`, CreateQueue idempotent-success on identical attributes; messages are memory-only with a graceful-shutdown snapshot under `persistence`.
18
+ - **S3 emulator**: byte-exact object round trips, `Range` reads, `ListObjectsV2` (prefix/delimiter/CommonPrefixes/continuation/`encoding-type=url`), `DeleteObjects`, `CopyObject`, versioning flag, notification configuration (including the legacy `CloudFunctionConfiguration` XML names), quoted-MD5 ETags, `GetBucketLocation` us-east-1 quirk; multipart answers an explicit `NotImplemented` until the hardening phase.
19
+ - **EventBridge emulator**: buses, rules with validated patterns (exact, array-OR, `prefix`, `exists`, nested keys; unsupported operators rejected at `PutRule` with `InvalidEventPatternException`), targets, `PutEvents` with per-entry results, plus minimal **SNS** (topics + logged `Publish`) and **STS** (`GetCallerIdentity`).
20
+ - **Lambda control plane**: the provisioner's proxy functions are absorbed as metadata (zip discarded, `INVOKE_URL` kept — it doubles as the HTTP fallback for services still on serverless-offline), event source mappings with UUIDs persisted across restarts, `UpdateEventSourceMapping Enabled` = QueueInspector hold/release, `Invoke` honoring `X-Amz-Invocation-Type`.
21
+ - **In-process event dispatch** (`src/server/engine/dispatch/`): SQS delivery loops (batch size + `MaximumBatchingWindowInSeconds`, failure → visibility redelivery, capped backoff on runtime-unavailable), DynamoDB stream tailers (`TRIM_HORIZON`/`LATEST`, retry-then-advance with the `DDBStreamBatchInfo` OnFailure SQS envelope), S3 notification fan-out (event globs + prefix/suffix filters, `eventVersion 2.1` records), EventBridge target invocation (`Input`/`InputPath`) and **schedule triggering** (`rate()` + 6-field AWS cron, single timer wheel) — all delivered straight into the LSS Lambda runtime: no proxy Lambdas, no HTTP hop, no polling containers. Closes the long-standing scheduled-triggers TODO for self-engine mode.
22
+ - **Example `examples/self-engine-sample`**: three microservices (orders → billing → notifications) exercising DynamoDB + SQS (cross-service ESM by ARN) + S3 + EventBridge on the self engine, registered with `sls package` only. Measured: engine boot ~10 ms; the full pipeline across the three services completes in ~170 ms — no Docker.
23
+ - **Docs**: `docs/SELF_ENGINE.md` (coverage matrix, storage model, known divergences), `docs/PRD_SELF_ENGINE.md` (design), FEATURES.md §13, CONFIGURATION.md and README (self engine as the headline feature).
24
+ - **VS Code tasks** (`.vscode/tasks.json`, now versioned via a `.gitignore` exception): build/dev, unit/coverage/integration tests, lint, cross-project typecheck, a `validate: pre-prod` sequence (lint → typecheck → tests → build), and one-click flows for the self-engine and eventbridge examples (start/register/drive pipeline/stop).
25
+
26
+ ### Changed
27
+ - **Dashboard component library updated**: `@treeui/vue` `^0.6.1` → `^0.10.0` (latest). No API changes required in the LSS components — `vue-tsc` and the Vite build pass unchanged.
28
+ - **Engine seam**: the LocalStack container lifecycle moved to `src/server/engine/backends/localstack-backend.ts`; `services/localstack-manager.ts` is now a thin facade over the new `EngineManager`, so the provisioner/explorers/seeds keep their imports and work against whichever engine is active (they always speak AWS SDK to `getConfig().endpoint`). Self-engine code is loaded via dynamic `import()` — LocalStack-mode memory footprint is unchanged.
29
+ - `lambdaRuntime.invokeHost` defaults to `127.0.0.1` in self-engine mode (nothing runs inside Docker); explicit config still wins.
30
+ - `GET /api/health` now includes an `engine: {kind, running, endpoint, ...}` block; the `localstack` boolean stays truthy when the active engine is healthy (client/UI compatibility).
31
+ - The root package version is now `0.8.0`. The `serverless-lss` plugin package was not changed.
32
+
33
+ ### Fixed
34
+ - **Branch-coverage gate restored to 100%**: closed the six uncovered branches left by the 0.7.0 EventBridge work (`cloudformation-parser.ts` — bus/rule with no `Properties`, rule with no `Targets`; `resource-provisioner.ts` — non-Error rejections in the event-rule pass and eventbus cleanup, `AddPermission` conflict/message-less fallbacks while wiring rule targets). `npm run test:coverage` passes again.
35
+
36
+ ### Tests
37
+ - ~700 new unit tests (1802 total, up from 1100): wire router/SigV4/aws-chunked, store WAL/compaction/hydration/LRU-budget, DynamoDB expression engine (223 assertions) + emulator core, SQS/S3/EventBridge/SNS/STS/lambda-ctl emulators, dispatcher loops/stream tailers/scheduler, self-backend boot; engine selection covered in `config-manager` and `cli` suites. End-to-end smoke with real AWS SDK v3 clients against a booted engine (CRUD/Query/GSI, queue lifecycle, binary S3 round trip, per-entry PutEvents, ESM hold, restart persistence).
38
+
39
+ ## [0.7.0] - 2026-07-10
40
+
41
+ EventBridge support: LSS can now provision the shared event bus and rule→Lambda triggers that previously required the last remaining `serverless deploy` (CloudFormation) step in local monorepo setups.
42
+
43
+ ### Added
44
+ - **`AWS::Events::EventBus` provisioning**: buses declared in the `resources:` section are created in LocalStack on registration (idempotent — re-registration tolerates an existing bus). `PutEvents` from handlers already worked via the SDK; the bus just had to exist.
45
+ - **`AWS::Events::Rule` triggers**: rules (event pattern or schedule, `ENABLED`/`DISABLED` state honored) are created on the declared bus and their Lambda targets wired through the same proxy model used by streams/SQS — EventBridge → proxy Lambda in LocalStack → LSS invoke API (130xx). Target `Input`/`InputPath` pass through; the bus is resolved from the template's logical ids, a literal name, or an ARN. Rules whose `EventBusName` can't be resolved from the template (e.g. `Fn::ImportValue`) are skipped with a warning instead of silently landing on the default bus.
46
+ - **Resources-only stacks**: a registered service that declares only `resources:` (no functions, no ports) provisions its resources without starting a runtime worker, gateway listeners or watcher — this already worked structurally since 0.5.0 gated those on declared functions/ports, and is now covered by tests for the EventBus-only infra-stack case.
47
+ - **Cleanup parity**: unregistering a service removes rule targets and rules first, then deletes its event buses.
48
+ - **Dashboard visibility**: EventBridge buses and rules show up in the service detail page (own sections) and as counters in the services list (`resourceBreakdown.buses`/`eventRules`), so a resources-only infra stack no longer renders as "N total" with an empty body.
49
+ - **Example `examples/eventbridge-sample`**: resources-only `events-stack` owning the shared bus (+ skipped Archive), a producer publishing `UserSignedUp` via `PutEvents`, and a consumer with an `events: eventBridge` trigger storing events in DynamoDB — registered with `sls package` only, no deploy. Its LocalStack runs on port `14566`, outside the standard 4566–4599 range, so a real LocalStack publishing that range (docker-compose defaults) can't intercept the example's `localhost` traffic on Docker Desktop/WSL2.
50
+
51
+ ### Fixed
52
+ - **EventBridge event shape through proxies**: the generated LocalStack proxy Lambda no longer wraps EventBridge events in a `Records` array — handlers receive `source`/`detail-type`/`detail` at the top level, exactly like on AWS. SQS/DynamoDB/SNS batches keep their `Records` shape. Proxies created by earlier versions keep the old code until recreated (only their `INVOKE_URL` is updated in place); delete the proxy function or reset LocalStack to pick up the fix.
53
+
54
+ ### Changed
55
+ - `AWS::Events::Archive` resources are accepted and skipped with a registration warning: LocalStack mocks Archives (CloudFormation reports `CREATE_COMPLETE` but `ListArchives` stays empty), so provisioning one locally would only fake success.
56
+ - `CloudFormationParser.parse()` accepts an optional warnings sink; the registrar forwards template-level warnings (like skipped Archives) to the registering client alongside state-file warnings.
57
+ - New runtime dependency: `@aws-sdk/client-eventbridge`.
58
+
59
+ ### Tests
60
+ - Parser coverage for `AWS::Events::EventBus`/`Rule`/`Archive` (bus name fallback, pattern/schedule/state, `Fn::ImportValue` flagging, literal-ARN targets, warning sink) and ResourceProvisioner coverage for bus creation, rule wiring (proxy reuse, permissions, default vs named vs literal bus), unresolvable-bus/unsupported-target skips, and cleanup ordering.
61
+
62
+ ## [0.6.0] - 2026-07-09
63
+
64
+ Corrections from integrating LSS 0.5.0 in a real monorepo using osls 4, serverless-esbuild ESM artifacts, HTTP API v2 authorizers, DynamoDB Streams, and Docker-in-Docker devcontainers.
65
+
66
+ ### Added
67
+ - **Configurable LocalStack proxy callback host**: `lambdaRuntime.invokeHost` and `LSS_INVOKE_HOST` now control the host used when generated LocalStack Lambda proxies call back into LSS's invoke listener. The default remains `host.docker.internal`; devcontainers/DinD can point it at the Docker network gateway (for example `172.19.0.1`).
68
+ - **Native TypeScript source loading when available**: in `source` mode, the runtime worker now tries Node's native TypeScript type stripping (`process.features.typescript`) before requiring `esbuild-register`, `tsx`, or `ts-node`.
69
+
70
+ ### Fixed
71
+ - **Artifact resolution for osls/serverless package output**: `package.artifact` values such as `s7-identity.zip` are now resolved relative to `.serverless/` as well as the service root, and nonexistent declared candidates no longer suppress the `.serverless/*.zip` scan fallback.
72
+ - **Stale LocalStack proxy `INVOKE_URL`**: re-registering a service now updates an existing proxy Lambda when the expected invoke URL changed (port renumbering or `invokeHost` changes).
73
+ - **Service identity collisions**: service registration now uses the `service:` name from `serverless-state.json` instead of the directory basename, with migration for same-root legacy cache entries.
74
+ - **Event source mapping fidelity**: CloudFormation `StartingPosition`, `MaximumRetryAttempts`, `FunctionResponseTypes`, `MaximumBatchingWindowInSeconds`, `FilterCriteria`, and `DestinationConfig.OnFailure` are parsed/applied where supported; duplicate checks compare the resolved live ARN instead of unresolved CFN refs.
75
+ - **DynamoDB table fidelity**: `StreamViewType` is preserved and `TimeToLiveSpecification` is applied after table creation or on re-registration, including disabled TTL declarations.
76
+ - **CLI stop/start race**: `lss stop` now waits for the orchestrator process to exit (with timeout) before returning, reducing immediate `lss start` failures from a still-bound port.
77
+
78
+ ### Changed
79
+ - The root package version is now `0.6.0`. The `serverless-lss` plugin package was not changed.
80
+
81
+ ### Tests
82
+ - Added/updated unit coverage for artifact resolution, Lambda runtime config env overrides, CloudFormation parsing, ResourceProvisioner proxy/TTL/event-source behavior, and the async CLI stop flow.
83
+
8
84
  ## [0.5.0] - 2026-07-08
9
85
 
10
86
  API Gateway & Lambda runtime emulation: LSS now registers every function and HTTP route a service declares, executes the handlers itself in per-service workers, and answers on the service's own API (30xx) and Lambda-invoke (130xx) ports — making `serverless-offline` optional. Monorepo callers and the LocalStack event proxies keep their ports and contracts unchanged; only the process answering changes.
package/README.md CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/local-serverless-stack.svg)](https://www.npmjs.com/package/local-serverless-stack)
4
4
 
5
- **Local control plane for serverless development with LocalStack orchestration**
5
+ **Local control plane for serverless development with its own in-process AWS engine (no Docker) or LocalStack orchestration**
6
6
 
7
- LSS provides a unified local development environment for serverless microservices, eliminating the need to run separate LocalStack instances for each service.
7
+ 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).
8
8
 
9
9
  ## Features
10
10
 
11
- - **Centralized LocalStack**: Single LocalStack instance manages DynamoDB, SQS, SNS, S3, and Lambda
12
- - **Auto-provisioning**: Parses CloudFormation templates from `sls package` and provisions resources automatically
13
- - **Event source mappings**: Automatically connects SQS queues to Lambda handlers via LocalStack
14
- - **Lambda proxies**: Generated proxy functions forward events to serverless-offline invoke endpoints
11
+ - **⚡ Self engine (the LSS differentiator)**: DynamoDB, SQS, S3, EventBridge, SNS and the Lambda control plane emulated **in-process** by the orchestrator — no Docker, no LocalStack, no auth token. Boots in milliseconds, stores data in local files, delivers events straight into your handlers. See [Self engine](#self-engine--no-docker-no-localstack-no-auth-token) below.
12
+ - **Centralized provisioning**: Parses CloudFormation templates from `sls package` and provisions resources automatically — into the self engine or a single shared LocalStack, your choice per instance
13
+ - **Event source mappings**: Automatically connects SQS queues, streams, S3 notifications and EventBridge rules to Lambda handlers
14
+ - **Lambda runtime & API emulation**: LSS answers on the same API (30xx) and Lambda invoke (130xx) ports that serverless-offline used
15
15
  - **Web UI**: Vue 3 dashboard to monitor services, resources, and event mappings
16
16
  - **Hot reload**: Watch for code changes and auto-rebuild/reprovision
17
17
  - **Process management**: Start/stop microservices from the orchestrator
@@ -19,6 +19,57 @@ LSS provides a unified local development environment for serverless microservice
19
19
 
20
20
  See [docs/FEATURES.md](docs/FEATURES.md) for the complete feature inventory and how each capability is tested.
21
21
 
22
+ ## Self engine — no Docker, no LocalStack, no auth token
23
+
24
+ LocalStack got heavy (a container eating 1 GB+ of RAM) and stopped being free by default
25
+ (community images `>= 2026.5` require an auth token). The **self engine** replaces it for
26
+ the typical serverless dev loop: the orchestrator itself serves the real AWS wire
27
+ protocols on one port, so your application code, the AWS SDK, the dashboard and `lss seed`
28
+ all work unchanged — there is simply no container underneath.
29
+
30
+ ```bash
31
+ npx lss start --self-engine # or "engine": "self" in lss.config.json
32
+ ```
33
+
34
+ ```
35
+ AWS_ENDPOINT=http://localhost:14566 # point your services here, done
36
+ ```
37
+
38
+ What you get:
39
+
40
+ - **DynamoDB** with the full expression language (KeyCondition/Filter/Update/Projection,
41
+ exact decimal arithmetic), GSIs/LSIs, TTL and streams — items persisted in local
42
+ JSONL files under `~/.lss/engine/`, hydrated lazily and unloaded when idle.
43
+ - **SQS** with FIFO, visibility redelivery and live counters; **S3** with byte-exact
44
+ object round trips and notifications; **EventBridge** with buses, pattern-filtered
45
+ rules and `rate()`/cron schedules; minimal **SNS** and **STS**.
46
+ - **Events delivered in-process**: SQS batches, DynamoDB streams, S3 notifications and
47
+ EventBridge targets go straight from the engine to the LSS Lambda runtime — no proxy
48
+ Lambdas, no polling containers.
49
+
50
+ ```mermaid
51
+ flowchart LR
52
+ APP[Your services<br/>AWS SDK → :14566] --> ENG
53
+ subgraph ORCH["One orchestrator process — no Docker"]
54
+ ENG[Self engine<br/>DynamoDB · SQS · S3<br/>EventBridge · SNS · STS]
55
+ ENG -->|in-process events| RT[LSS Lambda runtime<br/>your handlers, ports 30xx/130xx]
56
+ ENG --- FS[(local files<br/>~/.lss/engine)]
57
+ end
58
+ ```
59
+
60
+ Measured on [examples/self-engine-sample](examples/self-engine-sample/) (3 microservices:
61
+ orders → billing → notifications): engine boot **~10 ms**; a full pipeline crossing
62
+ DynamoDB + SQS + S3 + EventBridge across the three services completes in **~170 ms** —
63
+ with the whole stack being the orchestrator process plus one small worker per service.
64
+
65
+ Migration is gradual: LocalStack mode remains the default and fully supported; a running
66
+ instance picks one engine. Anything the self engine doesn't implement yet answers with an
67
+ explicit error naming the operation — or is forwarded verbatim to a LocalStack via
68
+ `selfEngine.fallbackEndpoint`. Coverage matrix and storage model:
69
+ [docs/SELF_ENGINE.md](docs/SELF_ENGINE.md) · design/PRD:
70
+ [docs/PRD_SELF_ENGINE.md](docs/PRD_SELF_ENGINE.md) · runnable demo:
71
+ [examples/self-engine-sample](examples/self-engine-sample/).
72
+
22
73
  ## Architecture
23
74
 
24
75
  ```
@@ -41,18 +92,18 @@ local-serverless-stack/
41
92
 
42
93
  **Components**:
43
94
  - **CLI** (`bin/cli.js`): Background process management (start/stop/status/logs)
44
- - **Server** (`src/server/`): Express API + LocalStack orchestration
95
+ - **Server** (`src/server/`): Express API + engine orchestration
96
+ - **Engine** (`src/server/engine/`): the AWS provider behind everything — either the in-process **self engine** (port 14566, no Docker) or a managed/external **LocalStack** container (port 4566)
45
97
  - **UI** (`src/ui/`): Vue 3 dashboard for monitoring
46
98
  - **Plugin** (`packages/serverless-plugin/`): Auto-registration for Serverless Framework
47
- - **LocalStack**: Docker container (port 4566) with AWS services
48
99
 
49
100
  ## Quick Start
50
101
 
51
102
  ### Prerequisites
52
103
 
53
- - Node.js >= 18
54
- - Docker (for LocalStack)
104
+ - Node.js >= 20
55
105
  - Serverless Framework 3.40.0
106
+ - Docker — **only for the LocalStack engine**; the self engine (`--self-engine`) needs none
56
107
 
57
108
  ### Installation
58
109
 
@@ -86,9 +137,12 @@ See the [plugin documentation](packages/serverless-plugin/README.md) for configu
86
137
  LSS provides a simple CLI to manage the orchestrator in background mode:
87
138
 
88
139
  ```bash
89
- # Start the orchestrator in background
140
+ # Start the orchestrator in background (managed LocalStack)
90
141
  npx lss start
91
142
 
143
+ # Start with the in-process self engine instead — no Docker
144
+ npx lss start --self-engine
145
+
92
146
  # Check if orchestrator is running
93
147
  npx lss status
94
148
 
@@ -105,6 +159,12 @@ npx lss help
105
159
  ### CLI Output
106
160
 
107
161
  ```bash
162
+ $ npx lss start --self-engine
163
+ 🚀 LSS Orchestrator started (PID: 12345)
164
+ 📊 Server: http://localhost:3100
165
+ 🔧 Self Engine: http://localhost:14566 (no Docker)
166
+ ✅ Service is running
167
+
108
168
  $ npx lss start
109
169
  🚀 LSS Orchestrator started (PID: 12345)
110
170
  📊 Dashboard: http://localhost:3100
@@ -178,19 +238,19 @@ npx lss start
178
238
  cd your-microservice
179
239
  npx sls package
180
240
 
181
- # 3. Start serverless offline
182
- npx serverless offline start --host 0.0.0.0 --httpPort 3020 --lambdaPort 13020
183
-
184
- # 4. Monitor in the dashboard
241
+ # 3. Monitor in the dashboard
185
242
  open http://localhost:3100
186
243
  ```
187
244
 
188
245
  Now when you send a message to an SQS queue in LocalStack, the orchestrator will:
189
246
  1. Detect the event via event source mapping
190
247
  2. Invoke the Lambda proxy in LocalStack
191
- 3. Proxy forwards to serverless-offline on the invoke port
248
+ 3. Proxy calls LSS's Lambda invoke listener on the service invoke port
192
249
  4. Your handler executes
193
250
 
251
+ If you still want serverless-offline to own the ports for a service, disable the
252
+ LSS runtime globally or per service with `lambdaRuntime.enabled`/`serviceRuntime`.
253
+
194
254
  ## Project Structure
195
255
 
196
256
  ```
@@ -214,13 +274,30 @@ local-serverless-stack/
214
274
  ### Environment Variables
215
275
 
216
276
  - `PORT`: Orchestrator API port (default: 3100)
277
+ - `LSS_ENGINE`: AWS engine — `localstack` (default) or `self` (in-process, no Docker)
278
+ - `LSS_ENGINE_PORT`: Self engine port (default: 14566)
217
279
  - `ENABLE_DYNAMO_PROXY`: Enable DynamoDB proxy on port 8000 (default: false)
218
280
  - `DYNAMO_PROXY_PORT`: DynamoDB proxy port (default: 8000)
219
281
 
282
+ ### Engine selection
283
+
284
+ ```jsonc
285
+ // lss.config.json
286
+ {
287
+ "engine": "self", // "localstack" (default) | "self"
288
+ "selfEngine": { "port": 14566 } // full reference: docs/SELF_ENGINE.md
289
+ }
290
+ ```
291
+
292
+ The self engine's default port sits **outside 4566–4599** on purpose: a real LocalStack
293
+ install intercepts that whole range on some hosts (Docker Desktop/WSL2). `--self-engine`
294
+ cannot be combined with the LocalStack-only flags (`--external`, `--pro`,
295
+ `--localstack-token`).
296
+
220
297
  ### LocalStack Settings
221
298
 
222
299
  LocalStack is configured with:
223
- - Services: `dynamodb,sqs,sns,s3,lambda`
300
+ - Services: `dynamodb,sqs,sns,s3,lambda,events`
224
301
  - Persistence: Enabled (volume: `lss-localstack-data`)
225
302
  - Lambda executor: `local` (no Docker-in-Docker required)
226
303
  - Docker socket: Mounted from host
@@ -479,6 +556,17 @@ sequenceDiagram
479
556
  - Response returned through proxy chain
480
557
  - Message deleted from queue on success, or sent to DLQ on failure
481
558
 
559
+ > **Self-engine mode collapses this whole chain**: the engine's event source mapping
560
+ > delivers the SQS batch **in-process** to the LSS Lambda runtime — no LocalStack
561
+ > polling, no proxy Lambda, no HTTP hop:
562
+ >
563
+ > ```
564
+ > LocalStack mode: SQS → LocalStack ESM → proxy Lambda (container) → HTTP → handler
565
+ > Self engine: SQS (engine) → dispatcher → handler
566
+ > ```
567
+ >
568
+ > The same applies to DynamoDB streams, S3 notifications and EventBridge targets.
569
+
482
570
  ## CLI Implementation Details
483
571
 
484
572
  The `npx lss` CLI is implemented in `/bin/cli.js` and provides:
package/bin/cli.js CHANGED
@@ -96,6 +96,8 @@ function getConfig(config) {
96
96
  localstackImage: config.localstackImage,
97
97
  localstackAuthToken: config.localstackAuthToken,
98
98
  stateDir: config.stateDir,
99
+ engine: config.engine || 'localstack',
100
+ selfEnginePort: (config.selfEngine && config.selfEngine.port) || 14566,
99
101
  };
100
102
  }
101
103
 
@@ -150,7 +152,11 @@ function startOrchestrator() {
150
152
  const cfg = getConfig(config);
151
153
  console.log('✅ LSS Orchestrator already running (PID:', pid + ')');
152
154
  console.log(`📊 Server: http://localhost:${cfg.serverPort}`);
153
- console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort}`);
155
+ if (cfg.engine === 'self') {
156
+ console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort}`);
157
+ } else {
158
+ console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort}`);
159
+ }
154
160
  if (cfg.enableDynamoProxy) {
155
161
  console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`);
156
162
  }
@@ -183,6 +189,13 @@ function startOrchestrator() {
183
189
  const useExternal = process.argv.includes('--external');
184
190
  const usePro = process.argv.includes('--pro');
185
191
  const cliToken = getArgValue('--localstack-token');
192
+ const useSelfEngine = process.argv.includes('--self-engine');
193
+
194
+ const engine = useSelfEngine ? 'self' : cfg.engine;
195
+ if (engine === 'self' && (useExternal || usePro || cliToken)) {
196
+ console.error('❌ --self-engine cannot be combined with --external, --pro or --localstack-token (those are LocalStack options).');
197
+ process.exit(1);
198
+ }
186
199
 
187
200
  const mode = useExternal ? 'external' : cfg.mode;
188
201
  const edition = usePro ? 'pro' : cfg.localstackEdition;
@@ -223,6 +236,9 @@ function startOrchestrator() {
223
236
  if (authToken) {
224
237
  env.LOCALSTACK_AUTH_TOKEN = authToken;
225
238
  }
239
+ if (engine === 'self') {
240
+ env.LSS_ENGINE = 'self';
241
+ }
226
242
  // Hand the same config file to the server so its ConfigManager reads the
227
243
  // identical serverPort/localstackPort/seedsDir/region/mode (not just the
228
244
  // hand-translated subset above). Keeps the two config loaders in agreement.
@@ -243,7 +259,11 @@ function startOrchestrator() {
243
259
 
244
260
  console.log('🚀 LSS Orchestrator started (PID:', child.pid + ')');
245
261
  console.log(`📊 Server: http://localhost:${cfg.serverPort}`);
246
- console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort} (mode: ${mode}, edition: ${edition})`);
262
+ if (engine === 'self') {
263
+ console.log(`🔧 Self Engine: http://localhost:${cfg.selfEnginePort} (no Docker)`);
264
+ } else {
265
+ console.log(`🔧 LocalStack: http://localhost:${cfg.localstackPort} (mode: ${mode}, edition: ${edition})`);
266
+ }
247
267
  if (enableDynamoProxy) {
248
268
  console.log(`🔄 DynamoDB Proxy: http://localhost:${cfg.dynamoProxyPort} (enabled)`);
249
269
  }
@@ -262,7 +282,40 @@ function startOrchestrator() {
262
282
  }, 2000);
263
283
  }
264
284
 
265
- function stopOrchestrator() {
285
+ // Poll kill(pid, 0) until the process is gone. SIGTERM alone isn't enough to
286
+ // return from `stop`: an immediate `lss start` would race the dying orchestrator
287
+ // for the server port and crash with EADDRINUSE.
288
+ function waitForExit(pid, timeoutMs = 10000, intervalMs = 200) {
289
+ return new Promise(resolve => {
290
+ const deadline = Date.now() + timeoutMs;
291
+ let timer;
292
+ let done = false;
293
+ const finish = (value) => {
294
+ done = true;
295
+ if (timer) clearInterval(timer);
296
+ resolve(value);
297
+ };
298
+ const check = () => {
299
+ try {
300
+ process.kill(pid, 0);
301
+ } catch (e) {
302
+ finish(true);
303
+ return;
304
+ }
305
+ if (Date.now() >= deadline) {
306
+ finish(false);
307
+ }
308
+ };
309
+ // Fast path: the process is often already gone — check synchronously so
310
+ // `stop` resolves without ever scheduling (and leaking) an interval.
311
+ check();
312
+ if (!done) {
313
+ timer = setInterval(check, intervalMs);
314
+ }
315
+ });
316
+ }
317
+
318
+ async function stopOrchestrator() {
266
319
  const { pidFile } = runtimePaths();
267
320
  if (!fs.existsSync(pidFile)) {
268
321
  console.log('⚠️ LSS Orchestrator is not running');
@@ -273,13 +326,20 @@ function stopOrchestrator() {
273
326
 
274
327
  try {
275
328
  process.kill(pid, 'SIGTERM');
276
- fs.unlinkSync(pidFile);
277
- console.log('🛑 LSS Orchestrator stopped (PID:', pid + ')');
278
329
  } catch (e) {
279
330
  console.error('❌ Failed to stop process:', e.message);
280
331
  if (fs.existsSync(pidFile)) {
281
332
  fs.unlinkSync(pidFile);
282
333
  }
334
+ return;
335
+ }
336
+
337
+ const exited = await waitForExit(pid);
338
+ fs.unlinkSync(pidFile);
339
+ if (exited) {
340
+ console.log('🛑 LSS Orchestrator stopped (PID:', pid + ')');
341
+ } else {
342
+ console.warn(`⚠️ Process ${pid} did not exit within 10s of SIGTERM — the server port may still be busy. Check \`lss status\` before starting again.`);
283
343
  }
284
344
  }
285
345
 
@@ -598,6 +658,7 @@ Options:
598
658
  Applies to start/stop/status/logs so an isolated instance
599
659
  can be addressed without cd-ing into its folder.
600
660
  --enable-dynamo-proxy Enable DynamoDB proxy on port 8000 (for start command)
661
+ --self-engine Use the in-process AWS engine instead of LocalStack (no Docker)
601
662
  --external Connect to a LocalStack already running, do not spawn a container
602
663
  --pro Use the LocalStack Pro image (requires LOCALSTACK_AUTH_TOKEN)
603
664
  --localstack-token <token> Pass a LOCALSTACK_AUTH_TOKEN to the container
@@ -637,6 +698,7 @@ Configuration:
637
698
 
638
699
  Examples:
639
700
  npx lss start # Start the orchestrator (managed LocalStack)
701
+ npx lss start --self-engine # Use the in-process engine (no Docker, port 14566)
640
702
  npx lss start --enable-dynamo-proxy # Start with DynamoDB proxy enabled
641
703
  npx lss start --external # Connect to an external LocalStack
642
704
  npx lss start --pro # Use LocalStack Pro (token required)
@@ -687,6 +749,7 @@ module.exports = {
687
749
  getArgValue,
688
750
  runtimePaths,
689
751
  getOrchestratorPath,
752
+ waitForExit,
690
753
  formatError,
691
754
  buildHttpError,
692
755
  firstPositional,
@@ -0,0 +1,25 @@
1
+ import type { EngineBackend } from '../engine-backend.js';
2
+ export declare class LocalStackBackend implements EngineBackend {
3
+ readonly kind: "localstack";
4
+ private process;
5
+ private _isRunning;
6
+ private endpoint;
7
+ private readonly containerName;
8
+ private readonly configManager;
9
+ constructor();
10
+ start(): Promise<void>;
11
+ stop(): Promise<void>;
12
+ private waitForReady;
13
+ isRunning(): boolean;
14
+ getEndpoint(): string;
15
+ getConfig(): {
16
+ endpoint: string;
17
+ region: string;
18
+ credentials: {
19
+ accessKeyId: string;
20
+ secretAccessKey: string;
21
+ };
22
+ };
23
+ healthDetail(): Record<string, unknown>;
24
+ }
25
+ //# sourceMappingURL=localstack-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localstack-backend.d.ts","sourceRoot":"","sources":["../../../../src/server/engine/backends/localstack-backend.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,qBAAa,iBAAkB,YAAW,aAAa;IACrD,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IACtC,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAS;IAKzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;;IASxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+HtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAwBb,YAAY;IAmB1B,SAAS,IAAI,OAAO;IAIpB,WAAW,IAAI,MAAM;IAIrB,SAAS;;;;;;;;IAWT,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQxC"}