local-serverless-stack 0.1.2 → 0.3.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 +29 -1
- package/README.md +6 -4
- package/bin/cli.js +126 -35
- package/dist/client/config-discovery.d.ts +10 -0
- package/dist/client/config-discovery.d.ts.map +1 -0
- package/dist/client/config-discovery.js +63 -0
- package/dist/client/config-discovery.js.map +1 -0
- package/dist/client/http.d.ts +32 -0
- package/dist/client/http.d.ts.map +1 -0
- package/dist/client/http.js +124 -0
- package/dist/client/http.js.map +1 -0
- package/dist/client/index.d.ts +40 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +59 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/lifecycle.d.ts +53 -0
- package/dist/client/lifecycle.d.ts.map +1 -0
- package/dist/client/lifecycle.js +97 -0
- package/dist/client/lifecycle.js.map +1 -0
- package/dist/client/namespaces/buckets.d.ts +19 -0
- package/dist/client/namespaces/buckets.d.ts.map +1 -0
- package/dist/client/namespaces/buckets.js +26 -0
- package/dist/client/namespaces/buckets.js.map +1 -0
- package/dist/client/namespaces/config.d.ts +7 -0
- package/dist/client/namespaces/config.d.ts.map +1 -0
- package/dist/client/namespaces/config.js +9 -0
- package/dist/client/namespaces/config.js.map +1 -0
- package/dist/client/namespaces/dynamo.d.ts +23 -0
- package/dist/client/namespaces/dynamo.d.ts.map +1 -0
- package/dist/client/namespaces/dynamo.js +22 -0
- package/dist/client/namespaces/dynamo.js.map +1 -0
- package/dist/client/namespaces/health.d.ts +8 -0
- package/dist/client/namespaces/health.d.ts.map +1 -0
- package/dist/client/namespaces/health.js +9 -0
- package/dist/client/namespaces/health.js.map +1 -0
- package/dist/client/namespaces/queues.d.ts +26 -0
- package/dist/client/namespaces/queues.d.ts.map +1 -0
- package/dist/client/namespaces/queues.js +28 -0
- package/dist/client/namespaces/queues.js.map +1 -0
- package/dist/client/namespaces/resources.d.ts +10 -0
- package/dist/client/namespaces/resources.d.ts.map +1 -0
- package/dist/client/namespaces/resources.js +11 -0
- package/dist/client/namespaces/resources.js.map +1 -0
- package/dist/client/namespaces/seeds.d.ts +16 -0
- package/dist/client/namespaces/seeds.d.ts.map +1 -0
- package/dist/client/namespaces/seeds.js +18 -0
- package/dist/client/namespaces/seeds.js.map +1 -0
- package/dist/client/namespaces/services.d.ts +27 -0
- package/dist/client/namespaces/services.d.ts.map +1 -0
- package/dist/client/namespaces/services.js +17 -0
- package/dist/client/namespaces/services.js.map +1 -0
- package/dist/client/types.d.ts +236 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +10 -0
- package/dist/client/types.js.map +1 -0
- package/dist/server/dev/dynamo-proxy.d.ts.map +1 -1
- package/dist/server/dev/dynamo-proxy.js +4 -0
- package/dist/server/dev/dynamo-proxy.js.map +1 -1
- package/dist/server/routes/queues.d.ts.map +1 -1
- package/dist/server/routes/queues.js +81 -0
- package/dist/server/routes/queues.js.map +1 -1
- package/dist/server/services/config-manager.d.ts +2 -0
- package/dist/server/services/config-manager.d.ts.map +1 -1
- package/dist/server/services/config-manager.js +10 -0
- package/dist/server/services/config-manager.js.map +1 -1
- package/dist/server/services/queue-inspector.d.ts +68 -0
- package/dist/server/services/queue-inspector.d.ts.map +1 -1
- package/dist/server/services/queue-inspector.js +182 -4
- package/dist/server/services/queue-inspector.js.map +1 -1
- package/dist/server/services/resource-provisioner.d.ts.map +1 -1
- package/dist/server/services/resource-provisioner.js +1 -0
- package/dist/server/services/resource-provisioner.js.map +1 -1
- package/package.json +28 -9
- package/packages/serverless-plugin/README.md +4 -4
- package/packages/serverless-plugin/dist/index.js +7 -0
- package/packages/serverless-plugin/dist/index.js.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ 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.3.0] - 2026-06-06
|
|
9
|
+
|
|
10
|
+
Programmatic client (`LssClient`) so downstream Jest e2e suites can drive everything the `lss` CLI does at runtime via `import`, instead of shelling out to `npx lss` per step.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Programmatic client `LssClient`** (`import { LssClient } from 'local-serverless-stack'`): everything the `lss` CLI/orchestrator exposes, callable from Jest at runtime instead of spawning `npx lss` per step. The data-plane is a thin typed HTTP wrapper over the orchestrator's `/api/*` endpoints, grouped into namespaces — `seeds` (`run`/`clear`/`list`), `queues` (incl. `awaitIdle`, `hold`/`captured`/`release`, `send`/`receive`/`purge`), `dynamo` (tables/scan/query/item CRUD/TTL), `buckets` (S3 list/objects/`getObject` as a `Buffer`/put/delete), `resources`, `services`, `config`, `health` — plus a `request()` escape hatch. `lifecycle` (`start`/`stop`/`status`/`logs`) shells out to the battle-tested `bin/cli.js` (so PID/`stateDir` logic is reused, not duplicated), and `lifecycle.waitUntilReady()` polls `GET /api/health` until LocalStack is actually up (the CLI returns before that). The constructor resolves its target from options → env (`LSS_CONFIG`, `LSS_BASE_URL`, `LSS_SERVER_PORT`, `AWS_REGION`) → `lss.config.json`/`.lssrc`, so `new LssClient()` works purely from the environment or `new LssClient({ configPath })` from an explicit file. Quirks handled for callers: `queues.awaitIdle` resolves on both `200` (drained) and `408` (timeout) rather than throwing, and `buckets.getObject` returns the raw binary body. Errors throw an `LssHttpError` carrying `{ status, statusText, body, path }` and the orchestrator's own `{error|message}`.
|
|
14
|
+
- **Package now ships a library entry point**: added `main`/`types`/`exports` to `package.json` pointing at a self-contained CommonJS build at `dist/client` (mirrors the `serverless-lss` plugin's CJS build so consumers on CJS or ESM can `import`/`require` it). New `client:build` (`tsc --project src/client/tsconfig.json`) wired into `npm run build`. Importable as `local-serverless-stack` or `local-serverless-stack/client`.
|
|
15
|
+
|
|
16
|
+
### Tests
|
|
17
|
+
- **100% coverage extended to `src/client/**`**: stub-HTTP-server unit tests assert every namespace method maps to the right route/query/body and cover the full error-mapping matrix (`{error}`/`{message}`/snippet/empty/over-long/non-JSON, timeout, connection refused); lifecycle is driven against a fake CLI fixture (`tests/fixtures/fake-cli.js`) via the `LSS_CLI_PATH` seam plus `waitUntilReady` polling. The integration suite (`features.test.ts`) gained a "programmatic client" block that drives the same isolated instance through `LssClient` end-to-end.
|
|
18
|
+
|
|
19
|
+
## [0.2.0] - 2026-06-04
|
|
20
|
+
|
|
21
|
+
Testability features for downstream e2e suites: an isolated test instance and a deterministic queue-drain wait. Plugin `serverless-lss` bumped to `0.1.0` (it gained `LSS_DASHBOARD_PORT` support — install both).
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **`--config <path>` flag for `start|stop|status|logs`**: loads config from the given file, taking precedence over the cwd/home search (`lss.config.json` / `.lssrc`). A missing or unparseable explicit file warns and falls back to the search rather than hard-exiting, so `stop`/`status`/`logs` never orphan a running instance. `bin/cli.js` resolves the path to absolute once per invocation (also accepted via the `LSS_CONFIG` env var) and hands it to the spawned server as `LSS_CONFIG_PATH`, so the orchestrator's `ConfigManager` reads the identical file — keeping the two config loaders in agreement on port/seedsDir/region/mode.
|
|
25
|
+
- **`stateDir` config field**: directory where an instance keeps its PID/log (the PID file doubles as the lock). When set (e.g. `".lss-e2e"`), `runtimePaths()` places state there so an isolated instance — typically an e2e test stack started with `--config` — can be started and stopped without ever touching the dev instance. When omitted, behavior is unchanged: PID/log live in the OS temp dir scoped by `serverPort`. `ConfigManager` gained the field plus a `getStateDir()` getter (resolved relative to the working directory).
|
|
26
|
+
- **`POST /api/queues/:name/await-idle`**: blocking endpoint that polls a queue's counters (forcing a fresh read every ~250 ms rather than waiting on the 5 s background poller) and resolves `200 { queue, available, inFlight, processed, drained: true }` once the queue is idle (`available === 0 && inFlight === 0`, and `processed >= sinceProcessed` when that body field is supplied), or `408 { …, drained: false }` on timeout. Body: `{ timeoutMs?: number = 15000 (clamped 100–120000), sinceProcessed?: number }`. Lets a test deterministically wait for an SQS consumer to drain before asserting persistence. Accepts the logical queue name (e.g. `activity-save.fifo`).
|
|
27
|
+
- **Queue hold/intercept primitives** (`POST /api/queues/:name/hold`, `GET /api/queues/:name/captured`, `POST /api/queues/:name/release`): `hold` disables the queue's consumer event source mapping(s) (`UpdateEventSourceMapping Enabled: false`) and starts capturing; `captured` drains the queue into an in-memory buffer and returns `[{ messageId, body, attributes, messageAttributes, receivedAt }]`; `release` re-enables the mapping(s) and re-dispatches the captured messages. Lets a test assert a producer's enqueued payload without running the consumer. Best-effort: hold state is in-memory (lost on restart), messages already consumed before hold can't be recalled, and LocalStack applies the `Enabled` toggle asynchronously.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- **`serverless-lss` plugin honors `LSS_DASHBOARD_PORT`**: when set (and `ORCHESTRATOR_URL` is not), the plugin registers the service at `http://localhost:${LSS_DASHBOARD_PORT}`. Precedence is `ORCHESTRATOR_URL` (full URL) > `LSS_DASHBOARD_PORT` (port) > `custom.orchestrator.orchestratorUrl` > default `http://localhost:3100`. This lets the same `serverless.yml` register against an isolated test orchestrator at runtime without editing the file.
|
|
31
|
+
|
|
32
|
+
### Tests
|
|
33
|
+
- **Two separated test types**: `npm run test:unit` (default `npm test`) is hermetic, runs in CI, and enforces a **100% coverage gate** (statements/branches/functions/lines) over the unit-testable server code — `src/server/services/**` (except the Docker-driven `localstack-manager.ts`), `src/server/routes/**`, `src/server/dev/**`, `packages/serverless-plugin/src/**` and `bin/cli.js` (`index.ts` is excluded as it bootstraps the server at import). `npm run test:integration` boots a real isolated LSS + LocalStack and validates the promised features end-to-end. Added `aws-sdk-client-mock` + `supertest` as dev deps; split `tests/setup.ts` into shared matchers + per-type setup; `bin/cli.js` now guards its dispatch behind `require.main === module` and exports its helpers for in-process testing. ~750 unit tests.
|
|
34
|
+
- **`docs/FEATURES.md`**: a single inventory of the project's promised features (CLI, HTTP API, resource provisioning, plugin, seeds, queue primitives, config/isolation), doubling as the integration suite's checklist. The integration suite provisions `examples/sample-microservice` and asserts each capability; it runs locally and in a CI job gated on a `LOCALSTACK_AUTH_TOKEN` secret.
|
|
35
|
+
|
|
8
36
|
## [0.1.2] - 2026-05-26
|
|
9
37
|
|
|
10
38
|
### Added
|
|
@@ -328,7 +356,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
328
356
|
- Requires Docker for LocalStack
|
|
329
357
|
- Tested on Linux (Ubuntu/Debian)
|
|
330
358
|
- Node.js >= 18 required
|
|
331
|
-
- Serverless Framework
|
|
359
|
+
- Serverless Framework 3.40.0 required
|
|
332
360
|
|
|
333
361
|
### Breaking Changes
|
|
334
362
|
None (initial release)
|
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ LSS provides a unified local development environment for serverless microservice
|
|
|
17
17
|
- **Process management**: Start/stop microservices from the orchestrator
|
|
18
18
|
- **CLI Tool**: Simple commands to manage the orchestrator (start/stop/status/logs)
|
|
19
19
|
|
|
20
|
+
See [docs/FEATURES.md](docs/FEATURES.md) for the complete feature inventory and how each capability is tested.
|
|
21
|
+
|
|
20
22
|
## Architecture
|
|
21
23
|
|
|
22
24
|
```
|
|
@@ -50,7 +52,7 @@ local-serverless-stack/
|
|
|
50
52
|
|
|
51
53
|
- Node.js >= 18
|
|
52
54
|
- Docker (for LocalStack)
|
|
53
|
-
- Serverless Framework
|
|
55
|
+
- Serverless Framework 3.40.0
|
|
54
56
|
|
|
55
57
|
### Installation
|
|
56
58
|
|
|
@@ -74,7 +76,7 @@ The `npm link` command makes the `lss` CLI available globally via `npx`.
|
|
|
74
76
|
To automatically register your microservices with LSS, install the Serverless plugin:
|
|
75
77
|
|
|
76
78
|
```bash
|
|
77
|
-
npm install --save-dev
|
|
79
|
+
npm install --save-dev serverless-lss
|
|
78
80
|
```
|
|
79
81
|
|
|
80
82
|
See the [plugin documentation](packages/serverless-plugin/README.md) for configuration details.
|
|
@@ -146,7 +148,7 @@ npm link local-serverless-stack
|
|
|
146
148
|
In each microservice directory:
|
|
147
149
|
|
|
148
150
|
```bash
|
|
149
|
-
npm link
|
|
151
|
+
npm link serverless-lss
|
|
150
152
|
```
|
|
151
153
|
|
|
152
154
|
### 3. Configure serverless.yml
|
|
@@ -159,7 +161,7 @@ plugins:
|
|
|
159
161
|
- serverless-esbuild
|
|
160
162
|
- serverless-offline
|
|
161
163
|
- serverless-localstack
|
|
162
|
-
-
|
|
164
|
+
- serverless-lss # Add this line
|
|
163
165
|
|
|
164
166
|
custom:
|
|
165
167
|
orchestrator:
|
package/bin/cli.js
CHANGED
|
@@ -11,10 +11,24 @@ const os = require('os');
|
|
|
11
11
|
const DEFAULT_PID_FILE = path.join(os.tmpdir(), 'lss-orchestrator.pid');
|
|
12
12
|
const DEFAULT_LOG_FILE = path.join(os.tmpdir(), 'lss-orchestrator.log');
|
|
13
13
|
|
|
14
|
-
// PID/log file paths
|
|
15
|
-
//
|
|
14
|
+
// PID/log file paths for the instance addressed by this invocation.
|
|
15
|
+
// - When the config provides a `stateDir`, PID/log live inside it. This gives
|
|
16
|
+
// an explicitly isolated instance (e.g. an e2e test stack) its own state so
|
|
17
|
+
// `lss stop --config <path>` targets it and never the dev instance.
|
|
18
|
+
// - Otherwise the paths are scoped to the cwd's serverPort, so multiple
|
|
19
|
+
// examples sitting in different folders don't trample each other.
|
|
16
20
|
function runtimePaths() {
|
|
17
21
|
const cfg = getConfig(loadConfig());
|
|
22
|
+
|
|
23
|
+
if (cfg.stateDir) {
|
|
24
|
+
const dir = path.resolve(process.cwd(), cfg.stateDir);
|
|
25
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
26
|
+
return {
|
|
27
|
+
pidFile: path.join(dir, 'orchestrator.pid'),
|
|
28
|
+
logFile: path.join(dir, 'orchestrator.log'),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
18
32
|
const port = cfg.serverPort;
|
|
19
33
|
// Keep the legacy global path when the default port is in use so existing
|
|
20
34
|
// installations don't lose their running process across an upgrade.
|
|
@@ -28,9 +42,24 @@ function runtimePaths() {
|
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
/**
|
|
31
|
-
* Load configuration
|
|
45
|
+
* Load configuration. An explicit `--config <path>` (or LSS_CONFIG env) wins over
|
|
46
|
+
* the cwd/home search so an isolated instance can point at its own config file.
|
|
47
|
+
* A missing or unparseable explicit file warns and falls back to the search,
|
|
48
|
+
* rather than hard-exiting, so stop/status/logs never orphan a running instance.
|
|
32
49
|
*/
|
|
33
50
|
function loadConfig() {
|
|
51
|
+
if (EXPLICIT_CONFIG) {
|
|
52
|
+
if (fs.existsSync(EXPLICIT_CONFIG)) {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(fs.readFileSync(EXPLICIT_CONFIG, 'utf-8'));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.warn(`⚠️ Failed to parse config file ${EXPLICIT_CONFIG}`);
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
console.warn(`⚠️ Config file not found: ${EXPLICIT_CONFIG}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
34
63
|
const candidates = [
|
|
35
64
|
path.join(process.cwd(), 'lss.config.json'),
|
|
36
65
|
path.join(process.cwd(), '.lssrc'),
|
|
@@ -66,6 +95,7 @@ function getConfig(config) {
|
|
|
66
95
|
localstackVersion: config.localstackVersion || 'latest',
|
|
67
96
|
localstackImage: config.localstackImage,
|
|
68
97
|
localstackAuthToken: config.localstackAuthToken,
|
|
98
|
+
stateDir: config.stateDir,
|
|
69
99
|
};
|
|
70
100
|
}
|
|
71
101
|
|
|
@@ -79,6 +109,15 @@ function getArgValue(name) {
|
|
|
79
109
|
return inline ? inline.slice(prefix.length) : undefined;
|
|
80
110
|
}
|
|
81
111
|
|
|
112
|
+
// Resolved once per invocation: an explicit config file from `--config <path>`
|
|
113
|
+
// (or the LSS_CONFIG env var), resolved to an absolute path so it's found
|
|
114
|
+
// regardless of cwd. Every argument-less loadConfig() call honors it because
|
|
115
|
+
// process.argv is fixed for the lifetime of the invocation.
|
|
116
|
+
const EXPLICIT_CONFIG = (() => {
|
|
117
|
+
const v = getArgValue('--config') || process.env.LSS_CONFIG;
|
|
118
|
+
return v ? path.resolve(v) : undefined;
|
|
119
|
+
})();
|
|
120
|
+
|
|
82
121
|
// Resolve orchestrator path - works both in development and when installed via npm
|
|
83
122
|
function getOrchestratorPath() {
|
|
84
123
|
// Try to find the orchestrator relative to this script
|
|
@@ -151,24 +190,30 @@ function startOrchestrator() {
|
|
|
151
190
|
|
|
152
191
|
// Build environment variables from config
|
|
153
192
|
const env = { ...process.env };
|
|
193
|
+
/* istanbul ignore else: getConfig() always defaults serverPort to 3100, so the else is unreachable */
|
|
154
194
|
if (cfg.serverPort) {
|
|
155
195
|
env.PORT = cfg.serverPort;
|
|
156
196
|
}
|
|
197
|
+
/* istanbul ignore else: getConfig() always defaults localstackPort to 4566, so the else is unreachable */
|
|
157
198
|
if (cfg.localstackPort) {
|
|
158
199
|
env.LSS_LOCALSTACK_PORT = cfg.localstackPort;
|
|
159
200
|
}
|
|
160
201
|
if (enableDynamoProxy) {
|
|
161
202
|
env.LSS_ENABLE_DYNAMO_PROXY = 'true';
|
|
162
203
|
}
|
|
204
|
+
/* istanbul ignore else: getConfig() always defaults dynamoProxyPort to 8000, so the else is unreachable */
|
|
163
205
|
if (cfg.dynamoProxyPort) {
|
|
164
206
|
env.LSS_DYNAMO_PROXY_PORT = cfg.dynamoProxyPort;
|
|
165
207
|
}
|
|
208
|
+
/* istanbul ignore else: mode resolves to cfg.mode which getConfig() defaults to 'managed', so the else is unreachable */
|
|
166
209
|
if (mode) {
|
|
167
210
|
env.LSS_LOCALSTACK_MODE = mode;
|
|
168
211
|
}
|
|
212
|
+
/* istanbul ignore else: edition resolves to localstackEdition which getConfig() defaults to 'community', so the else is unreachable */
|
|
169
213
|
if (edition) {
|
|
170
214
|
env.LSS_LOCALSTACK_EDITION = edition;
|
|
171
215
|
}
|
|
216
|
+
/* istanbul ignore else: getConfig() always defaults localstackVersion to 'latest', so the else is unreachable */
|
|
172
217
|
if (cfg.localstackVersion) {
|
|
173
218
|
env.LSS_LOCALSTACK_VERSION = cfg.localstackVersion;
|
|
174
219
|
}
|
|
@@ -178,7 +223,13 @@ function startOrchestrator() {
|
|
|
178
223
|
if (authToken) {
|
|
179
224
|
env.LOCALSTACK_AUTH_TOKEN = authToken;
|
|
180
225
|
}
|
|
181
|
-
|
|
226
|
+
// Hand the same config file to the server so its ConfigManager reads the
|
|
227
|
+
// identical serverPort/localstackPort/seedsDir/region/mode (not just the
|
|
228
|
+
// hand-translated subset above). Keeps the two config loaders in agreement.
|
|
229
|
+
if (EXPLICIT_CONFIG) {
|
|
230
|
+
env.LSS_CONFIG_PATH = EXPLICIT_CONFIG;
|
|
231
|
+
}
|
|
232
|
+
|
|
182
233
|
const child = spawn('node', [orchestratorPath], {
|
|
183
234
|
detached: true,
|
|
184
235
|
stdio: ['ignore', logFd, logFd],
|
|
@@ -543,6 +594,9 @@ Commands:
|
|
|
543
594
|
help Show this help message
|
|
544
595
|
|
|
545
596
|
Options:
|
|
597
|
+
--config <path> Load config from this file (precedes the cwd/home search).
|
|
598
|
+
Applies to start/stop/status/logs so an isolated instance
|
|
599
|
+
can be addressed without cd-ing into its folder.
|
|
546
600
|
--enable-dynamo-proxy Enable DynamoDB proxy on port 8000 (for start command)
|
|
547
601
|
--external Connect to a LocalStack already running, do not spawn a container
|
|
548
602
|
--pro Use the LocalStack Pro image (requires LOCALSTACK_AUTH_TOKEN)
|
|
@@ -567,9 +621,14 @@ Configuration:
|
|
|
567
621
|
"region": "us-east-1",
|
|
568
622
|
"services": ["dynamodb", "sqs", "sns", "lambda"],
|
|
569
623
|
"persistence": true,
|
|
570
|
-
"debug": false
|
|
624
|
+
"debug": false,
|
|
625
|
+
"stateDir": ".lss"
|
|
571
626
|
}
|
|
572
627
|
|
|
628
|
+
stateDir (optional): directory for this instance's PID/log files. Set it (e.g.
|
|
629
|
+
".lss-e2e") together with --config to run a fully isolated instance alongside
|
|
630
|
+
the dev one. When omitted, PID/log live in the OS temp dir scoped by serverPort.
|
|
631
|
+
|
|
573
632
|
For the Serverless Plugin, add to serverless.yml:
|
|
574
633
|
custom:
|
|
575
634
|
orchestrator:
|
|
@@ -607,8 +666,6 @@ function showLogs() {
|
|
|
607
666
|
console.log(lastLines);
|
|
608
667
|
}
|
|
609
668
|
|
|
610
|
-
const command = process.argv[2];
|
|
611
|
-
|
|
612
669
|
// First positional arg after the command (e.g. table name for `seed`/`seed:clear`).
|
|
613
670
|
// Skip anything that looks like a flag so `seed:clear --yes` doesn't pass
|
|
614
671
|
// "--yes" as the table name.
|
|
@@ -620,32 +677,66 @@ function firstPositional() {
|
|
|
620
677
|
return undefined;
|
|
621
678
|
}
|
|
622
679
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
680
|
+
// Exported so the pure/in-process helpers can be unit-tested by requiring this
|
|
681
|
+
// module. The command dispatch below only runs when the file is executed
|
|
682
|
+
// directly (the `lss` bin), never when required, so requiring it has no side
|
|
683
|
+
// effects.
|
|
684
|
+
module.exports = {
|
|
685
|
+
loadConfig,
|
|
686
|
+
getConfig,
|
|
687
|
+
getArgValue,
|
|
688
|
+
runtimePaths,
|
|
689
|
+
getOrchestratorPath,
|
|
690
|
+
formatError,
|
|
691
|
+
buildHttpError,
|
|
692
|
+
firstPositional,
|
|
693
|
+
getServerPort,
|
|
694
|
+
printSeedRunResults,
|
|
695
|
+
printSeedMismatchDiagnostic,
|
|
696
|
+
printSeedClearResults,
|
|
697
|
+
getJson,
|
|
698
|
+
postJson,
|
|
699
|
+
ensureRunningOrExit,
|
|
700
|
+
promptConfirmation,
|
|
701
|
+
startOrchestrator,
|
|
702
|
+
stopOrchestrator,
|
|
703
|
+
showStatus,
|
|
704
|
+
showLogs,
|
|
705
|
+
runSeed,
|
|
706
|
+
clearSeed,
|
|
707
|
+
showHelp,
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
/* istanbul ignore next: CLI dispatch runs only when executed directly, not when required in tests */
|
|
711
|
+
if (require.main === module) {
|
|
712
|
+
const command = process.argv[2];
|
|
713
|
+
switch (command) {
|
|
714
|
+
case 'start':
|
|
715
|
+
startOrchestrator();
|
|
716
|
+
break;
|
|
717
|
+
case 'stop':
|
|
718
|
+
stopOrchestrator();
|
|
719
|
+
break;
|
|
720
|
+
case 'status':
|
|
721
|
+
showStatus();
|
|
722
|
+
break;
|
|
723
|
+
case 'logs':
|
|
724
|
+
showLogs();
|
|
725
|
+
break;
|
|
726
|
+
case 'seed':
|
|
727
|
+
runSeed(firstPositional());
|
|
728
|
+
break;
|
|
729
|
+
case 'seed:clear':
|
|
730
|
+
clearSeed(firstPositional());
|
|
731
|
+
break;
|
|
732
|
+
case 'help':
|
|
733
|
+
case '--help':
|
|
734
|
+
case '-h':
|
|
735
|
+
showHelp();
|
|
736
|
+
break;
|
|
737
|
+
default:
|
|
738
|
+
console.log('❌ Unknown command:', command);
|
|
739
|
+
showHelp();
|
|
740
|
+
process.exit(1);
|
|
741
|
+
}
|
|
651
742
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LssClientOptions } from './types';
|
|
2
|
+
export interface ResolvedConfig {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
region?: string;
|
|
5
|
+
configPath?: string;
|
|
6
|
+
cwd: string;
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveConfig(options?: LssClientOptions): ResolvedConfig;
|
|
10
|
+
//# sourceMappingURL=config-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-discovery.d.ts","sourceRoot":"","sources":["../../src/client/config-discovery.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AA6CD,wBAAgB,aAAa,CAAC,OAAO,GAAE,gBAAqB,GAAG,cAAc,CAO5E"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Resolves where the orchestrator lives (baseUrl) and the default region, from
|
|
3
|
+
// explicit options → environment → config file → defaults. Mirrors the CLI's
|
|
4
|
+
// port handling (bin/cli.js getServerPort / getConfig) but honors the client's
|
|
5
|
+
// own configPath/cwd instead of process.argv, which the CLI freezes at load.
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.resolveConfig = resolveConfig;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const DEFAULT_PORT = 3100;
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 15000;
|
|
15
|
+
function stripTrailingSlash(url) {
|
|
16
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
17
|
+
}
|
|
18
|
+
function readServerPortFromConfig(configPath, cwd) {
|
|
19
|
+
const candidates = configPath
|
|
20
|
+
? [path_1.default.resolve(cwd, configPath)]
|
|
21
|
+
: [path_1.default.join(cwd, 'lss.config.json'), path_1.default.join(cwd, '.lssrc')];
|
|
22
|
+
for (const candidate of candidates) {
|
|
23
|
+
try {
|
|
24
|
+
if (fs_1.default.existsSync(candidate)) {
|
|
25
|
+
const cfg = JSON.parse(fs_1.default.readFileSync(candidate, 'utf-8'));
|
|
26
|
+
if (typeof cfg.serverPort === 'number')
|
|
27
|
+
return cfg.serverPort;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Unreadable/invalid config — fall through to the next candidate / default.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return DEFAULT_PORT;
|
|
35
|
+
}
|
|
36
|
+
function resolveBaseUrl(options, configPath, cwd) {
|
|
37
|
+
if (options.baseUrl)
|
|
38
|
+
return stripTrailingSlash(options.baseUrl);
|
|
39
|
+
if (process.env.LSS_BASE_URL)
|
|
40
|
+
return stripTrailingSlash(process.env.LSS_BASE_URL);
|
|
41
|
+
const host = options.host ?? 'localhost';
|
|
42
|
+
let port = options.port;
|
|
43
|
+
if (port === undefined && process.env.LSS_SERVER_PORT) {
|
|
44
|
+
// Strict parse + validation: a non-numeric/zero/negative env value falls
|
|
45
|
+
// through to the config file / default rather than yielding "http://host:NaN".
|
|
46
|
+
const parsed = Number(process.env.LSS_SERVER_PORT);
|
|
47
|
+
if (Number.isInteger(parsed) && parsed > 0)
|
|
48
|
+
port = parsed;
|
|
49
|
+
}
|
|
50
|
+
if (port === undefined) {
|
|
51
|
+
port = readServerPortFromConfig(configPath, cwd);
|
|
52
|
+
}
|
|
53
|
+
return `http://${host}:${port}`;
|
|
54
|
+
}
|
|
55
|
+
function resolveConfig(options = {}) {
|
|
56
|
+
const cwd = options.cwd ?? process.cwd();
|
|
57
|
+
const configPath = options.configPath ?? process.env.LSS_CONFIG ?? undefined;
|
|
58
|
+
const region = options.region ?? process.env.AWS_REGION ?? undefined;
|
|
59
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
60
|
+
const baseUrl = resolveBaseUrl(options, configPath, cwd);
|
|
61
|
+
return { baseUrl, region, configPath, cwd, timeoutMs };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=config-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-discovery.js","sourceRoot":"","sources":["../../src/client/config-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare class LssHttpError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly statusText: string;
|
|
4
|
+
readonly body?: string;
|
|
5
|
+
readonly path: string;
|
|
6
|
+
constructor(message: string, info: {
|
|
7
|
+
status: number;
|
|
8
|
+
statusText: string;
|
|
9
|
+
body?: string;
|
|
10
|
+
path: string;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export type QueryValue = string | number | boolean | undefined;
|
|
14
|
+
export interface RequestOptions {
|
|
15
|
+
body?: unknown;
|
|
16
|
+
query?: Record<string, QueryValue>;
|
|
17
|
+
/** Status codes treated as success in addition to 2xx (e.g. await-idle's 408). */
|
|
18
|
+
okStatuses?: number[];
|
|
19
|
+
}
|
|
20
|
+
export interface RequestContext {
|
|
21
|
+
baseUrl: string;
|
|
22
|
+
timeoutMs: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class Http {
|
|
25
|
+
private readonly ctx;
|
|
26
|
+
constructor(ctx: RequestContext);
|
|
27
|
+
/** Request expecting a JSON response (or an empty body on success). */
|
|
28
|
+
json<T>(method: string, path: string, opts?: RequestOptions): Promise<T>;
|
|
29
|
+
/** Request expecting a raw binary body (e.g. S3 object content). */
|
|
30
|
+
raw(method: string, path: string, opts: RequestOptions): Promise<Buffer>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"AAKA,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAQvG;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAiFD,qBAAa,IAAI;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,cAAc;IAEhD,uEAAuE;IACjE,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IASlF,oEAAoE;IAC9D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;CAQ/E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Minimal HTTP layer for the LSS client. Talks to the orchestrator's `/api/*`
|
|
3
|
+
// endpoints over `fetch` (Node >=18). The error mapping mirrors the CLI's
|
|
4
|
+
// buildHttpError/formatError (bin/cli.js) so failures carry the orchestrator's
|
|
5
|
+
// own `{error|message}` instead of an opaque status.
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Http = exports.LssHttpError = void 0;
|
|
8
|
+
class LssHttpError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
statusText;
|
|
11
|
+
body;
|
|
12
|
+
path;
|
|
13
|
+
constructor(message, info) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'LssHttpError';
|
|
16
|
+
this.status = info.status;
|
|
17
|
+
this.statusText = info.statusText;
|
|
18
|
+
this.body = info.body;
|
|
19
|
+
this.path = info.path;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.LssHttpError = LssHttpError;
|
|
23
|
+
/* istanbul ignore next -- defensive: only runs on connection failure, where the error's message shape varies by runtime */
|
|
24
|
+
function reason(err) {
|
|
25
|
+
return err instanceof Error && err.message ? err.message : String(err);
|
|
26
|
+
}
|
|
27
|
+
function buildQuery(query) {
|
|
28
|
+
if (!query)
|
|
29
|
+
return '';
|
|
30
|
+
const parts = [];
|
|
31
|
+
for (const [key, value] of Object.entries(query)) {
|
|
32
|
+
if (value === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
35
|
+
}
|
|
36
|
+
return parts.length ? `?${parts.join('&')}` : '';
|
|
37
|
+
}
|
|
38
|
+
function isOk(status, okStatuses) {
|
|
39
|
+
// okStatuses is ADDITIVE to the 2xx range, not a replacement — so passing
|
|
40
|
+
// e.g. [408] still treats a normal 200 as success.
|
|
41
|
+
if (status >= 200 && status < 300)
|
|
42
|
+
return true;
|
|
43
|
+
return okStatuses ? okStatuses.includes(status) : false;
|
|
44
|
+
}
|
|
45
|
+
function httpError(status, statusText, data, path) {
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = data ? JSON.parse(data) : {};
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
parsed = null;
|
|
52
|
+
}
|
|
53
|
+
const fromBody = parsed && (parsed.error || parsed.message);
|
|
54
|
+
const label = statusText ? `${status} ${statusText}` : `${status}`;
|
|
55
|
+
let message;
|
|
56
|
+
if (fromBody && String(fromBody).trim()) {
|
|
57
|
+
message = String(fromBody).trim();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const snippet = data && data.length < 300 ? data.trim() : '';
|
|
61
|
+
message = snippet ? `HTTP ${label}: ${snippet}` : `HTTP ${label} (no error body)`;
|
|
62
|
+
}
|
|
63
|
+
return new LssHttpError(message, { status, statusText, body: data, path });
|
|
64
|
+
}
|
|
65
|
+
async function doFetch(ctx, method, path, opts) {
|
|
66
|
+
const url = ctx.baseUrl + path + buildQuery(opts.query);
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const timer = setTimeout(() => controller.abort(), ctx.timeoutMs);
|
|
69
|
+
const hasBody = opts.body !== undefined;
|
|
70
|
+
try {
|
|
71
|
+
return await fetch(url, {
|
|
72
|
+
method,
|
|
73
|
+
headers: hasBody ? { 'Content-Type': 'application/json' } : undefined,
|
|
74
|
+
body: hasBody ? JSON.stringify(opts.body) : undefined,
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
// An aborted fetch rejects with a DOMException named 'AbortError' (not always
|
|
80
|
+
// an Error subclass across Node versions), so match on the name directly.
|
|
81
|
+
const name = err.name;
|
|
82
|
+
if (name === 'AbortError') {
|
|
83
|
+
throw new LssHttpError(`request to ${path} timed out after ${ctx.timeoutMs}ms`, {
|
|
84
|
+
status: 0,
|
|
85
|
+
statusText: 'timeout',
|
|
86
|
+
path,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
throw new LssHttpError(`could not connect to orchestrator at ${ctx.baseUrl}: ${reason(err)}`, {
|
|
90
|
+
status: 0,
|
|
91
|
+
statusText: 'connection_error',
|
|
92
|
+
path,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
class Http {
|
|
100
|
+
ctx;
|
|
101
|
+
constructor(ctx) {
|
|
102
|
+
this.ctx = ctx;
|
|
103
|
+
}
|
|
104
|
+
/** Request expecting a JSON response (or an empty body on success). */
|
|
105
|
+
async json(method, path, opts = {}) {
|
|
106
|
+
const res = await doFetch(this.ctx, method, path, opts);
|
|
107
|
+
const text = await res.text();
|
|
108
|
+
if (!isOk(res.status, opts.okStatuses)) {
|
|
109
|
+
throw httpError(res.status, res.statusText, text, path);
|
|
110
|
+
}
|
|
111
|
+
return (text ? JSON.parse(text) : {});
|
|
112
|
+
}
|
|
113
|
+
/** Request expecting a raw binary body (e.g. S3 object content). */
|
|
114
|
+
async raw(method, path, opts) {
|
|
115
|
+
const res = await doFetch(this.ctx, method, path, opts);
|
|
116
|
+
if (!isOk(res.status, opts.okStatuses)) {
|
|
117
|
+
const text = await res.text();
|
|
118
|
+
throw httpError(res.status, res.statusText, text, path);
|
|
119
|
+
}
|
|
120
|
+
return Buffer.from(await res.arrayBuffer());
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.Http = Http;
|
|
124
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type QueryValue } from './http';
|
|
2
|
+
import { type LifecycleApi } from './lifecycle';
|
|
3
|
+
import { type SeedsApi } from './namespaces/seeds';
|
|
4
|
+
import { type QueuesApi } from './namespaces/queues';
|
|
5
|
+
import { type DynamoApi } from './namespaces/dynamo';
|
|
6
|
+
import { type BucketsApi } from './namespaces/buckets';
|
|
7
|
+
import { type ResourcesApi } from './namespaces/resources';
|
|
8
|
+
import { type ServicesApi } from './namespaces/services';
|
|
9
|
+
import { type ConfigApi } from './namespaces/config';
|
|
10
|
+
import { type HealthApi } from './namespaces/health';
|
|
11
|
+
import type { LssClientOptions } from './types';
|
|
12
|
+
export declare class LssClient {
|
|
13
|
+
/** Resolved base URL the data-plane talks to. */
|
|
14
|
+
readonly baseUrl: string;
|
|
15
|
+
readonly seeds: SeedsApi;
|
|
16
|
+
readonly queues: QueuesApi;
|
|
17
|
+
readonly dynamo: DynamoApi;
|
|
18
|
+
readonly buckets: BucketsApi;
|
|
19
|
+
readonly resources: ResourcesApi;
|
|
20
|
+
readonly services: ServicesApi;
|
|
21
|
+
readonly config: ConfigApi;
|
|
22
|
+
readonly health: HealthApi;
|
|
23
|
+
readonly lifecycle: LifecycleApi;
|
|
24
|
+
private readonly http;
|
|
25
|
+
constructor(options?: LssClientOptions);
|
|
26
|
+
/** Escape hatch for an arbitrary orchestrator call not covered by a namespace. */
|
|
27
|
+
request<T = unknown>(method: string, path: string, body?: unknown, query?: Record<string, QueryValue>): Promise<T>;
|
|
28
|
+
}
|
|
29
|
+
export { LssHttpError } from './http';
|
|
30
|
+
export type { SeedsApi } from './namespaces/seeds';
|
|
31
|
+
export type { QueuesApi } from './namespaces/queues';
|
|
32
|
+
export type { DynamoApi } from './namespaces/dynamo';
|
|
33
|
+
export type { BucketsApi } from './namespaces/buckets';
|
|
34
|
+
export type { ResourcesApi } from './namespaces/resources';
|
|
35
|
+
export type { ServicesApi } from './namespaces/services';
|
|
36
|
+
export type { ConfigApi } from './namespaces/config';
|
|
37
|
+
export type { HealthApi } from './namespaces/health';
|
|
38
|
+
export type { LifecycleApi, StartOptions, StartResult, StopResult, StatusResult, LogsResult, WaitUntilReadyOptions, } from './lifecycle';
|
|
39
|
+
export type * from './types';
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,SAAS;IACpB,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IAEjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;gBAEhB,OAAO,GAAE,gBAAqB;IAgB1C,kFAAkF;IAClF,OAAO,CAAC,CAAC,GAAG,OAAO,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GACjC,OAAO,CAAC,CAAC,CAAC;CAGd;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,YAAY,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,mBAAmB,SAAS,CAAC"}
|