local-serverless-stack 0.6.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.
- package/CHANGELOG.md +54 -0
- package/README.md +99 -11
- package/bin/cli.js +31 -3
- package/dist/server/engine/backends/localstack-backend.d.ts +25 -0
- package/dist/server/engine/backends/localstack-backend.d.ts.map +1 -0
- package/dist/server/engine/backends/localstack-backend.js +199 -0
- package/dist/server/engine/backends/localstack-backend.js.map +1 -0
- package/dist/server/engine/backends/self-backend.d.ts +32 -0
- package/dist/server/engine/backends/self-backend.d.ts.map +1 -0
- package/dist/server/engine/backends/self-backend.js +205 -0
- package/dist/server/engine/backends/self-backend.js.map +1 -0
- package/dist/server/engine/bus.d.ts +10 -0
- package/dist/server/engine/bus.d.ts.map +1 -0
- package/dist/server/engine/bus.js +24 -0
- package/dist/server/engine/bus.js.map +1 -0
- package/dist/server/engine/dispatch/dispatcher.d.ts +46 -0
- package/dist/server/engine/dispatch/dispatcher.d.ts.map +1 -0
- package/dist/server/engine/dispatch/dispatcher.js +312 -0
- package/dist/server/engine/dispatch/dispatcher.js.map +1 -0
- package/dist/server/engine/dispatch/scheduler.d.ts +47 -0
- package/dist/server/engine/dispatch/scheduler.d.ts.map +1 -0
- package/dist/server/engine/dispatch/scheduler.js +328 -0
- package/dist/server/engine/dispatch/scheduler.js.map +1 -0
- package/dist/server/engine/dispatch/sqs-poller.d.ts +25 -0
- package/dist/server/engine/dispatch/sqs-poller.d.ts.map +1 -0
- package/dist/server/engine/dispatch/sqs-poller.js +242 -0
- package/dist/server/engine/dispatch/sqs-poller.js.map +1 -0
- package/dist/server/engine/dispatch/stream-tailer.d.ts +22 -0
- package/dist/server/engine/dispatch/stream-tailer.d.ts.map +1 -0
- package/dist/server/engine/dispatch/stream-tailer.js +205 -0
- package/dist/server/engine/dispatch/stream-tailer.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/decimal.d.ts +5 -0
- package/dist/server/engine/emulators/dynamodb/expressions/decimal.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/decimal.js +91 -0
- package/dist/server/engine/emulators/dynamodb/expressions/decimal.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/evaluate.d.ts +24 -0
- package/dist/server/engine/emulators/dynamodb/expressions/evaluate.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/evaluate.js +183 -0
- package/dist/server/engine/emulators/dynamodb/expressions/evaluate.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/expression-types.d.ts +29 -0
- package/dist/server/engine/emulators/dynamodb/expressions/expression-types.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/expression-types.js +12 -0
- package/dist/server/engine/emulators/dynamodb/expressions/expression-types.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/index.d.ts +13 -0
- package/dist/server/engine/emulators/dynamodb/expressions/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/index.js +244 -0
- package/dist/server/engine/emulators/dynamodb/expressions/index.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/lexer.d.ts +11 -0
- package/dist/server/engine/emulators/dynamodb/expressions/lexer.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/lexer.js +109 -0
- package/dist/server/engine/emulators/dynamodb/expressions/lexer.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/parser.d.ts +23 -0
- package/dist/server/engine/emulators/dynamodb/expressions/parser.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/expressions/parser.js +541 -0
- package/dist/server/engine/emulators/dynamodb/expressions/parser.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/index.d.ts +46 -0
- package/dist/server/engine/emulators/dynamodb/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/index.js +572 -0
- package/dist/server/engine/emulators/dynamodb/index.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/query.d.ts +12 -0
- package/dist/server/engine/emulators/dynamodb/query.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/query.js +237 -0
- package/dist/server/engine/emulators/dynamodb/query.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/schema.d.ts +58 -0
- package/dist/server/engine/emulators/dynamodb/schema.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/schema.js +284 -0
- package/dist/server/engine/emulators/dynamodb/schema.js.map +1 -0
- package/dist/server/engine/emulators/dynamodb/streams.d.ts +28 -0
- package/dist/server/engine/emulators/dynamodb/streams.d.ts.map +1 -0
- package/dist/server/engine/emulators/dynamodb/streams.js +100 -0
- package/dist/server/engine/emulators/dynamodb/streams.js.map +1 -0
- package/dist/server/engine/emulators/events/index.d.ts +53 -0
- package/dist/server/engine/emulators/events/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/events/index.js +417 -0
- package/dist/server/engine/emulators/events/index.js.map +1 -0
- package/dist/server/engine/emulators/events/pattern.d.ts +3 -0
- package/dist/server/engine/emulators/events/pattern.d.ts.map +1 -0
- package/dist/server/engine/emulators/events/pattern.js +125 -0
- package/dist/server/engine/emulators/events/pattern.js.map +1 -0
- package/dist/server/engine/emulators/lambda-ctl/index.d.ts +55 -0
- package/dist/server/engine/emulators/lambda-ctl/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/lambda-ctl/index.js +461 -0
- package/dist/server/engine/emulators/lambda-ctl/index.js.map +1 -0
- package/dist/server/engine/emulators/s3/index.d.ts +45 -0
- package/dist/server/engine/emulators/s3/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/s3/index.js +591 -0
- package/dist/server/engine/emulators/s3/index.js.map +1 -0
- package/dist/server/engine/emulators/sns/index.d.ts +22 -0
- package/dist/server/engine/emulators/sns/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/sns/index.js +135 -0
- package/dist/server/engine/emulators/sns/index.js.map +1 -0
- package/dist/server/engine/emulators/sqs/index.d.ts +66 -0
- package/dist/server/engine/emulators/sqs/index.d.ts.map +1 -0
- package/dist/server/engine/emulators/sqs/index.js +552 -0
- package/dist/server/engine/emulators/sqs/index.js.map +1 -0
- package/dist/server/engine/emulators/sqs/md5.d.ts +8 -0
- package/dist/server/engine/emulators/sqs/md5.d.ts.map +1 -0
- package/dist/server/engine/emulators/sqs/md5.js +36 -0
- package/dist/server/engine/emulators/sqs/md5.js.map +1 -0
- package/dist/server/engine/emulators/sqs/queue.d.ts +105 -0
- package/dist/server/engine/emulators/sqs/queue.d.ts.map +1 -0
- package/dist/server/engine/emulators/sqs/queue.js +371 -0
- package/dist/server/engine/emulators/sqs/queue.js.map +1 -0
- package/dist/server/engine/emulators/sts.d.ts +8 -0
- package/dist/server/engine/emulators/sts.d.ts.map +1 -0
- package/dist/server/engine/emulators/sts.js +23 -0
- package/dist/server/engine/emulators/sts.js.map +1 -0
- package/dist/server/engine/engine-backend.d.ts +17 -0
- package/dist/server/engine/engine-backend.d.ts.map +1 -0
- package/dist/server/engine/engine-backend.js +7 -0
- package/dist/server/engine/engine-backend.js.map +1 -0
- package/dist/server/engine/engine-manager.d.ts +22 -0
- package/dist/server/engine/engine-manager.d.ts.map +1 -0
- package/dist/server/engine/engine-manager.js +74 -0
- package/dist/server/engine/engine-manager.js.map +1 -0
- package/dist/server/engine/http/aws-chunked.d.ts +3 -0
- package/dist/server/engine/http/aws-chunked.d.ts.map +1 -0
- package/dist/server/engine/http/aws-chunked.js +50 -0
- package/dist/server/engine/http/aws-chunked.js.map +1 -0
- package/dist/server/engine/http/errors.d.ts +20 -0
- package/dist/server/engine/http/errors.d.ts.map +1 -0
- package/dist/server/engine/http/errors.js +43 -0
- package/dist/server/engine/http/errors.js.map +1 -0
- package/dist/server/engine/http/protocols/aws-json.d.ts +8 -0
- package/dist/server/engine/http/protocols/aws-json.d.ts.map +1 -0
- package/dist/server/engine/http/protocols/aws-json.js +42 -0
- package/dist/server/engine/http/protocols/aws-json.js.map +1 -0
- package/dist/server/engine/http/protocols/query-xml.d.ts +7 -0
- package/dist/server/engine/http/protocols/query-xml.d.ts.map +1 -0
- package/dist/server/engine/http/protocols/query-xml.js +35 -0
- package/dist/server/engine/http/protocols/query-xml.js.map +1 -0
- package/dist/server/engine/http/router.d.ts +8 -0
- package/dist/server/engine/http/router.d.ts.map +1 -0
- package/dist/server/engine/http/router.js +391 -0
- package/dist/server/engine/http/router.js.map +1 -0
- package/dist/server/engine/http/sigv4.d.ts +9 -0
- package/dist/server/engine/http/sigv4.d.ts.map +1 -0
- package/dist/server/engine/http/sigv4.js +33 -0
- package/dist/server/engine/http/sigv4.js.map +1 -0
- package/dist/server/engine/http/xml.d.ts +16 -0
- package/dist/server/engine/http/xml.d.ts.map +1 -0
- package/dist/server/engine/http/xml.js +92 -0
- package/dist/server/engine/http/xml.js.map +1 -0
- package/dist/server/engine/store/atomic.d.ts +4 -0
- package/dist/server/engine/store/atomic.d.ts.map +1 -0
- package/dist/server/engine/store/atomic.js +35 -0
- package/dist/server/engine/store/atomic.js.map +1 -0
- package/dist/server/engine/store/engine-store.d.ts +9 -0
- package/dist/server/engine/store/engine-store.d.ts.map +1 -0
- package/dist/server/engine/store/engine-store.js +218 -0
- package/dist/server/engine/store/engine-store.js.map +1 -0
- package/dist/server/engine/store/store-types.d.ts +37 -0
- package/dist/server/engine/store/store-types.d.ts.map +1 -0
- package/dist/server/engine/store/store-types.js +17 -0
- package/dist/server/engine/store/store-types.js.map +1 -0
- package/dist/server/engine/store/wal.d.ts +49 -0
- package/dist/server/engine/store/wal.d.ts.map +1 -0
- package/dist/server/engine/store/wal.js +328 -0
- package/dist/server/engine/store/wal.js.map +1 -0
- package/dist/server/engine/types.d.ts +137 -0
- package/dist/server/engine/types.d.ts.map +1 -0
- package/dist/server/engine/types.js +8 -0
- package/dist/server/engine/types.js.map +1 -0
- package/dist/server/index.js +12 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/services.d.ts.map +1 -1
- package/dist/server/routes/services.js +2 -0
- package/dist/server/routes/services.js.map +1 -1
- package/dist/server/services/cloudformation-parser.d.ts +26 -2
- package/dist/server/services/cloudformation-parser.d.ts.map +1 -1
- package/dist/server/services/cloudformation-parser.js +60 -3
- package/dist/server/services/cloudformation-parser.js.map +1 -1
- package/dist/server/services/config-manager.d.ts +27 -0
- package/dist/server/services/config-manager.d.ts.map +1 -1
- package/dist/server/services/config-manager.js +67 -7
- package/dist/server/services/config-manager.js.map +1 -1
- package/dist/server/services/localstack-manager.d.ts +0 -7
- package/dist/server/services/localstack-manager.d.ts.map +1 -1
- package/dist/server/services/localstack-manager.js +11 -173
- package/dist/server/services/localstack-manager.js.map +1 -1
- package/dist/server/services/resource-provisioner.d.ts +6 -0
- package/dist/server/services/resource-provisioner.d.ts.map +1 -1
- package/dist/server/services/resource-provisioner.js +171 -7
- package/dist/server/services/resource-provisioner.js.map +1 -1
- package/dist/server/services/service-registrar.js +2 -2
- package/dist/server/services/service-registrar.js.map +1 -1
- package/dist/ui/assets/ApisPage-a9i2qD0Z.js +1 -0
- package/dist/ui/assets/BucketDetailPage-Cz27N0KV.js +1 -0
- package/dist/ui/assets/BucketsPage-CZ7wGmUN.js +1 -0
- package/dist/ui/assets/{DynamoPage-B1__Rjr2.js → DynamoPage-BZMs1iW8.js} +1 -1
- package/dist/ui/assets/DynamoTablePage-BQsGkhtO.js +3 -0
- package/dist/ui/assets/LambdaDetailPage-DJb7xqRB.js +4 -0
- package/dist/ui/assets/LambdasPage-Ctg1l-Lg.js +1 -0
- package/dist/ui/assets/OverviewPage-DiijblCA.js +1 -0
- package/dist/ui/assets/QueueDetailPage-DRpSqost.js +1 -0
- package/dist/ui/assets/QueuesPage-CY0bDGwV.js +1 -0
- package/dist/ui/assets/ServiceDetailPage-CYTEdtts.js +2 -0
- package/dist/ui/assets/ServicesPage-OlV_rr-q.js +2 -0
- package/dist/ui/assets/index-C1KdKPDS.css +1 -0
- package/dist/ui/assets/index-DA_C1HOg.js +36 -0
- package/dist/ui/index.html +2 -2
- package/package.json +2 -1
- package/dist/ui/assets/ApisPage-DdgKjEdS.js +0 -1
- package/dist/ui/assets/BucketDetailPage-DZQGxm0y.js +0 -1
- package/dist/ui/assets/BucketsPage-xYXzxCvd.js +0 -1
- package/dist/ui/assets/DynamoTablePage-BCoxPdXW.js +0 -3
- package/dist/ui/assets/LambdaDetailPage-B85CA8tb.js +0 -4
- package/dist/ui/assets/LambdasPage-_TtxQMT_.js +0 -1
- package/dist/ui/assets/OverviewPage-CqTKTY64.js +0 -1
- package/dist/ui/assets/QueueDetailPage-BOr_sImA.js +0 -1
- package/dist/ui/assets/QueuesPage-DpByfcM5.js +0 -1
- package/dist/ui/assets/ServiceDetailPage-DsWgV-ad.js +0 -2
- package/dist/ui/assets/ServicesPage-CGlpsj98.js +0 -2
- package/dist/ui/assets/index-BWlB542w.js +0 -36
- package/dist/ui/assets/index-EYnsoJOq.css +0 -1
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
// Engine front door: one listener that resolves {service, region, operation}
|
|
2
|
+
// for every AWS SDK request and dispatches to the registered emulators, with
|
|
3
|
+
// protocol-correct success/error framing and an optional verbatim fallback
|
|
4
|
+
// proxy for anything the engine does not implement. See
|
|
5
|
+
// docs/PRD_SELF_ENGINE.md §RF2 for the routing contract.
|
|
6
|
+
import http from 'http';
|
|
7
|
+
import https from 'https';
|
|
8
|
+
import { randomUUID } from 'crypto';
|
|
9
|
+
import { AwsError, notImplemented } from './errors.js';
|
|
10
|
+
import { resolveSigV4Scope } from './sigv4.js';
|
|
11
|
+
import { decodeAwsChunkedBody, isAwsChunkedBody } from './aws-chunked.js';
|
|
12
|
+
import { jsonErrorResponse, jsonSuccessResponse, lambdaErrorResponse, } from './protocols/aws-json.js';
|
|
13
|
+
import { parseFormBody, queryErrorResponse, queryXmlSuccessResponse, s3ErrorResponse, } from './protocols/query-xml.js';
|
|
14
|
+
const TARGET_PREFIXES = {
|
|
15
|
+
DynamoDB_20120810: 'dynamodb',
|
|
16
|
+
AmazonSQS: 'sqs',
|
|
17
|
+
AWSEvents: 'events',
|
|
18
|
+
};
|
|
19
|
+
const LEGACY_SQS_MESSAGE = 'Your SDK predates the SQS JSON protocol. The LSS self engine serves SQS over ' +
|
|
20
|
+
'AWS JSON 1.0 (aws-sdk v3 / recent boto3); set selfEngine.fallbackEndpoint to ' +
|
|
21
|
+
'route legacy SDKs to a LocalStack instance.';
|
|
22
|
+
const LOCALSTACK_HEALTH = {
|
|
23
|
+
services: {
|
|
24
|
+
dynamodb: 'available',
|
|
25
|
+
sqs: 'available',
|
|
26
|
+
sns: 'available',
|
|
27
|
+
s3: 'available',
|
|
28
|
+
lambda: 'available',
|
|
29
|
+
events: 'available',
|
|
30
|
+
sts: 'available',
|
|
31
|
+
},
|
|
32
|
+
edition: 'self',
|
|
33
|
+
version: 'lss-self-engine',
|
|
34
|
+
};
|
|
35
|
+
export function createEngineRequestHandler(deps) {
|
|
36
|
+
const byService = new Map();
|
|
37
|
+
for (const emulator of deps.emulators)
|
|
38
|
+
byService.set(emulator.service, emulator);
|
|
39
|
+
return (req, res) => {
|
|
40
|
+
handleRequest(deps, byService, req, res).catch(err => {
|
|
41
|
+
// The inner handler serializes every failure; this only guards against
|
|
42
|
+
// bugs in the serialization path itself.
|
|
43
|
+
console.error('[engine] request handler crashed:', err instanceof Error ? err.stack : err);
|
|
44
|
+
if (!res.headersSent) {
|
|
45
|
+
res.statusCode = 500;
|
|
46
|
+
res.end();
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
res.destroy();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function handleRequest(deps, byService, req, res) {
|
|
55
|
+
const requestId = randomUUID();
|
|
56
|
+
const method = (req.method ?? 'GET').toUpperCase();
|
|
57
|
+
const urlValue = req.url ?? '/';
|
|
58
|
+
const queryIndex = urlValue.indexOf('?');
|
|
59
|
+
// Raw (still-encoded) path: S3 keys must keep encoded slashes intact.
|
|
60
|
+
let rawPath = queryIndex === -1 ? urlValue : urlValue.slice(0, queryIndex);
|
|
61
|
+
const query = {};
|
|
62
|
+
if (queryIndex !== -1) {
|
|
63
|
+
for (const [key, value] of new URLSearchParams(urlValue.slice(queryIndex + 1)))
|
|
64
|
+
query[key] = value;
|
|
65
|
+
}
|
|
66
|
+
if (method === 'GET' && rawPath === '/_lss/health') {
|
|
67
|
+
finish(res, requestId, false, jsonBody(200, { status: 'ok', engine: 'self' }));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (method === 'GET' && rawPath === '/_localstack/health') {
|
|
71
|
+
finish(res, requestId, false, jsonBody(200, LOCALSTACK_HEALTH));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const headers = collectHeaders(req);
|
|
75
|
+
// Kept as first received for the fallback proxy, which must forward the
|
|
76
|
+
// original bytes (including aws-chunked framing) verbatim.
|
|
77
|
+
const rawBody = await readBody(req);
|
|
78
|
+
let shape = guessShape(headers, undefined);
|
|
79
|
+
let serviceLabel = 'unknown';
|
|
80
|
+
let operationLabel = `${method} ${rawPath}`;
|
|
81
|
+
try {
|
|
82
|
+
let body = rawBody;
|
|
83
|
+
if (isAwsChunkedBody(headers)) {
|
|
84
|
+
body = decodeAwsChunkedBody(rawBody);
|
|
85
|
+
stripAwsChunkedHeaders(headers, body.length);
|
|
86
|
+
}
|
|
87
|
+
// ---- service resolution, in precedence order (RF2.1) ----
|
|
88
|
+
const scope = resolveSigV4Scope(headers, query);
|
|
89
|
+
const region = scope?.region ?? deps.ctx.config.region;
|
|
90
|
+
const target = headers['x-amz-target'];
|
|
91
|
+
const contentType = headers['content-type'] ?? '';
|
|
92
|
+
let service = scope?.service;
|
|
93
|
+
let formParams;
|
|
94
|
+
if (contentType.includes('x-www-form-urlencoded') &&
|
|
95
|
+
(!service || service === 'sns' || service === 'sts' || service === 'sqs')) {
|
|
96
|
+
formParams = parseFormBody(body);
|
|
97
|
+
}
|
|
98
|
+
const formAction = formParams?.Action;
|
|
99
|
+
let legacySqs = false;
|
|
100
|
+
if (!service) {
|
|
101
|
+
if (target) {
|
|
102
|
+
service = TARGET_PREFIXES[target.split('.')[0]];
|
|
103
|
+
if (!service) {
|
|
104
|
+
shape = { kind: 'json', service: undefined, version: '1.0' };
|
|
105
|
+
operationLabel = target;
|
|
106
|
+
await respondUnknown(deps, req, res, rawBody, requestId, method, shape, serviceLabel, operationLabel);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (formAction) {
|
|
111
|
+
// Legacy SQS Query SDKs post data-plane calls to the QueueUrl path
|
|
112
|
+
// (/<account>/<queue>); everything Query-shaped at the root is SNS,
|
|
113
|
+
// except the STS bootstrap call.
|
|
114
|
+
if (rawPath !== '/')
|
|
115
|
+
legacySqs = true;
|
|
116
|
+
else
|
|
117
|
+
service = formAction === 'GetCallerIdentity' ? 'sts' : 'sns';
|
|
118
|
+
}
|
|
119
|
+
else if (rawPath.startsWith('/2015-03-31/')) {
|
|
120
|
+
service = 'lambda';
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
service = 's3';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// A SigV4-scoped SQS request without X-Amz-Target that carries a Query
|
|
127
|
+
// form body is a legacy SDK too, whatever path it posted to.
|
|
128
|
+
if (service === 'sqs' && !target && formAction)
|
|
129
|
+
legacySqs = true;
|
|
130
|
+
if (legacySqs) {
|
|
131
|
+
shape = { kind: 'query' };
|
|
132
|
+
serviceLabel = 'sqs';
|
|
133
|
+
if (deps.ctx.config.fallbackEndpoint) {
|
|
134
|
+
await proxyToFallback(deps.ctx.config.fallbackEndpoint, req, rawBody, res, shape, requestId, method);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
throw new AwsError('InvalidAction', LEGACY_SQS_MESSAGE, { status: 400 });
|
|
138
|
+
}
|
|
139
|
+
if (service === 's3')
|
|
140
|
+
rawPath = peelVirtualHostBucket(rawPath, headers['host']);
|
|
141
|
+
serviceLabel = service ?? 'unknown';
|
|
142
|
+
shape = shapeForService(service, byService) ?? guessShape(headers, formAction);
|
|
143
|
+
const emulator = byService.get(service);
|
|
144
|
+
if (!emulator) {
|
|
145
|
+
await respondUnknown(deps, req, res, rawBody, requestId, method, shape, serviceLabel, operationLabel);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const awsReq = {
|
|
149
|
+
method,
|
|
150
|
+
rawPath,
|
|
151
|
+
query,
|
|
152
|
+
headers,
|
|
153
|
+
body,
|
|
154
|
+
service: emulator.service,
|
|
155
|
+
region,
|
|
156
|
+
requestId,
|
|
157
|
+
};
|
|
158
|
+
// ---- dispatch by emulator flavor ----
|
|
159
|
+
let response;
|
|
160
|
+
if ('targetPrefix' in emulator) {
|
|
161
|
+
if (!target) {
|
|
162
|
+
// No JSON operation on a JSON-protocol service: unknown op, and
|
|
163
|
+
// therefore fallback-eligible (caught below).
|
|
164
|
+
throw new AwsError('UnknownOperationException', `Missing X-Amz-Target header for ${emulator.service}`);
|
|
165
|
+
}
|
|
166
|
+
const dot = target.indexOf('.');
|
|
167
|
+
const operation = dot === -1 ? target : target.slice(dot + 1);
|
|
168
|
+
operationLabel = operation;
|
|
169
|
+
let input = {};
|
|
170
|
+
if (body.length > 0) {
|
|
171
|
+
try {
|
|
172
|
+
input = JSON.parse(body.toString('utf8'));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
throw new AwsError('SerializationException', 'Could not parse the request body as JSON');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
response = jsonSuccessResponse(await emulator.handle(operation, input, awsReq), emulator.jsonVersion);
|
|
179
|
+
}
|
|
180
|
+
else if (emulator.service === 'sns' || emulator.service === 'sts') {
|
|
181
|
+
// QueryEmulator vs RestEmulator is not structurally narrowable; SNS and
|
|
182
|
+
// STS are the engine's Query-protocol services by contract.
|
|
183
|
+
const queryEmulator = emulator;
|
|
184
|
+
const action = formAction ?? query['Action'];
|
|
185
|
+
if (!action)
|
|
186
|
+
throw new AwsError('MissingAction', 'The request must contain the parameter Action.');
|
|
187
|
+
operationLabel = action;
|
|
188
|
+
response = queryXmlSuccessResponse(await queryEmulator.handle(action, formParams ?? query, awsReq));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const restEmulator = emulator;
|
|
192
|
+
response = await restEmulator.handle(awsReq);
|
|
193
|
+
}
|
|
194
|
+
finish(res, requestId, emulator.service === 's3', response);
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
const awsErr = err instanceof AwsError ? err : internalError(err);
|
|
198
|
+
if (awsErr.code === 'UnknownOperationException') {
|
|
199
|
+
await respondUnknown(deps, req, res, rawBody, requestId, method, shape, serviceLabel, operationLabel);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
finish(res, requestId, shape.kind === 's3', serializeError(awsErr, shape, requestId, method));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
// Unknown service/operation: verbatim fallback proxy or explicit 400 — the
|
|
207
|
+
// engine never silently succeeds (RF2.2).
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
async function respondUnknown(deps, req, res, rawBody, requestId, method, shape, serviceLabel, operationLabel) {
|
|
210
|
+
const fallback = deps.ctx.config.fallbackEndpoint;
|
|
211
|
+
if (fallback) {
|
|
212
|
+
await proxyToFallback(fallback, req, rawBody, res, shape, requestId, method);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const err = notImplemented(serviceLabel, operationLabel);
|
|
216
|
+
finish(res, requestId, shape.kind === 's3', serializeError(err, shape, requestId, method));
|
|
217
|
+
}
|
|
218
|
+
function proxyToFallback(endpoint, req, rawBody, res, shape, requestId, method) {
|
|
219
|
+
return new Promise(resolve => {
|
|
220
|
+
const url = new URL(endpoint);
|
|
221
|
+
const transport = url.protocol === 'https:' ? https : http;
|
|
222
|
+
const headers = { ...req.headers };
|
|
223
|
+
delete headers['host'];
|
|
224
|
+
// The body was fully buffered (any HTTP chunking already undone), so the
|
|
225
|
+
// proxied request carries an explicit length.
|
|
226
|
+
delete headers['transfer-encoding'];
|
|
227
|
+
headers['content-length'] = String(rawBody.length);
|
|
228
|
+
const proxyReq = transport.request({
|
|
229
|
+
protocol: url.protocol,
|
|
230
|
+
hostname: url.hostname,
|
|
231
|
+
port: url.port,
|
|
232
|
+
path: req.url,
|
|
233
|
+
method: req.method,
|
|
234
|
+
headers,
|
|
235
|
+
}, proxyRes => {
|
|
236
|
+
const responseHeaders = { ...proxyRes.headers };
|
|
237
|
+
// Node re-frames the piped body itself.
|
|
238
|
+
delete responseHeaders['transfer-encoding'];
|
|
239
|
+
res.writeHead(proxyRes.statusCode ?? 502, responseHeaders);
|
|
240
|
+
proxyRes.pipe(res);
|
|
241
|
+
proxyRes.on('end', () => resolve());
|
|
242
|
+
proxyRes.on('error', () => {
|
|
243
|
+
res.destroy();
|
|
244
|
+
resolve();
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
proxyReq.on('error', err => {
|
|
248
|
+
if (res.headersSent) {
|
|
249
|
+
res.destroy();
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const unreachable = new AwsError('ServiceUnavailable', `selfEngine.fallbackEndpoint (${endpoint}) is unreachable: ${err.message}`, { status: 502, fault: 'Receiver' });
|
|
253
|
+
finish(res, requestId, shape.kind === 's3', serializeError(unreachable, shape, requestId, method));
|
|
254
|
+
}
|
|
255
|
+
resolve();
|
|
256
|
+
});
|
|
257
|
+
proxyReq.end(rawBody);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
// Error shaping
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
function shapeForService(service, byService) {
|
|
264
|
+
switch (service) {
|
|
265
|
+
case 'dynamodb':
|
|
266
|
+
case 'sqs':
|
|
267
|
+
case 'events': {
|
|
268
|
+
const emulator = byService.get(service);
|
|
269
|
+
const version = emulator && 'jsonVersion' in emulator ? emulator.jsonVersion : service === 'events' ? '1.1' : '1.0';
|
|
270
|
+
return { kind: 'json', service, version };
|
|
271
|
+
}
|
|
272
|
+
case 'sns':
|
|
273
|
+
case 'sts':
|
|
274
|
+
return { kind: 'query' };
|
|
275
|
+
case 'lambda':
|
|
276
|
+
return { kind: 'lambda' };
|
|
277
|
+
case 's3':
|
|
278
|
+
return { kind: 's3' };
|
|
279
|
+
default:
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function guessShape(headers, formAction) {
|
|
284
|
+
if (headers['x-amz-target'] || (headers['content-type'] ?? '').includes('json')) {
|
|
285
|
+
return { kind: 'json', service: undefined, version: '1.0' };
|
|
286
|
+
}
|
|
287
|
+
if (formAction)
|
|
288
|
+
return { kind: 'query' };
|
|
289
|
+
return { kind: 's3' };
|
|
290
|
+
}
|
|
291
|
+
function serializeError(err, shape, requestId, method) {
|
|
292
|
+
switch (shape.kind) {
|
|
293
|
+
case 'json':
|
|
294
|
+
return jsonErrorResponse(err, shape.service, shape.version);
|
|
295
|
+
case 'query':
|
|
296
|
+
return queryErrorResponse(err, requestId);
|
|
297
|
+
case 'lambda':
|
|
298
|
+
return lambdaErrorResponse(err);
|
|
299
|
+
case 's3':
|
|
300
|
+
return s3ErrorResponse(err, requestId, method);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function internalError(err) {
|
|
304
|
+
console.error('[engine] unexpected error:', err instanceof Error ? err.stack : err);
|
|
305
|
+
return new AwsError('InternalFailure', 'The LSS self engine encountered an internal error', {
|
|
306
|
+
status: 500,
|
|
307
|
+
fault: 'Receiver',
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
// ---------------------------------------------------------------------------
|
|
311
|
+
// Wire helpers
|
|
312
|
+
// ---------------------------------------------------------------------------
|
|
313
|
+
function collectHeaders(req) {
|
|
314
|
+
const headers = {};
|
|
315
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
316
|
+
if (value === undefined)
|
|
317
|
+
continue;
|
|
318
|
+
headers[name] = Array.isArray(value) ? value.join(', ') : value;
|
|
319
|
+
}
|
|
320
|
+
return headers;
|
|
321
|
+
}
|
|
322
|
+
function readBody(req) {
|
|
323
|
+
return new Promise((resolve, reject) => {
|
|
324
|
+
const chunks = [];
|
|
325
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
326
|
+
req.on('end', () => resolve(Buffer.concat(chunks)));
|
|
327
|
+
req.on('error', reject);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
function stripAwsChunkedHeaders(headers, decodedLength) {
|
|
331
|
+
const encoding = headers['content-encoding'];
|
|
332
|
+
if (encoding) {
|
|
333
|
+
const remaining = encoding
|
|
334
|
+
.split(',')
|
|
335
|
+
.map(token => token.trim())
|
|
336
|
+
.filter(token => token && token !== 'aws-chunked');
|
|
337
|
+
if (remaining.length > 0)
|
|
338
|
+
headers['content-encoding'] = remaining.join(', ');
|
|
339
|
+
else
|
|
340
|
+
delete headers['content-encoding'];
|
|
341
|
+
}
|
|
342
|
+
delete headers['x-amz-trailer'];
|
|
343
|
+
delete headers['x-amz-decoded-content-length'];
|
|
344
|
+
headers['content-length'] = String(decodedLength);
|
|
345
|
+
}
|
|
346
|
+
// Virtual-host-style S3 (bucket in the Host header) → path-style. Kept
|
|
347
|
+
// conservative: never peel plain localhost, loopback or IP hosts, so
|
|
348
|
+
// path-style requests (every LSS client sets forcePathStyle) are untouched.
|
|
349
|
+
function peelVirtualHostBucket(rawPath, host) {
|
|
350
|
+
if (!host || host.startsWith('['))
|
|
351
|
+
return rawPath;
|
|
352
|
+
const hostname = host.split(':')[0];
|
|
353
|
+
const dot = hostname.indexOf('.');
|
|
354
|
+
if (dot <= 0)
|
|
355
|
+
return rawPath;
|
|
356
|
+
if (hostname.startsWith('localhost') || hostname.startsWith('127.'))
|
|
357
|
+
return rawPath;
|
|
358
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(hostname))
|
|
359
|
+
return rawPath;
|
|
360
|
+
const bucket = hostname.slice(0, dot);
|
|
361
|
+
return `/${bucket}${rawPath === '/' ? '' : rawPath}`;
|
|
362
|
+
}
|
|
363
|
+
function jsonBody(status, payload) {
|
|
364
|
+
return { status, headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) };
|
|
365
|
+
}
|
|
366
|
+
function finish(res, requestId, s3Ids, response) {
|
|
367
|
+
const body = response.body === undefined
|
|
368
|
+
? Buffer.alloc(0)
|
|
369
|
+
: typeof response.body === 'string'
|
|
370
|
+
? Buffer.from(response.body, 'utf8')
|
|
371
|
+
: response.body;
|
|
372
|
+
for (const [name, value] of Object.entries(response.headers ?? {}))
|
|
373
|
+
res.setHeader(name, value);
|
|
374
|
+
if (!res.hasHeader('date'))
|
|
375
|
+
res.setHeader('Date', new Date().toUTCString());
|
|
376
|
+
if (s3Ids) {
|
|
377
|
+
if (!res.hasHeader('x-amz-request-id'))
|
|
378
|
+
res.setHeader('x-amz-request-id', requestId);
|
|
379
|
+
if (!res.hasHeader('x-amz-id-2'))
|
|
380
|
+
res.setHeader('x-amz-id-2', Buffer.from(requestId).toString('base64'));
|
|
381
|
+
}
|
|
382
|
+
else if (!res.hasHeader('x-amzn-requestid')) {
|
|
383
|
+
res.setHeader('x-amzn-RequestId', requestId);
|
|
384
|
+
}
|
|
385
|
+
if (!res.hasHeader('content-length') && response.status !== 204 && response.status !== 304) {
|
|
386
|
+
res.setHeader('Content-Length', body.length);
|
|
387
|
+
}
|
|
388
|
+
res.statusCode = response.status;
|
|
389
|
+
res.end(body.length > 0 ? body : undefined);
|
|
390
|
+
}
|
|
391
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../../src/server/engine/http/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SigV4Scope {
|
|
2
|
+
accessKeyId: string;
|
|
3
|
+
date: string;
|
|
4
|
+
region: string;
|
|
5
|
+
service: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseCredentialScope(credential: string): SigV4Scope | undefined;
|
|
8
|
+
export declare function resolveSigV4Scope(headers: Record<string, string>, query: Record<string, string>): SigV4Scope | undefined;
|
|
9
|
+
//# sourceMappingURL=sigv4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.d.ts","sourceRoot":"","sources":["../../../../src/server/engine/http/sigv4.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAM/E;AAID,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B,UAAU,GAAG,SAAS,CAYxB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// SigV4 credential-scope parsing. The engine never verifies signatures — the
|
|
2
|
+
// scope is only mined for {service, region} so one port can route every AWS
|
|
3
|
+
// SDK request deterministically (see docs/PRD_SELF_ENGINE.md §RF2.1).
|
|
4
|
+
// Parse "AKID/20260710/us-east-1/dynamodb/aws4_request" (the value of
|
|
5
|
+
// Credential= in the Authorization header or the X-Amz-Credential query
|
|
6
|
+
// param). Returns undefined for anything not scope-shaped.
|
|
7
|
+
export function parseCredentialScope(credential) {
|
|
8
|
+
const parts = credential.split('/');
|
|
9
|
+
if (parts.length !== 5 || parts[4] !== 'aws4_request')
|
|
10
|
+
return undefined;
|
|
11
|
+
const [accessKeyId, date, region, service] = parts;
|
|
12
|
+
if (!region || !service)
|
|
13
|
+
return undefined;
|
|
14
|
+
return { accessKeyId, date, region, service };
|
|
15
|
+
}
|
|
16
|
+
// Resolve the scope of a request: Authorization header first (SDK-signed
|
|
17
|
+
// requests), then the presigned-URL X-Amz-Credential query param.
|
|
18
|
+
export function resolveSigV4Scope(headers, query) {
|
|
19
|
+
const authorization = headers['authorization'];
|
|
20
|
+
if (authorization && authorization.startsWith('AWS4-HMAC-SHA256')) {
|
|
21
|
+
const match = /Credential=([^,\s]+)/.exec(authorization);
|
|
22
|
+
if (match) {
|
|
23
|
+
const scope = parseCredentialScope(match[1]);
|
|
24
|
+
if (scope)
|
|
25
|
+
return scope;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const presigned = query['X-Amz-Credential'];
|
|
29
|
+
if (presigned)
|
|
30
|
+
return parseCredentialScope(presigned);
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=sigv4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.js","sourceRoot":"","sources":["../../../../src/server/engine/http/sigv4.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,sEAAsE;AAStE,sEAAsE;AACtE,wEAAwE;AACxE,2DAA2D;AAC3D,MAAM,UAAU,oBAAoB,CAAC,UAAkB;IACrD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,cAAc;QAAE,OAAO,SAAS,CAAC;IACxE,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IACnD,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAChD,CAAC;AAED,yEAAyE;AACzE,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAC/B,OAA+B,EAC/B,KAA6B;IAE7B,MAAM,aAAa,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/C,IAAI,aAAa,IAAI,aAAa,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAClE,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACzD,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,SAAS;QAAE,OAAO,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACtD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface XmlNode {
|
|
2
|
+
name: string;
|
|
3
|
+
attributes: Record<string, string>;
|
|
4
|
+
children: XmlNode[];
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function escapeXml(value: string): string;
|
|
8
|
+
export declare function tag(name: string, content: string, options?: {
|
|
9
|
+
attrs?: Record<string, string>;
|
|
10
|
+
escape?: boolean;
|
|
11
|
+
}): string;
|
|
12
|
+
export declare function xmlDocument(root: string): string;
|
|
13
|
+
export declare function parseXml(input: string): XmlNode;
|
|
14
|
+
export declare function childrenNamed(node: XmlNode, name: string): XmlNode[];
|
|
15
|
+
export declare function childText(node: XmlNode, name: string): string | undefined;
|
|
16
|
+
//# sourceMappingURL=xml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../../../src/server/engine/http/xml.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO/C;AAcD,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAOzH;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAID,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA2C/C;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAEpE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Minimal XML helpers shared by the rest-xml (S3) and query-xml (SNS/STS)
|
|
2
|
+
// protocols. Deliberately tiny: the engine only ever parses XML documents
|
|
3
|
+
// whose shape it defined the request contract for (DeleteObjects,
|
|
4
|
+
// NotificationConfiguration, VersioningConfiguration), so this is a strict
|
|
5
|
+
// well-formed-subset parser — no namespaces resolution, no DTD, no CDATA.
|
|
6
|
+
export function escapeXml(value) {
|
|
7
|
+
return value
|
|
8
|
+
.replace(/&/g, '&')
|
|
9
|
+
.replace(/</g, '<')
|
|
10
|
+
.replace(/>/g, '>')
|
|
11
|
+
.replace(/"/g, '"')
|
|
12
|
+
.replace(/'/g, ''');
|
|
13
|
+
}
|
|
14
|
+
function unescapeXml(value) {
|
|
15
|
+
return value
|
|
16
|
+
.replace(/</g, '<')
|
|
17
|
+
.replace(/>/g, '>')
|
|
18
|
+
.replace(/"/g, '"')
|
|
19
|
+
.replace(/'/g, "'")
|
|
20
|
+
.replace(/&#(\d+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10)))
|
|
21
|
+
.replace(/&/g, '&');
|
|
22
|
+
}
|
|
23
|
+
// Build one element. `content` is either pre-built XML (from nested tag()
|
|
24
|
+
// calls) or raw text that gets escaped when `escape` is true (default).
|
|
25
|
+
export function tag(name, content, options) {
|
|
26
|
+
const attrs = Object.entries(options?.attrs ?? {})
|
|
27
|
+
.map(([key, value]) => ` ${key}="${escapeXml(value)}"`)
|
|
28
|
+
.join('');
|
|
29
|
+
if (content === '')
|
|
30
|
+
return `<${name}${attrs}/>`;
|
|
31
|
+
const body = options?.escape === false ? content : escapeXml(content);
|
|
32
|
+
return `<${name}${attrs}>${body}</${name}>`;
|
|
33
|
+
}
|
|
34
|
+
export function xmlDocument(root) {
|
|
35
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n${root}`;
|
|
36
|
+
}
|
|
37
|
+
// Parse a well-formed XML document into a node tree. Throws on malformed
|
|
38
|
+
// input (mismatched tags, trailing garbage).
|
|
39
|
+
export function parseXml(input) {
|
|
40
|
+
const source = input.replace(/<\?xml[^?]*\?>/g, '').replace(/<!--[\s\S]*?-->/g, '').trim();
|
|
41
|
+
let pos = 0;
|
|
42
|
+
function fail(reason) {
|
|
43
|
+
throw new Error(`Malformed XML at offset ${pos}: ${reason}`);
|
|
44
|
+
}
|
|
45
|
+
function parseNode() {
|
|
46
|
+
if (source[pos] !== '<')
|
|
47
|
+
fail('expected element');
|
|
48
|
+
const open = /^<([\w:.-]+)((?:\s+[\w:.-]+="[^"]*")*)\s*(\/?)>/.exec(source.slice(pos));
|
|
49
|
+
if (!open)
|
|
50
|
+
fail('invalid opening tag');
|
|
51
|
+
const [openText, name, attrText, selfClose] = open;
|
|
52
|
+
pos += openText.length;
|
|
53
|
+
const attributes = {};
|
|
54
|
+
for (const match of attrText.matchAll(/([\w:.-]+)="([^"]*)"/g)) {
|
|
55
|
+
attributes[match[1]] = unescapeXml(match[2]);
|
|
56
|
+
}
|
|
57
|
+
const node = { name, attributes, children: [], text: '' };
|
|
58
|
+
if (selfClose === '/')
|
|
59
|
+
return node;
|
|
60
|
+
for (;;) {
|
|
61
|
+
const nextTag = source.indexOf('<', pos);
|
|
62
|
+
if (nextTag === -1)
|
|
63
|
+
fail(`unclosed element <${name}>`);
|
|
64
|
+
const textChunk = source.slice(pos, nextTag);
|
|
65
|
+
if (textChunk.trim())
|
|
66
|
+
node.text += unescapeXml(textChunk.trim());
|
|
67
|
+
pos = nextTag;
|
|
68
|
+
if (source.startsWith(`</${name}`, pos)) {
|
|
69
|
+
const close = source.indexOf('>', pos);
|
|
70
|
+
if (close === -1)
|
|
71
|
+
fail(`unclosed closing tag for <${name}>`);
|
|
72
|
+
pos = close + 1;
|
|
73
|
+
return node;
|
|
74
|
+
}
|
|
75
|
+
if (source.startsWith('</', pos))
|
|
76
|
+
fail(`unexpected closing tag inside <${name}>`);
|
|
77
|
+
node.children.push(parseNode());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const root = parseNode();
|
|
81
|
+
if (source.slice(pos).trim())
|
|
82
|
+
fail('trailing content after root element');
|
|
83
|
+
return root;
|
|
84
|
+
}
|
|
85
|
+
// Convenience lookups used by emulators.
|
|
86
|
+
export function childrenNamed(node, name) {
|
|
87
|
+
return node.children.filter(child => child.name === name);
|
|
88
|
+
}
|
|
89
|
+
export function childText(node, name) {
|
|
90
|
+
return node.children.find(child => child.name === name)?.text;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=xml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xml.js","sourceRoot":"","sources":["../../../../src/server/engine/http/xml.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function ensureDirFor(filePath: string): Promise<void>;
|
|
2
|
+
export declare function atomicWriteFile(filePath: string, data: string | Buffer, fsync: boolean): Promise<void>;
|
|
3
|
+
export declare function appendToFile(filePath: string, data: string, fsync: boolean): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=atomic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../../../../src/server/engine/store/atomic.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5G;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAShG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Shared file primitives for the engine store: atomic replace (write tmp +
|
|
2
|
+
// rename — rename is the commit point) and buffered append, each with opt-in
|
|
3
|
+
// fsync for the paranoid durability mode.
|
|
4
|
+
import fsp from 'fs/promises';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
export async function ensureDirFor(filePath) {
|
|
7
|
+
await fsp.mkdir(path.dirname(filePath), { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
export async function atomicWriteFile(filePath, data, fsync) {
|
|
10
|
+
await ensureDirFor(filePath);
|
|
11
|
+
const tmpPath = `${filePath}.tmp`;
|
|
12
|
+
const handle = await fsp.open(tmpPath, 'w');
|
|
13
|
+
try {
|
|
14
|
+
await handle.writeFile(data);
|
|
15
|
+
if (fsync)
|
|
16
|
+
await handle.sync();
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
await handle.close();
|
|
20
|
+
}
|
|
21
|
+
await fsp.rename(tmpPath, filePath);
|
|
22
|
+
}
|
|
23
|
+
export async function appendToFile(filePath, data, fsync) {
|
|
24
|
+
await ensureDirFor(filePath);
|
|
25
|
+
const handle = await fsp.open(filePath, 'a');
|
|
26
|
+
try {
|
|
27
|
+
await handle.write(data);
|
|
28
|
+
if (fsync)
|
|
29
|
+
await handle.sync();
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
await handle.close();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=atomic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../../../src/server/engine/store/atomic.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,6EAA6E;AAC7E,0CAA0C;AAE1C,OAAO,GAAG,MAAM,aAAa,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,IAAqB,EAAE,KAAc;IAC3F,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,KAAK;YAAE,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,IAAY,EAAE,KAAc;IAC/E,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,KAAK;YAAE,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
|