local-serverless-stack 0.0.10 → 0.0.11

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 CHANGED
@@ -5,7 +5,17 @@ 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.0.9] - 2026-05-18
8
+ ## [0.0.11] - 2026-05-18
9
+
10
+ ### Added
11
+ - **DynamoDB explorer**: new "DynamoDB" tab inspired by the AWS Console. Lists every table with key schema, item count, billing mode, TTL/Streams status and per-table warnings (e.g. "TTL not configured"). Clicking a table opens a detail view with three sub-tabs.
12
+ - **Explore items (Scan / Query)**: visual filter builder with attribute / operator / value rows (operators: `=`, `<>`, `<`, `<=`, `>`, `>=`, `begins_with`, `contains`, `attribute_exists`, `attribute_not_exists`). Values are auto-typed (number/boolean/null/JSON). Supports running on the table or any GSI/LSI, configurable limit, and "Load more" pagination via `LastEvaluatedKey`. Query mode requires key conditions (up to PK + SK) and reuses the same builder.
13
+ - **Item CRUD**: per-row "View", "Edit" and "Delete" actions, plus a "Create item" button. Items are edited as plain JSON in a modal with format/validate. Edit performs a `PutItem` (full-replace); if any key attribute changed during edit, the original row is deleted first so it behaves like an update instead of producing a duplicate.
14
+ - **Indexes sub-tab**: lists GSIs and LSIs with their key schema, projection type, item count and status.
15
+ - **Settings sub-tab**: TTL toggle (`UpdateTimeToLive`), Streams view, table identifier (ARN + creation date), item count and size.
16
+ - **`/api/dynamo` endpoints**: `GET /tables`, `GET /tables/:name`, `GET/PUT /tables/:name/ttl`, `POST /tables/:name/scan`, `POST /tables/:name/query`, `POST /tables/:name/items` (PutItem), `POST /tables/:name/items/get` (GetItem), `POST /tables/:name/items/delete`. Items and keys cross the wire as plain JSON — the server `marshall`s/`unmarshall`s.
17
+
18
+ ## [0.0.10] - 2026-05-18
9
19
 
10
20
  ### Added
11
21
  - **DynamoDB seeding**: drop `{tableName}.json` files into the directory configured by the new `seedsDir` option (default `./seeds`) and items get marshalled and inserted into the matching DynamoDB table. Items are written as plain JSON (no AWS attribute-typed envelope) — `@aws-sdk/util-dynamodb`'s `marshall` infers types automatically.
@@ -6,6 +6,7 @@ import { servicesRouter, processManager } from './routes/services.js';
6
6
  import { resourcesRouter } from './routes/resources.js';
7
7
  import { queuesRouter } from './routes/queues.js';
8
8
  import { seedsRouter } from './routes/seeds.js';
9
+ import { dynamoRouter } from './routes/dynamo.js';
9
10
  import { LocalStackManager } from './services/localstack-manager.js';
10
11
  import { ConfigManager } from './services/config-manager.js';
11
12
  import { QueueInspector } from './services/queue-inspector.js';
@@ -23,6 +24,7 @@ app.use('/api/services', servicesRouter);
23
24
  app.use('/api/resources', resourcesRouter);
24
25
  app.use('/api/queues', queuesRouter);
25
26
  app.use('/api/seeds', seedsRouter);
27
+ app.use('/api/dynamo', dynamoRouter);
26
28
  // Health check
27
29
  app.get('/api/health', (_req, res) => {
28
30
  res.json({
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export { router as dynamoRouter };
3
+ //# sourceMappingURL=dynamo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamo.d.ts","sourceRoot":"","sources":["../../../src/server/routes/dynamo.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA6HxB,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,CAAC"}
@@ -0,0 +1,135 @@
1
+ import { Router } from 'express';
2
+ import { DynamoExplorer } from '../services/dynamo-explorer.js';
3
+ const router = Router();
4
+ const explorer = DynamoExplorer.getInstance();
5
+ function isValidName(name) {
6
+ return (typeof name === 'string' &&
7
+ name.length > 0 &&
8
+ name.length <= 255 &&
9
+ !name.includes('/') &&
10
+ !name.includes('..') &&
11
+ !name.includes('\\'));
12
+ }
13
+ function fail(res, error, status = 500) {
14
+ const message = error instanceof Error ? error.message : 'Unknown error';
15
+ return res.status(status).json({ error: message });
16
+ }
17
+ router.get('/tables', async (_req, res) => {
18
+ try {
19
+ const tables = await explorer.listTables();
20
+ res.json({ tables });
21
+ }
22
+ catch (error) {
23
+ fail(res, error);
24
+ }
25
+ });
26
+ router.get('/tables/:name', async (req, res) => {
27
+ const { name } = req.params;
28
+ if (!isValidName(name))
29
+ return fail(res, new Error('Invalid table name'), 400);
30
+ try {
31
+ const detail = await explorer.describeTable(name);
32
+ if (!detail)
33
+ return res.status(404).json({ error: 'Table not found' });
34
+ return res.json(detail);
35
+ }
36
+ catch (error) {
37
+ return fail(res, error);
38
+ }
39
+ });
40
+ router.get('/tables/:name/ttl', async (req, res) => {
41
+ const { name } = req.params;
42
+ if (!isValidName(name))
43
+ return fail(res, new Error('Invalid table name'), 400);
44
+ try {
45
+ return res.json(await explorer.describeTtl(name));
46
+ }
47
+ catch (error) {
48
+ return fail(res, error);
49
+ }
50
+ });
51
+ router.put('/tables/:name/ttl', async (req, res) => {
52
+ const { name } = req.params;
53
+ if (!isValidName(name))
54
+ return fail(res, new Error('Invalid table name'), 400);
55
+ const { enabled, attributeName } = req.body ?? {};
56
+ if (typeof enabled !== 'boolean') {
57
+ return fail(res, new Error('enabled (boolean) is required'), 400);
58
+ }
59
+ try {
60
+ return res.json(await explorer.setTtl(name, enabled, attributeName));
61
+ }
62
+ catch (error) {
63
+ return fail(res, error, 400);
64
+ }
65
+ });
66
+ router.post('/tables/:name/scan', async (req, res) => {
67
+ const { name } = req.params;
68
+ if (!isValidName(name))
69
+ return fail(res, new Error('Invalid table name'), 400);
70
+ try {
71
+ return res.json(await explorer.scan(name, req.body ?? {}));
72
+ }
73
+ catch (error) {
74
+ return fail(res, error, 400);
75
+ }
76
+ });
77
+ router.post('/tables/:name/query', async (req, res) => {
78
+ const { name } = req.params;
79
+ if (!isValidName(name))
80
+ return fail(res, new Error('Invalid table name'), 400);
81
+ try {
82
+ return res.json(await explorer.query(name, req.body ?? {}));
83
+ }
84
+ catch (error) {
85
+ return fail(res, error, 400);
86
+ }
87
+ });
88
+ router.post('/tables/:name/items/get', async (req, res) => {
89
+ const { name } = req.params;
90
+ if (!isValidName(name))
91
+ return fail(res, new Error('Invalid table name'), 400);
92
+ const { key } = req.body ?? {};
93
+ if (!key || typeof key !== 'object')
94
+ return fail(res, new Error('key is required'), 400);
95
+ try {
96
+ const item = await explorer.getItem(name, key);
97
+ return res.json({ item });
98
+ }
99
+ catch (error) {
100
+ return fail(res, error);
101
+ }
102
+ });
103
+ router.post('/tables/:name/items', async (req, res) => {
104
+ const { name } = req.params;
105
+ if (!isValidName(name))
106
+ return fail(res, new Error('Invalid table name'), 400);
107
+ const { item } = req.body ?? {};
108
+ if (!item || typeof item !== 'object' || Array.isArray(item)) {
109
+ return fail(res, new Error('item must be a plain object'), 400);
110
+ }
111
+ try {
112
+ await explorer.putItem(name, item);
113
+ return res.json({ success: true });
114
+ }
115
+ catch (error) {
116
+ return fail(res, error, 400);
117
+ }
118
+ });
119
+ router.post('/tables/:name/items/delete', async (req, res) => {
120
+ const { name } = req.params;
121
+ if (!isValidName(name))
122
+ return fail(res, new Error('Invalid table name'), 400);
123
+ const { key } = req.body ?? {};
124
+ if (!key || typeof key !== 'object')
125
+ return fail(res, new Error('key is required'), 400);
126
+ try {
127
+ await explorer.deleteItem(name, key);
128
+ return res.json({ success: true });
129
+ }
130
+ catch (error) {
131
+ return fail(res, error, 400);
132
+ }
133
+ });
134
+ export { router as dynamoRouter };
135
+ //# sourceMappingURL=dynamo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamo.js","sourceRoot":"","sources":["../../../src/server/routes/dynamo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { type KeySchemaElement, type AttributeDefinition, type GlobalSecondaryIndexDescription, type LocalSecondaryIndexDescription } from '@aws-sdk/client-dynamodb';
2
+ export interface TtlInfo {
3
+ enabled: boolean;
4
+ attributeName?: string;
5
+ }
6
+ export interface DynamoTableSummary {
7
+ name: string;
8
+ status?: string;
9
+ itemCount: number;
10
+ sizeBytes: number;
11
+ keySchema: KeySchemaElement[];
12
+ attributeDefinitions: AttributeDefinition[];
13
+ hasGsi: boolean;
14
+ hasLsi: boolean;
15
+ streamEnabled: boolean;
16
+ ttl: TtlInfo;
17
+ billingMode?: string;
18
+ createdAt?: string;
19
+ warnings: string[];
20
+ }
21
+ export interface DynamoTableDetail extends DynamoTableSummary {
22
+ arn?: string;
23
+ gsis: GlobalSecondaryIndexDescription[];
24
+ lsis: LocalSecondaryIndexDescription[];
25
+ streamArn?: string;
26
+ streamViewType?: string;
27
+ }
28
+ export interface ScanQueryInput {
29
+ filterExpression?: string;
30
+ keyConditionExpression?: string;
31
+ projectionExpression?: string;
32
+ expressionAttributeNames?: Record<string, string>;
33
+ expressionAttributeValues?: Record<string, unknown>;
34
+ indexName?: string;
35
+ limit?: number;
36
+ exclusiveStartKey?: Record<string, unknown>;
37
+ scanIndexForward?: boolean;
38
+ }
39
+ export interface ScanQueryOutput {
40
+ items: Record<string, unknown>[];
41
+ count: number;
42
+ scannedCount?: number;
43
+ lastEvaluatedKey?: Record<string, unknown>;
44
+ }
45
+ export declare class DynamoExplorer {
46
+ private static instance;
47
+ private client;
48
+ private currentRegion;
49
+ private constructor();
50
+ static getInstance(): DynamoExplorer;
51
+ private init;
52
+ setRegion(region: string): void;
53
+ listTables(): Promise<DynamoTableSummary[]>;
54
+ private summarize;
55
+ describeTable(name: string): Promise<DynamoTableDetail | null>;
56
+ describeTtl(name: string): Promise<TtlInfo>;
57
+ setTtl(name: string, enabled: boolean, attributeName?: string): Promise<TtlInfo>;
58
+ scan(name: string, input: ScanQueryInput): Promise<ScanQueryOutput>;
59
+ query(name: string, input: ScanQueryInput): Promise<ScanQueryOutput>;
60
+ getItem(name: string, key: Record<string, unknown>): Promise<Record<string, unknown> | null>;
61
+ putItem(name: string, item: Record<string, unknown>): Promise<void>;
62
+ deleteItem(name: string, key: Record<string, unknown>): Promise<void>;
63
+ private marshallExpressionValues;
64
+ private formatPagedOutput;
65
+ }
66
+ //# sourceMappingURL=dynamo-explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamo-explorer.d.ts","sourceRoot":"","sources":["../../../src/server/services/dynamo-explorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,189 @@
1
+ import { DynamoDBClient, ListTablesCommand, DescribeTableCommand, DescribeTimeToLiveCommand, UpdateTimeToLiveCommand, ScanCommand, QueryCommand, GetItemCommand, PutItemCommand, DeleteItemCommand, } from '@aws-sdk/client-dynamodb';
2
+ import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
3
+ import { LocalStackManager } from './localstack-manager.js';
4
+ export class DynamoExplorer {
5
+ static instance;
6
+ client;
7
+ currentRegion = 'us-east-1';
8
+ constructor() {
9
+ this.init(this.currentRegion);
10
+ }
11
+ static getInstance() {
12
+ if (!DynamoExplorer.instance)
13
+ DynamoExplorer.instance = new DynamoExplorer();
14
+ return DynamoExplorer.instance;
15
+ }
16
+ init(region) {
17
+ const baseConfig = LocalStackManager.getInstance().getConfig();
18
+ this.client = new DynamoDBClient({ ...baseConfig, region });
19
+ this.currentRegion = region;
20
+ }
21
+ setRegion(region) {
22
+ if (region && region !== this.currentRegion)
23
+ this.init(region);
24
+ }
25
+ async listTables() {
26
+ const list = await this.client.send(new ListTablesCommand({}));
27
+ const names = list.TableNames ?? [];
28
+ const summaries = await Promise.all(names.map(name => this.summarize(name)));
29
+ return summaries.filter((s) => s !== null);
30
+ }
31
+ async summarize(name) {
32
+ try {
33
+ const [desc, ttl] = await Promise.all([
34
+ this.client.send(new DescribeTableCommand({ TableName: name })),
35
+ this.describeTtl(name),
36
+ ]);
37
+ const table = desc.Table;
38
+ if (!table)
39
+ return null;
40
+ const warnings = [];
41
+ if (!ttl.enabled)
42
+ warnings.push('TTL not configured');
43
+ return {
44
+ name,
45
+ status: table.TableStatus,
46
+ itemCount: table.ItemCount ?? 0,
47
+ sizeBytes: table.TableSizeBytes ?? 0,
48
+ keySchema: table.KeySchema ?? [],
49
+ attributeDefinitions: table.AttributeDefinitions ?? [],
50
+ hasGsi: (table.GlobalSecondaryIndexes ?? []).length > 0,
51
+ hasLsi: (table.LocalSecondaryIndexes ?? []).length > 0,
52
+ streamEnabled: Boolean(table.StreamSpecification?.StreamEnabled),
53
+ ttl,
54
+ billingMode: table.BillingModeSummary?.BillingMode ?? 'PROVISIONED',
55
+ createdAt: table.CreationDateTime?.toISOString(),
56
+ warnings,
57
+ };
58
+ }
59
+ catch (error) {
60
+ const msg = error instanceof Error ? error.message : 'unknown error';
61
+ console.warn(`[dynamo] failed to describe ${name}: ${msg}`);
62
+ return null;
63
+ }
64
+ }
65
+ async describeTable(name) {
66
+ const summary = await this.summarize(name);
67
+ if (!summary)
68
+ return null;
69
+ const desc = await this.client.send(new DescribeTableCommand({ TableName: name }));
70
+ const table = desc.Table;
71
+ return {
72
+ ...summary,
73
+ arn: table.TableArn,
74
+ gsis: table.GlobalSecondaryIndexes ?? [],
75
+ lsis: table.LocalSecondaryIndexes ?? [],
76
+ streamArn: table.LatestStreamArn,
77
+ streamViewType: table.StreamSpecification?.StreamViewType,
78
+ };
79
+ }
80
+ async describeTtl(name) {
81
+ try {
82
+ const res = await this.client.send(new DescribeTimeToLiveCommand({ TableName: name }));
83
+ const desc = res.TimeToLiveDescription;
84
+ const status = desc?.TimeToLiveStatus;
85
+ const enabled = status === 'ENABLED' || status === 'ENABLING';
86
+ return { enabled, attributeName: desc?.AttributeName };
87
+ }
88
+ catch {
89
+ return { enabled: false };
90
+ }
91
+ }
92
+ async setTtl(name, enabled, attributeName) {
93
+ if (enabled && !attributeName) {
94
+ throw new Error('attributeName is required when enabling TTL');
95
+ }
96
+ const current = await this.describeTtl(name);
97
+ // UpdateTimeToLive requires the attribute name even when disabling — pass the current one.
98
+ const attr = enabled ? attributeName : current.attributeName ?? attributeName ?? 'ttl';
99
+ await this.client.send(new UpdateTimeToLiveCommand({
100
+ TableName: name,
101
+ TimeToLiveSpecification: { Enabled: enabled, AttributeName: attr },
102
+ }));
103
+ return { enabled, attributeName: attr };
104
+ }
105
+ async scan(name, input) {
106
+ const eav = this.marshallExpressionValues(input.expressionAttributeValues);
107
+ const esk = input.exclusiveStartKey
108
+ ? marshall(input.exclusiveStartKey, { removeUndefinedValues: true })
109
+ : undefined;
110
+ const res = await this.client.send(new ScanCommand({
111
+ TableName: name,
112
+ FilterExpression: input.filterExpression || undefined,
113
+ ProjectionExpression: input.projectionExpression || undefined,
114
+ ExpressionAttributeNames: input.expressionAttributeNames,
115
+ ExpressionAttributeValues: eav,
116
+ IndexName: input.indexName || undefined,
117
+ Limit: input.limit,
118
+ ExclusiveStartKey: esk,
119
+ }));
120
+ return this.formatPagedOutput(res);
121
+ }
122
+ async query(name, input) {
123
+ if (!input.keyConditionExpression) {
124
+ throw new Error('keyConditionExpression is required for query');
125
+ }
126
+ const eav = this.marshallExpressionValues(input.expressionAttributeValues);
127
+ const esk = input.exclusiveStartKey
128
+ ? marshall(input.exclusiveStartKey, { removeUndefinedValues: true })
129
+ : undefined;
130
+ const res = await this.client.send(new QueryCommand({
131
+ TableName: name,
132
+ KeyConditionExpression: input.keyConditionExpression,
133
+ FilterExpression: input.filterExpression || undefined,
134
+ ProjectionExpression: input.projectionExpression || undefined,
135
+ ExpressionAttributeNames: input.expressionAttributeNames,
136
+ ExpressionAttributeValues: eav,
137
+ IndexName: input.indexName || undefined,
138
+ Limit: input.limit,
139
+ ExclusiveStartKey: esk,
140
+ ScanIndexForward: input.scanIndexForward,
141
+ }));
142
+ return this.formatPagedOutput(res);
143
+ }
144
+ async getItem(name, key) {
145
+ const res = await this.client.send(new GetItemCommand({
146
+ TableName: name,
147
+ Key: marshall(key, { removeUndefinedValues: true }),
148
+ }));
149
+ return res.Item ? unmarshall(res.Item) : null;
150
+ }
151
+ async putItem(name, item) {
152
+ if (!item || typeof item !== 'object') {
153
+ throw new Error('Item must be a plain object');
154
+ }
155
+ await this.client.send(new PutItemCommand({
156
+ TableName: name,
157
+ Item: marshall(item, {
158
+ removeUndefinedValues: true,
159
+ convertClassInstanceToMap: true,
160
+ }),
161
+ }));
162
+ }
163
+ async deleteItem(name, key) {
164
+ await this.client.send(new DeleteItemCommand({
165
+ TableName: name,
166
+ Key: marshall(key, { removeUndefinedValues: true }),
167
+ }));
168
+ }
169
+ marshallExpressionValues(values) {
170
+ if (!values || Object.keys(values).length === 0)
171
+ return undefined;
172
+ // marshall expects a plain object — each value is marshalled to AttributeValue individually.
173
+ const out = {};
174
+ for (const [placeholder, v] of Object.entries(values)) {
175
+ const wrapped = marshall({ v }, { removeUndefinedValues: true });
176
+ out[placeholder] = wrapped.v;
177
+ }
178
+ return out;
179
+ }
180
+ formatPagedOutput(res) {
181
+ return {
182
+ items: (res.Items ?? []).map(item => unmarshall(item)),
183
+ count: res.Count ?? 0,
184
+ scannedCount: res.ScannedCount,
185
+ lastEvaluatedKey: res.LastEvaluatedKey ? unmarshall(res.LastEvaluatedKey) : undefined,
186
+ };
187
+ }
188
+ }
189
+ //# sourceMappingURL=dynamo-explorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamo-explorer.js","sourceRoot":"","sources":["../../../src/server/services/dynamo-explorer.ts"],"names":[],"mappings":"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"}