@kensio/yulin 1.21.28 → 1.21.30
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/dist/sdk/wire/sim-sdk-wire-bedrock-action.d.ts +18 -0
- package/dist/sdk/wire/sim-sdk-wire-bedrock-action.js +71 -0
- package/dist/sdk/wire/sim-sdk-wire-bedrock-input.d.ts +11 -0
- package/dist/sdk/wire/sim-sdk-wire-bedrock-input.js +45 -0
- package/dist/sdk/wire/sim-sdk-wire-bedrock.d.ts +10 -0
- package/dist/sdk/wire/sim-sdk-wire-bedrock.js +47 -0
- package/dist/sdk/wire/sim-sdk-wire-call.d.ts +30 -0
- package/dist/sdk/wire/sim-sdk-wire-call.js +32 -0
- package/dist/sdk/wire/sim-sdk-wire-dispatcher.js +7 -9
- package/dist/sdk/wire/sim-sdk-wire-event-stream.d.ts +16 -0
- package/dist/sdk/wire/sim-sdk-wire-event-stream.js +79 -0
- package/dist/sdk/wire/sim-sdk-wire-unbridged.js +2 -2
- package/dist/service/athena/engine/sim-athena-array-shims.js +1 -1
- package/dist/service/athena/engine/sim-athena-binary-text.d.ts +2 -2
- package/dist/service/athena/engine/sim-athena-binary-text.js +2 -2
- package/dist/service/athena/engine/sim-athena-cast-rewrite.d.ts +30 -0
- package/dist/service/athena/engine/sim-athena-cast-rewrite.js +107 -0
- package/dist/service/athena/engine/sim-athena-cast-shims.d.ts +12 -0
- package/dist/service/athena/engine/sim-athena-cast-shims.js +29 -0
- package/dist/service/athena/engine/sim-athena-cast-text.d.ts +13 -0
- package/dist/service/athena/engine/sim-athena-cast-text.js +66 -0
- package/dist/service/athena/engine/sim-athena-comparison-shims.js +1 -2
- package/dist/service/athena/engine/sim-athena-date-arithmetic-shims.d.ts +4 -5
- package/dist/service/athena/engine/sim-athena-date-arithmetic-shims.js +6 -14
- package/dist/service/athena/engine/sim-athena-date-units.d.ts +1 -1
- package/dist/service/athena/engine/sim-athena-date-units.js +1 -1
- package/dist/service/athena/engine/sim-athena-engine-answer.d.ts +10 -5
- package/dist/service/athena/engine/sim-athena-engine-answer.js +4 -4
- package/dist/service/athena/engine/sim-athena-engine-run.d.ts +4 -0
- package/dist/service/athena/engine/sim-athena-engine-run.js +10 -2
- package/dist/service/athena/engine/sim-athena-regexp-shims.js +2 -2
- package/dist/service/athena/engine/sim-athena-shim-refusal.d.ts +17 -0
- package/dist/service/athena/engine/sim-athena-shim-refusal.js +22 -0
- package/dist/service/athena/engine/sim-athena-shim-registry.d.ts +5 -1
- package/dist/service/athena/engine/sim-athena-shim-registry.js +14 -2
- package/dist/service/athena/engine/sim-athena-shims.js +2 -0
- package/dist/service/athena/engine/sim-athena-sql-translation.d.ts +1 -23
- package/dist/service/athena/engine/sim-athena-sql-translation.js +8 -23
- package/dist/service/athena/engine/sim-athena-translated-sql.d.ts +29 -0
- package/dist/service/athena/engine/sim-athena-translated-sql.js +12 -0
- package/dist/service/athena/engine/sim-athena-turn-down.d.ts +7 -0
- package/dist/service/athena/engine/sim-athena-turn-down.js +11 -0
- package/dist/service/athena/result/sim-athena-query-answer.d.ts +2 -1
- package/dist/service/athena/result/sim-athena-query-answer.js +2 -1
- package/dist/service/athena/sim-athena-snapshot-table.fixture.d.ts +10 -0
- package/dist/service/athena/sim-athena-snapshot-table.fixture.js +39 -0
- package/dist/service/bedrock/command/authorize/sim-bedrock-authorizer.js +7 -3
- package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.d.ts +2 -2
- package/dist/service/lambda/function/code/vm/sdk/sim-sdk-lambda-vm-module-provider.js +5 -9
- package/dist/service/lambda/function/code/vm/sim-lambda-vm-context.d.ts +1 -1
- package/dist/service/lambda/function/code/vm/sim-lambda-vm-context.js +11 -22
- package/dist/service/lambda/function/code/vm/sim-lambda-vm-host-globals.d.ts +4 -0
- package/dist/service/lambda/function/code/vm/sim-lambda-vm-host-globals.js +87 -0
- package/dist/service/lambda/function/invoke/sim-lambda-outbound-clients.d.ts +3 -0
- package/dist/service/lambda/function/invoke/sim-lambda-outbound-clients.js +10 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-exchanges.d.ts +32 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-exchanges.js +39 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-messages.d.ts +33 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-messages.js +87 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-module.d.ts +27 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-module.js +53 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-session.d.ts +31 -0
- package/dist/service/lambda/function/outbound/sim-lambda-http2-session.js +57 -0
- package/dist/service/lambda/function/outbound/sim-lambda-transport-module.d.ts +11 -0
- package/dist/service/lambda/function/outbound/sim-lambda-transport-module.js +24 -0
- package/docs/services/athena/README.md +29 -8
- package/docs/services/lambda/README.md +18 -8
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SimSdkWireRequest, SimSdkWireResponse } from "./sim-sdk-wire.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The REST-JSON content type, for bodies and for errors.
|
|
4
|
+
*/
|
|
5
|
+
export declare const simSdkWireBedrockJsonContentType = "application/json";
|
|
6
|
+
/**
|
|
7
|
+
* How one Bedrock Runtime operation reads its input off a request and writes
|
|
8
|
+
* its output back.
|
|
9
|
+
*/
|
|
10
|
+
export interface SimSdkWireBedrockAction {
|
|
11
|
+
readonly commandName: string;
|
|
12
|
+
input(modelId: string, request: SimSdkWireRequest): unknown;
|
|
13
|
+
outputResponse(output: unknown): Promise<SimSdkWireResponse>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The invocation operations, keyed by the last segment of their path.
|
|
17
|
+
*/
|
|
18
|
+
export declare const simSdkWireBedrockActions: ReadonlyMap<string, SimSdkWireBedrockAction>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { simSdkWireConverseInput, simSdkWireInvokeInput, } from "./sim-sdk-wire-bedrock-input.js";
|
|
2
|
+
import { simSdkWireEventStreamBody, simSdkWireEventStreamContentType, } from "./sim-sdk-wire-event-stream.js";
|
|
3
|
+
import { simSdkWireOutputResponse } from "./sim-sdk-wire-response.js";
|
|
4
|
+
/**
|
|
5
|
+
* The REST-JSON content type, for bodies and for errors.
|
|
6
|
+
*/
|
|
7
|
+
export const simSdkWireBedrockJsonContentType = "application/json";
|
|
8
|
+
/**
|
|
9
|
+
* The invocation operations, keyed by the last segment of their path.
|
|
10
|
+
*/
|
|
11
|
+
export const simSdkWireBedrockActions = new Map([
|
|
12
|
+
[
|
|
13
|
+
"converse",
|
|
14
|
+
{
|
|
15
|
+
commandName: "ConverseCommand",
|
|
16
|
+
input: simSdkWireConverseInput,
|
|
17
|
+
outputResponse: (output) => Promise.resolve(simSdkWireOutputResponse(output, simSdkWireBedrockJsonContentType)),
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
"converse-stream",
|
|
22
|
+
{
|
|
23
|
+
commandName: "ConverseStreamCommand",
|
|
24
|
+
input: simSdkWireConverseInput,
|
|
25
|
+
outputResponse: async (output) => await eventStreamResponse(output.stream, {}),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
"invoke",
|
|
30
|
+
{
|
|
31
|
+
commandName: "InvokeModelCommand",
|
|
32
|
+
input: (modelId, request) => simSdkWireInvokeInput(modelId, request, "accept"),
|
|
33
|
+
outputResponse: invokeModelResponse,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
"invoke-with-response-stream",
|
|
38
|
+
{
|
|
39
|
+
commandName: "InvokeModelWithResponseStreamCommand",
|
|
40
|
+
input: (modelId, request) => simSdkWireInvokeInput(modelId, request, "x-amzn-bedrock-accept"),
|
|
41
|
+
outputResponse: async (output) => {
|
|
42
|
+
const { body, contentType } = output;
|
|
43
|
+
return await eventStreamResponse(body, {
|
|
44
|
+
"x-amzn-bedrock-content-type": contentType,
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
]);
|
|
50
|
+
/**
|
|
51
|
+
* `InvokeModel` answers with the model's own body as it is, labelled with its
|
|
52
|
+
* content type.
|
|
53
|
+
*/
|
|
54
|
+
function invokeModelResponse(output) {
|
|
55
|
+
const { body, contentType } = output;
|
|
56
|
+
return Promise.resolve({
|
|
57
|
+
statusCode: 200,
|
|
58
|
+
headers: { "content-type": contentType },
|
|
59
|
+
body,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The streaming operations answer with an event stream body.
|
|
64
|
+
*/
|
|
65
|
+
async function eventStreamResponse(events, headers) {
|
|
66
|
+
return {
|
|
67
|
+
statusCode: 200,
|
|
68
|
+
headers: { "content-type": simSdkWireEventStreamContentType, ...headers },
|
|
69
|
+
body: await simSdkWireEventStreamBody(events),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SimSdkWireRequest } from "./sim-sdk-wire.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `Converse` and `ConverseStream` send their input as the JSON body, less the
|
|
4
|
+
* model id the path carries.
|
|
5
|
+
*/
|
|
6
|
+
export declare function simSdkWireConverseInput(modelId: string, request: SimSdkWireRequest): unknown;
|
|
7
|
+
/**
|
|
8
|
+
* The model invocations send the request body as it is, with every other
|
|
9
|
+
* member in a header.
|
|
10
|
+
*/
|
|
11
|
+
export declare function simSdkWireInvokeInput(modelId: string, request: SimSdkWireRequest, acceptHeaderName: string): unknown;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readSimSdkWireInput } from "./sim-sdk-wire-json.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Command input members `InvokeModel` and
|
|
4
|
+
* `InvokeModelWithResponseStream` carry in headers, with the header each one
|
|
5
|
+
* travels in. The two differ only in where they carry `accept`.
|
|
6
|
+
*
|
|
7
|
+
* Every one is read, including the ones the simulation refuses, so that a
|
|
8
|
+
* request naming a guardrail is refused here as it is through an intercepted
|
|
9
|
+
* client.
|
|
10
|
+
*/
|
|
11
|
+
const invokeHeaderMembers = [
|
|
12
|
+
["contentType", "content-type"],
|
|
13
|
+
["trace", "x-amzn-bedrock-trace"],
|
|
14
|
+
["guardrailIdentifier", "x-amzn-bedrock-guardrailidentifier"],
|
|
15
|
+
["guardrailVersion", "x-amzn-bedrock-guardrailversion"],
|
|
16
|
+
["performanceConfigLatency", "x-amzn-bedrock-performanceconfig-latency"],
|
|
17
|
+
["serviceTier", "x-amzn-bedrock-service-tier"],
|
|
18
|
+
["requestMetadata", "x-amzn-bedrock-request-metadata"],
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* `Converse` and `ConverseStream` send their input as the JSON body, less the
|
|
22
|
+
* model id the path carries.
|
|
23
|
+
*/
|
|
24
|
+
export function simSdkWireConverseInput(modelId, request) {
|
|
25
|
+
return { ...readSimSdkWireInput(request.body), modelId };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The model invocations send the request body as it is, with every other
|
|
29
|
+
* member in a header.
|
|
30
|
+
*/
|
|
31
|
+
export function simSdkWireInvokeInput(modelId, request, acceptHeaderName) {
|
|
32
|
+
const members = [
|
|
33
|
+
...invokeHeaderMembers,
|
|
34
|
+
["accept", acceptHeaderName],
|
|
35
|
+
].flatMap(([member, headerName]) => {
|
|
36
|
+
// oxlint-disable-next-line security/detect-object-injection -- this module's own fixed header names.
|
|
37
|
+
const value = request.headers[headerName];
|
|
38
|
+
return value === undefined ? [] : [[member, value]];
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
...Object.fromEntries(members),
|
|
42
|
+
modelId,
|
|
43
|
+
...(request.body.byteLength > 0 && { body: request.body }),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SimSdkWireCall } from "./sim-sdk-wire-call.js";
|
|
2
|
+
import type { SimSdkWireRequest } from "./sim-sdk-wire.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read a Bedrock Runtime model invocation, which names its operation and its
|
|
5
|
+
* model in the path rather than in a header.
|
|
6
|
+
*
|
|
7
|
+
* A request counts as one when it was signed for Bedrock, or, unsigned, sent
|
|
8
|
+
* to a Bedrock Runtime endpoint, and its path is a model invocation.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readSimSdkWireBedrockCall(request: SimSdkWireRequest): SimSdkWireCall | undefined;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { simSdkWireBedrockActions, simSdkWireBedrockJsonContentType, } from "./sim-sdk-wire-bedrock-action.js";
|
|
2
|
+
import { readSimSdkWireCredentialScope } from "./sim-sdk-wire-operation.js";
|
|
3
|
+
import { simSdkWireErrorResponse } from "./sim-sdk-wire-response.js";
|
|
4
|
+
/**
|
|
5
|
+
* The SDK `config.serviceId` of a `BedrockRuntimeClient`.
|
|
6
|
+
*/
|
|
7
|
+
const bedrockRuntimeServiceId = "Bedrock Runtime";
|
|
8
|
+
/**
|
|
9
|
+
* The SigV4 signing name Bedrock Runtime requests are signed with.
|
|
10
|
+
*/
|
|
11
|
+
const bedrockSigningName = "bedrock";
|
|
12
|
+
/**
|
|
13
|
+
* The path of a model invocation: `/model/{modelId}/{action}`, where the
|
|
14
|
+
* model id is URL-encoded and may be a whole ARN.
|
|
15
|
+
*/
|
|
16
|
+
const invocationPathPattern = /^\/model\/(?<modelId>[^/]+)\/(?<action>[a-z-]+)$/;
|
|
17
|
+
/**
|
|
18
|
+
* Read a Bedrock Runtime model invocation, which names its operation and its
|
|
19
|
+
* model in the path rather than in a header.
|
|
20
|
+
*
|
|
21
|
+
* A request counts as one when it was signed for Bedrock, or, unsigned, sent
|
|
22
|
+
* to a Bedrock Runtime endpoint, and its path is a model invocation.
|
|
23
|
+
*/
|
|
24
|
+
export function readSimSdkWireBedrockCall(request) {
|
|
25
|
+
const signingName = readSimSdkWireCredentialScope(request)?.signingName;
|
|
26
|
+
const isBedrock = signingName === undefined
|
|
27
|
+
? request.hostname.startsWith("bedrock-runtime.")
|
|
28
|
+
: signingName === bedrockSigningName;
|
|
29
|
+
if (!isBedrock || request.method.toUpperCase() !== "POST") {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
const groups = invocationPathPattern.exec(request.path.split("?", 1)[0] ?? "")?.groups;
|
|
33
|
+
const action = simSdkWireBedrockActions.get(groups?.["action"] ?? "");
|
|
34
|
+
if (groups === undefined || action === undefined) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
// A malformed escape fails decoding, which is the service's answer to the
|
|
38
|
+
// request, so the model id is decoded when the input is read.
|
|
39
|
+
const encodedModelId = groups["modelId"] ?? "";
|
|
40
|
+
return {
|
|
41
|
+
serviceId: bedrockRuntimeServiceId,
|
|
42
|
+
commandName: action.commandName,
|
|
43
|
+
input: () => action.input(decodeURIComponent(encodedModelId), request),
|
|
44
|
+
outputResponse: async (output) => await action.outputResponse(output),
|
|
45
|
+
errorResponse: (error) => simSdkWireErrorResponse(error, simSdkWireBedrockJsonContentType),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SimSdkWireRequest, SimSdkWireResponse } from "./sim-sdk-wire.types.js";
|
|
2
|
+
/**
|
|
3
|
+
* One wire request read back into the Command it was serialized from, with
|
|
4
|
+
* the protocol it came in to encode the answer in.
|
|
5
|
+
*/
|
|
6
|
+
export interface SimSdkWireCall {
|
|
7
|
+
/** The SDK `config.serviceId` of the service the request is addressed to. */
|
|
8
|
+
readonly serviceId: string;
|
|
9
|
+
/** The SDK Command class name the request would have been sent as. */
|
|
10
|
+
readonly commandName: string;
|
|
11
|
+
/**
|
|
12
|
+
* The Command input. Reading it can fail on a malformed body, and that
|
|
13
|
+
* failure is the service's answer to the request, so it is read when the
|
|
14
|
+
* operation runs.
|
|
15
|
+
*/
|
|
16
|
+
input(): unknown;
|
|
17
|
+
/** The response for an output the simulated operation answered with. */
|
|
18
|
+
outputResponse(output: unknown): Promise<SimSdkWireResponse>;
|
|
19
|
+
/** The response for an error the simulated operation refused with. */
|
|
20
|
+
errorResponse(error: unknown): SimSdkWireResponse;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Read a wire request as the Command it was serialized from.
|
|
24
|
+
*
|
|
25
|
+
* Returns undefined for a request no reader here understands. The AWS JSON
|
|
26
|
+
* protocol services all name their operation in one header. Bedrock Runtime
|
|
27
|
+
* speaks REST-JSON, with the operation and model in the path, and has a
|
|
28
|
+
* reader of its own.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readSimSdkWireCall(request: SimSdkWireRequest): SimSdkWireCall | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readSimSdkWireBedrockCall } from "./sim-sdk-wire-bedrock.js";
|
|
2
|
+
import { readSimSdkWireInput } from "./sim-sdk-wire-json.js";
|
|
3
|
+
import { readSimSdkWireOperation } from "./sim-sdk-wire-operation.js";
|
|
4
|
+
import { simSdkWireErrorResponse, simSdkWireOutputResponse, } from "./sim-sdk-wire-response.js";
|
|
5
|
+
/**
|
|
6
|
+
* Read a wire request as the Command it was serialized from.
|
|
7
|
+
*
|
|
8
|
+
* Returns undefined for a request no reader here understands. The AWS JSON
|
|
9
|
+
* protocol services all name their operation in one header. Bedrock Runtime
|
|
10
|
+
* speaks REST-JSON, with the operation and model in the path, and has a
|
|
11
|
+
* reader of its own.
|
|
12
|
+
*/
|
|
13
|
+
export function readSimSdkWireCall(request) {
|
|
14
|
+
return readSimSdkWireJsonCall(request) ?? readSimSdkWireBedrockCall(request);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Read an AWS JSON protocol request, whose body is the Command input and
|
|
18
|
+
* whose response echoes the protocol version it was sent with.
|
|
19
|
+
*/
|
|
20
|
+
function readSimSdkWireJsonCall(request) {
|
|
21
|
+
const operation = readSimSdkWireOperation(request);
|
|
22
|
+
if (operation === undefined) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const contentType = request.headers["content-type"];
|
|
26
|
+
return {
|
|
27
|
+
...operation,
|
|
28
|
+
input: () => readSimSdkWireInput(request.body),
|
|
29
|
+
outputResponse: (output) => Promise.resolve(simSdkWireOutputResponse(output, contentType)),
|
|
30
|
+
errorResponse: (error) => simSdkWireErrorResponse(error, contentType),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { SimSdkCommandDispatcher } from "../sim-sdk-command-dispatcher.js";
|
|
2
2
|
import { makeSimSdkWireClient, makeSimSdkWireCommand, } from "./sim-sdk-wire-command.js";
|
|
3
|
-
import {
|
|
4
|
-
import { readSimSdkWireCredentialScope
|
|
5
|
-
import { simSdkWireErrorResponse, simSdkWireOutputResponse, } from "./sim-sdk-wire-response.js";
|
|
3
|
+
import { readSimSdkWireCall } from "./sim-sdk-wire-call.js";
|
|
4
|
+
import { readSimSdkWireCredentialScope } from "./sim-sdk-wire-operation.js";
|
|
6
5
|
import { simSdkUnbridgedWireRequest } from "./sim-sdk-wire-unbridged.js";
|
|
7
6
|
/**
|
|
8
7
|
* Dispatches AWS API requests to simulated AWS service operations.
|
|
@@ -44,20 +43,19 @@ export class SimSdkWireDispatcher {
|
|
|
44
43
|
* relies on.
|
|
45
44
|
*/
|
|
46
45
|
async dispatch(request, caller) {
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
46
|
+
const call = readSimSdkWireCall(request);
|
|
47
|
+
if (call === undefined) {
|
|
49
48
|
throw simSdkUnbridgedWireRequest(request);
|
|
50
49
|
}
|
|
51
50
|
// The operation runs in the Region it was signed for or, unsigned, the
|
|
52
51
|
// Region of the code that sent it.
|
|
53
52
|
const scope = readSimSdkWireCredentialScope(request);
|
|
54
|
-
const contentType = request.headers["content-type"];
|
|
55
53
|
try {
|
|
56
|
-
const output = await this.dispatcher.dispatch(makeSimSdkWireCommand(
|
|
57
|
-
return
|
|
54
|
+
const output = await this.dispatcher.dispatch(makeSimSdkWireCommand(call.commandName, call.input()), makeSimSdkWireClient(call.serviceId, scope?.regionName ?? this.regionName), undefined, caller);
|
|
55
|
+
return await call.outputResponse(output);
|
|
58
56
|
}
|
|
59
57
|
catch (error) {
|
|
60
|
-
return
|
|
58
|
+
return call.errorResponse(error);
|
|
61
59
|
}
|
|
62
60
|
}
|
|
63
61
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The media type of an AWS event stream response body.
|
|
3
|
+
*/
|
|
4
|
+
export declare const simSdkWireEventStreamContentType = "application/vnd.amazon.eventstream";
|
|
5
|
+
/**
|
|
6
|
+
* Encode an event stream as the `application/vnd.amazon.eventstream` body an
|
|
7
|
+
* SDK reads it from.
|
|
8
|
+
*
|
|
9
|
+
* Each event is a union with one member set, as an SDK hands it to calling
|
|
10
|
+
* code (`{ chunk: { bytes } }` or `{ contentBlockDelta: { ... } }`). The
|
|
11
|
+
* member name is the message's event type, and its value is the JSON payload.
|
|
12
|
+
*
|
|
13
|
+
* The whole stream is read before the body is built. A simulated stream has
|
|
14
|
+
* every event available at once, so sending them together loses nothing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function simSdkWireEventStreamBody(events: AsyncIterable<object>): Promise<Uint8Array>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { crc32 } from "../../util/zip/crc32.js";
|
|
2
|
+
import { simSdkWireJsonBody } from "./sim-sdk-wire-json.js";
|
|
3
|
+
/**
|
|
4
|
+
* The media type of an AWS event stream response body.
|
|
5
|
+
*/
|
|
6
|
+
export const simSdkWireEventStreamContentType = "application/vnd.amazon.eventstream";
|
|
7
|
+
/**
|
|
8
|
+
* The header value type code for a string, the only type written here.
|
|
9
|
+
*/
|
|
10
|
+
const stringHeaderType = 7;
|
|
11
|
+
/**
|
|
12
|
+
* The bytes of the prelude: the total length, the headers length and the
|
|
13
|
+
* prelude checksum, each four bytes.
|
|
14
|
+
*/
|
|
15
|
+
const preludeLength = 12;
|
|
16
|
+
/**
|
|
17
|
+
* The bytes of the checksum closing every message.
|
|
18
|
+
*/
|
|
19
|
+
const messageChecksumLength = 4;
|
|
20
|
+
/**
|
|
21
|
+
* Encode an event stream as the `application/vnd.amazon.eventstream` body an
|
|
22
|
+
* SDK reads it from.
|
|
23
|
+
*
|
|
24
|
+
* Each event is a union with one member set, as an SDK hands it to calling
|
|
25
|
+
* code (`{ chunk: { bytes } }` or `{ contentBlockDelta: { ... } }`). The
|
|
26
|
+
* member name is the message's event type, and its value is the JSON payload.
|
|
27
|
+
*
|
|
28
|
+
* The whole stream is read before the body is built. A simulated stream has
|
|
29
|
+
* every event available at once, so sending them together loses nothing.
|
|
30
|
+
*/
|
|
31
|
+
export async function simSdkWireEventStreamBody(events) {
|
|
32
|
+
const messages = [];
|
|
33
|
+
for await (const event of events) {
|
|
34
|
+
const members = Object.entries(event).filter(([, value]) => value !== undefined);
|
|
35
|
+
for (const [eventType, value] of members) {
|
|
36
|
+
messages.push(eventMessage(eventType, simSdkWireJsonBody(value)));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Buffer.concat(messages);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Encode one event message.
|
|
43
|
+
*
|
|
44
|
+
* The layout is the prelude, the headers, the payload and a CRC-32 of
|
|
45
|
+
* everything before it. The prelude ends with a CRC-32 of its first eight
|
|
46
|
+
* bytes.
|
|
47
|
+
*/
|
|
48
|
+
function eventMessage(eventType, payload) {
|
|
49
|
+
const headers = Buffer.concat([
|
|
50
|
+
stringHeader(":event-type", eventType),
|
|
51
|
+
stringHeader(":content-type", "application/json"),
|
|
52
|
+
stringHeader(":message-type", "event"),
|
|
53
|
+
]);
|
|
54
|
+
const totalLength = preludeLength + headers.length + payload.length + messageChecksumLength;
|
|
55
|
+
const checksumOffset = totalLength - messageChecksumLength;
|
|
56
|
+
const message = Buffer.alloc(totalLength);
|
|
57
|
+
message.writeUInt32BE(totalLength, 0);
|
|
58
|
+
message.writeUInt32BE(headers.length, 4);
|
|
59
|
+
message.writeUInt32BE(crc32(message.subarray(0, 8)), 8);
|
|
60
|
+
headers.copy(message, preludeLength);
|
|
61
|
+
message.set(payload, preludeLength + headers.length);
|
|
62
|
+
message.writeUInt32BE(crc32(message.subarray(0, checksumOffset)), checksumOffset);
|
|
63
|
+
return message;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Encode one string-valued header: the name length and name, the type code,
|
|
67
|
+
* and the value length and value.
|
|
68
|
+
*/
|
|
69
|
+
function stringHeader(name, value) {
|
|
70
|
+
const nameBytes = Buffer.from(name);
|
|
71
|
+
const valueBytes = Buffer.from(value);
|
|
72
|
+
const header = Buffer.alloc(4 + nameBytes.length + valueBytes.length);
|
|
73
|
+
header.writeUInt8(nameBytes.length, 0);
|
|
74
|
+
nameBytes.copy(header, 1);
|
|
75
|
+
header.writeUInt8(stringHeaderType, 1 + nameBytes.length);
|
|
76
|
+
header.writeUInt16BE(valueBytes.length, 2 + nameBytes.length);
|
|
77
|
+
valueBytes.copy(header, 4 + nameBytes.length);
|
|
78
|
+
return header;
|
|
79
|
+
}
|
|
@@ -16,8 +16,8 @@ import { readSimSdkWireCredentialScope } from "./sim-sdk-wire-operation.js";
|
|
|
16
16
|
export function simSdkUnbridgedWireRequest(request) {
|
|
17
17
|
const service = readSimSdkWireCredentialScope(request)?.signingName ?? request.hostname;
|
|
18
18
|
return new SimSdkUnbridgedWireRequestError(`Cannot answer a request to ${service} from the simulation: a ` +
|
|
19
|
-
"serialized AWS API request can only be routed for
|
|
20
|
-
"the AWS JSON protocol. Where this is an AWS SDK bundled into " +
|
|
19
|
+
"serialized AWS API request can only be routed for S3, Bedrock " +
|
|
20
|
+
"Runtime and the services using the AWS JSON protocol. Where this is an AWS SDK bundled into " +
|
|
21
21
|
"function code, leaving the SDK out of the deployment package puts it " +
|
|
22
22
|
"back on the module interception path, which every simulated service " +
|
|
23
23
|
"is reachable through.");
|
|
@@ -57,7 +57,7 @@ function joined(array, delimiter, absent) {
|
|
|
57
57
|
* One element written out.
|
|
58
58
|
*
|
|
59
59
|
* Trino refuses to join an array whose elements are not text, and raising here
|
|
60
|
-
*
|
|
60
|
+
* fails the query the same way.
|
|
61
61
|
*/
|
|
62
62
|
function scalarText(value) {
|
|
63
63
|
if (typeof value === "string") {
|
|
@@ -3,8 +3,8 @@ import type { SQLOutputValue } from "node:sqlite";
|
|
|
3
3
|
* One encoded string read back to bytes, or null where it is null.
|
|
4
4
|
*
|
|
5
5
|
* Trino fails the query over text the encoding cannot carry, and `Buffer` reads
|
|
6
|
-
* as much of it as it can and drops the rest. Raising here
|
|
7
|
-
*
|
|
6
|
+
* as much of it as it can and drops the rest. Raising here fails the query the
|
|
7
|
+
* way Trino does.
|
|
8
8
|
*/
|
|
9
9
|
export declare function simAthenaDecodedText(text: string | undefined, encoding: "base64" | "hex"): Uint8Array | null;
|
|
10
10
|
/**
|
|
@@ -20,8 +20,8 @@ const encodedReplacement = Buffer.from([0xef, 0xbf, 0xbd]);
|
|
|
20
20
|
* One encoded string read back to bytes, or null where it is null.
|
|
21
21
|
*
|
|
22
22
|
* Trino fails the query over text the encoding cannot carry, and `Buffer` reads
|
|
23
|
-
* as much of it as it can and drops the rest. Raising here
|
|
24
|
-
*
|
|
23
|
+
* as much of it as it can and drops the rest. Raising here fails the query the
|
|
24
|
+
* way Trino does.
|
|
25
25
|
*/
|
|
26
26
|
export function simAthenaDecodedText(text, encoding) {
|
|
27
27
|
if (text === undefined) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SimAthenaCatalogTable } from "../table/sim-athena-catalog-table.js";
|
|
2
|
+
/**
|
|
3
|
+
* The shims a cast to `DATE` and to `TIMESTAMP` are handed to.
|
|
4
|
+
*
|
|
5
|
+
* The names have the simulator's prefix so that neither can collide with a
|
|
6
|
+
* Trino function a statement calls itself.
|
|
7
|
+
*/
|
|
8
|
+
export declare const simAthenaDateCast = "sim_athena_cast_date";
|
|
9
|
+
export declare const simAthenaTimestampCast = "sim_athena_cast_timestamp";
|
|
10
|
+
/** The second argument a shim is handed where the value it casts is text. */
|
|
11
|
+
export declare const simAthenaCastSource = "varchar";
|
|
12
|
+
/**
|
|
13
|
+
* Hand every cast to `DATE` or `TIMESTAMP` in the tree to the engine's shims.
|
|
14
|
+
*
|
|
15
|
+
* SQLite gives a column declared `DATE` or `TIMESTAMP` numeric affinity, so a
|
|
16
|
+
* plain `CAST('2026-08-15' AS DATE)` keeps the leading number and answers
|
|
17
|
+
* `2026`. Every date function downstream of that cast then reads a year where
|
|
18
|
+
* it expected a date.
|
|
19
|
+
*
|
|
20
|
+
* Trino's one-argument `date(x)` is the cast to `DATE` under another name,
|
|
21
|
+
* and it goes to the same shim. SQLite's own `date()` answers null over text
|
|
22
|
+
* that is no date, where Trino fails the cast.
|
|
23
|
+
*
|
|
24
|
+
* Trino reads text more strictly than a value already typed as a timestamp,
|
|
25
|
+
* and the shim is told which it has. A string literal and a column the catalog
|
|
26
|
+
* declares as text are text. Anything else is taken to be a date or a
|
|
27
|
+
* timestamp already, since the engine cannot tell the type a function answers
|
|
28
|
+
* with.
|
|
29
|
+
*/
|
|
30
|
+
export declare function simAthenaRewriteCasts(ast: unknown, tables: readonly SimAthenaCatalogTable[]): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { asAstNode, isColumnRef, replaceNode, simAthenaAstNodes, simAthenaCalledName, } from "./sim-athena-ast-nodes.js";
|
|
2
|
+
/**
|
|
3
|
+
* The shims a cast to `DATE` and to `TIMESTAMP` are handed to.
|
|
4
|
+
*
|
|
5
|
+
* The names have the simulator's prefix so that neither can collide with a
|
|
6
|
+
* Trino function a statement calls itself.
|
|
7
|
+
*/
|
|
8
|
+
export const simAthenaDateCast = "sim_athena_cast_date";
|
|
9
|
+
export const simAthenaTimestampCast = "sim_athena_cast_timestamp";
|
|
10
|
+
/** The second argument a shim is handed where the value it casts is text. */
|
|
11
|
+
export const simAthenaCastSource = "varchar";
|
|
12
|
+
/** The shim each cast target goes to. */
|
|
13
|
+
const castShims = new Map([
|
|
14
|
+
["DATE", simAthenaDateCast],
|
|
15
|
+
["TIMESTAMP", simAthenaTimestampCast],
|
|
16
|
+
]);
|
|
17
|
+
/** The Glue types a column of text is declared with. */
|
|
18
|
+
const textTypes = /^(?:string|varchar|char)\b/iu;
|
|
19
|
+
/**
|
|
20
|
+
* Hand every cast to `DATE` or `TIMESTAMP` in the tree to the engine's shims.
|
|
21
|
+
*
|
|
22
|
+
* SQLite gives a column declared `DATE` or `TIMESTAMP` numeric affinity, so a
|
|
23
|
+
* plain `CAST('2026-08-15' AS DATE)` keeps the leading number and answers
|
|
24
|
+
* `2026`. Every date function downstream of that cast then reads a year where
|
|
25
|
+
* it expected a date.
|
|
26
|
+
*
|
|
27
|
+
* Trino's one-argument `date(x)` is the cast to `DATE` under another name,
|
|
28
|
+
* and it goes to the same shim. SQLite's own `date()` answers null over text
|
|
29
|
+
* that is no date, where Trino fails the cast.
|
|
30
|
+
*
|
|
31
|
+
* Trino reads text more strictly than a value already typed as a timestamp,
|
|
32
|
+
* and the shim is told which it has. A string literal and a column the catalog
|
|
33
|
+
* declares as text are text. Anything else is taken to be a date or a
|
|
34
|
+
* timestamp already, since the engine cannot tell the type a function answers
|
|
35
|
+
* with.
|
|
36
|
+
*/
|
|
37
|
+
export function simAthenaRewriteCasts(ast, tables) {
|
|
38
|
+
const textColumns = textColumnsOf(tables);
|
|
39
|
+
for (const node of simAthenaAstNodes(ast)) {
|
|
40
|
+
const cast = castOf(node);
|
|
41
|
+
if (cast !== undefined) {
|
|
42
|
+
replaceNode(node, {
|
|
43
|
+
type: "function",
|
|
44
|
+
name: { name: [{ type: "default", value: cast.shim }] },
|
|
45
|
+
args: {
|
|
46
|
+
type: "expr_list",
|
|
47
|
+
value: [cast.value, sourceOf(cast.value, textColumns)],
|
|
48
|
+
},
|
|
49
|
+
over: null,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function castOf(node) {
|
|
55
|
+
if (node["type"] === "cast") {
|
|
56
|
+
const shim = castShims.get(targetOf(node["target"]));
|
|
57
|
+
return shim === undefined ? undefined : { shim, value: node["expr"] };
|
|
58
|
+
}
|
|
59
|
+
const values = asAstNode(node["args"])?.["value"];
|
|
60
|
+
if (node["type"] !== "function" ||
|
|
61
|
+
simAthenaCalledName(node)?.toLowerCase() !== "date" ||
|
|
62
|
+
!Array.isArray(values) ||
|
|
63
|
+
values.length !== 1) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return { shim: simAthenaDateCast, value: values[0] };
|
|
67
|
+
}
|
|
68
|
+
/** The one type a cast names, upper cased, or nothing for anything else. */
|
|
69
|
+
function targetOf(target) {
|
|
70
|
+
const only = Array.isArray(target) && target.length === 1 ? target[0] : null;
|
|
71
|
+
const dataType = asAstNode(only)?.["dataType"];
|
|
72
|
+
return typeof dataType === "string" ? dataType.toUpperCase() : "";
|
|
73
|
+
}
|
|
74
|
+
/** The second argument that tells the shim whether its value is text. */
|
|
75
|
+
function sourceOf(value, textColumns) {
|
|
76
|
+
const node = asAstNode(value);
|
|
77
|
+
const isText = node?.["type"] === "single_quote_string" ||
|
|
78
|
+
(node !== undefined &&
|
|
79
|
+
isColumnRef(node) &&
|
|
80
|
+
textColumns.has(node.column.toLowerCase()));
|
|
81
|
+
return {
|
|
82
|
+
type: "single_quote_string",
|
|
83
|
+
value: isText ? simAthenaCastSource : "",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Every column name the tables declare as text and as nothing else.
|
|
88
|
+
*
|
|
89
|
+
* A name two tables declare with different types is left out, since the
|
|
90
|
+
* statement could mean either and only text is held to the stricter read.
|
|
91
|
+
*/
|
|
92
|
+
function textColumnsOf(tables) {
|
|
93
|
+
const text = new Set();
|
|
94
|
+
const other = new Set();
|
|
95
|
+
for (const table of tables) {
|
|
96
|
+
for (const column of [...table.columns, ...table.partitionKeys]) {
|
|
97
|
+
const name = column.Name.toLowerCase();
|
|
98
|
+
if (textTypes.test(column.Type ?? "")) {
|
|
99
|
+
text.add(name);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
other.add(name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return text.difference(other);
|
|
107
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
/**
|
|
3
|
+
* Trino's casts to `DATE` and `TIMESTAMP`, which SQLite cannot do itself.
|
|
4
|
+
*
|
|
5
|
+
* SQLite gives both types numeric affinity, so its own cast of
|
|
6
|
+
* `'2026-08-15'` answers `2026`. The statement's casts are rewritten onto
|
|
7
|
+
* these shims before it runs, and the rewrite says whether the value is text.
|
|
8
|
+
*
|
|
9
|
+
* A value the cast cannot read fails the query with Trino's own message, the
|
|
10
|
+
* way Athena fails it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function simAthenaInstallCastShims(database: DatabaseSync): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SimAthenaSetUpError } from "../error/sim-athena.error.js";
|
|
2
|
+
import { simAthenaCastSource, simAthenaDateCast, simAthenaTimestampCast, } from "./sim-athena-cast-rewrite.js";
|
|
3
|
+
import { simAthenaCastInstant, simAthenaCastRendered, } from "./sim-athena-cast-text.js";
|
|
4
|
+
import { shimText, simAthenaScalarShim } from "./sim-athena-shim-registry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Trino's casts to `DATE` and `TIMESTAMP`, which SQLite cannot do itself.
|
|
7
|
+
*
|
|
8
|
+
* SQLite gives both types numeric affinity, so its own cast of
|
|
9
|
+
* `'2026-08-15'` answers `2026`. The statement's casts are rewritten onto
|
|
10
|
+
* these shims before it runs, and the rewrite says whether the value is text.
|
|
11
|
+
*
|
|
12
|
+
* A value the cast cannot read fails the query with Trino's own message, the
|
|
13
|
+
* way Athena fails it.
|
|
14
|
+
*/
|
|
15
|
+
export function simAthenaInstallCastShims(database) {
|
|
16
|
+
simAthenaScalarShim(database, simAthenaDateCast, (value, source) => cast(value, source, "date"), "CAST(... AS DATE)");
|
|
17
|
+
simAthenaScalarShim(database, simAthenaTimestampCast, (value, source) => cast(value, source, "timestamp"), "CAST(... AS TIMESTAMP)");
|
|
18
|
+
}
|
|
19
|
+
function cast(value, source, type) {
|
|
20
|
+
const text = shimText(value);
|
|
21
|
+
if (text === undefined) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const instant = simAthenaCastInstant(text, type, source === simAthenaCastSource);
|
|
25
|
+
if (instant === undefined) {
|
|
26
|
+
throw new SimAthenaSetUpError(`Value cannot be cast to ${type}: ${text}`);
|
|
27
|
+
}
|
|
28
|
+
return simAthenaCastRendered(instant, type);
|
|
29
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The two types a cast in the engine reads a value as. */
|
|
2
|
+
export type SimAthenaCastType = "date" | "timestamp";
|
|
3
|
+
/**
|
|
4
|
+
* The instant one value names as the cast reads it, or nothing where the cast
|
|
5
|
+
* fails.
|
|
6
|
+
*
|
|
7
|
+
* Text is held to the formats Trino's cast from `varchar` takes. Any other
|
|
8
|
+
* source is a value some column or function already typed as a date or a
|
|
9
|
+
* timestamp, written as the ISO-8601 text the engine holds one as.
|
|
10
|
+
*/
|
|
11
|
+
export declare function simAthenaCastInstant(text: string, type: SimAthenaCastType, fromText: boolean): number | undefined;
|
|
12
|
+
/** One instant rendered as Athena renders a value of the type. */
|
|
13
|
+
export declare function simAthenaCastRendered(instant: number, type: SimAthenaCastType): string;
|