sst 2.8.23 → 2.8.25
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/constructs/Api.js +1 -0
- package/constructs/Job.js +1 -1
- package/constructs/NextjsSite.d.ts +6 -0
- package/constructs/NextjsSite.js +59 -5
- package/constructs/WebSocketApi.d.ts +1 -1
- package/constructs/WebSocketApi.js +5 -1
- package/context/handler.d.ts +12 -3
- package/context/handler.js +4 -0
- package/node/api/index.d.ts +2 -4
- package/node/api/index.js +9 -7
- package/node/auth/session.js +13 -1
- package/node/future/auth/adapter/microsoft.d.ts +20 -0
- package/node/future/auth/adapter/microsoft.js +14 -0
- package/node/future/auth/index.d.ts +1 -0
- package/node/future/auth/index.js +1 -0
- package/node/future/auth/session.js +13 -1
- package/node/graphql/index.js +4 -1
- package/node/websocket-api/index.d.ts +23 -0
- package/node/websocket-api/index.js +48 -0
- package/package.json +3 -4
- package/runtime/handlers/java.js +2 -2
- package/sst.mjs +2 -2
- package/support/custom-resources/index.mjs +14197 -0
package/constructs/Api.js
CHANGED
|
@@ -586,6 +586,7 @@ export class Api extends Construct {
|
|
|
586
586
|
}, postfixName);
|
|
587
587
|
const data = this.routesData[routeKey];
|
|
588
588
|
if (data.type === "function") {
|
|
589
|
+
data.function.addEnvironment("GRAPHQL_ENDPOINT", routeKey.split(" ")[1]);
|
|
589
590
|
this.routesData[routeKey] = {
|
|
590
591
|
...data,
|
|
591
592
|
type: "graphql",
|
package/constructs/Job.js
CHANGED
|
@@ -249,13 +249,13 @@ export class Job extends Construct {
|
|
|
249
249
|
// in the Console.
|
|
250
250
|
const fn = new Function(this, this.node.id, {
|
|
251
251
|
runtime: "nodejs16.x",
|
|
252
|
-
timeout: "15 minutes",
|
|
253
252
|
memorySize: 1024,
|
|
254
253
|
environment: {
|
|
255
254
|
...this.props.environment,
|
|
256
255
|
SST_DEBUG_TYPE: "job",
|
|
257
256
|
},
|
|
258
257
|
...this.props,
|
|
258
|
+
timeout: "15 minutes",
|
|
259
259
|
});
|
|
260
260
|
fn._doNotAllowOthersToBind = true;
|
|
261
261
|
return fn;
|
|
@@ -16,6 +16,11 @@ export interface NextjsSiteProps extends Omit<SsrSiteProps, "nodejs"> {
|
|
|
16
16
|
*/
|
|
17
17
|
memorySize?: number | Size;
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* The number of server functions to keep warm. This option is only supported for the regional mode.
|
|
21
|
+
* @default Server function is not kept warm
|
|
22
|
+
*/
|
|
23
|
+
warm?: number;
|
|
19
24
|
}
|
|
20
25
|
/**
|
|
21
26
|
* The `NextjsSite` construct is a higher level CDK construct that makes it easy to create a Next.js app.
|
|
@@ -46,6 +51,7 @@ export declare class NextjsSite extends SsrSite {
|
|
|
46
51
|
protected createFunctionForRegional(): CdkFunction;
|
|
47
52
|
protected createFunctionForEdge(): EdgeFunction;
|
|
48
53
|
private createImageOptimizationFunction;
|
|
54
|
+
private createWarmer;
|
|
49
55
|
protected createCloudFrontDistributionForRegional(): Distribution;
|
|
50
56
|
protected createCloudFrontDistributionForEdge(): Distribution;
|
|
51
57
|
private buildServerBehaviorForRegional;
|
package/constructs/NextjsSite.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import url from "url";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { Fn, Duration as CdkDuration, RemovalPolicy } from "aws-cdk-lib";
|
|
4
|
+
import { Fn, Duration as CdkDuration, RemovalPolicy, CustomResource, } from "aws-cdk-lib";
|
|
5
|
+
import { Effect, Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
5
6
|
import { RetentionDays } from "aws-cdk-lib/aws-logs";
|
|
6
7
|
import { Function as CdkFunction, Code, Runtime, Architecture, FunctionUrlAuthType, } from "aws-cdk-lib/aws-lambda";
|
|
7
8
|
import { Distribution, ViewerProtocolPolicy, AllowedMethods, LambdaEdgeEventType, CachedMethods, CachePolicy, } from "aws-cdk-lib/aws-cloudfront";
|
|
8
9
|
import { S3Origin, HttpOrigin, OriginGroup, } from "aws-cdk-lib/aws-cloudfront-origins";
|
|
10
|
+
import { Rule, Schedule } from "aws-cdk-lib/aws-events";
|
|
11
|
+
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
|
|
12
|
+
import { Stack } from "./Stack.js";
|
|
9
13
|
import { SsrFunction } from "./SsrFunction.js";
|
|
10
14
|
import { EdgeFunction } from "./EdgeFunction.js";
|
|
11
15
|
import { SsrSite } from "./SsrSite.js";
|
|
12
16
|
import { toCdkSize } from "./util/size.js";
|
|
13
|
-
import { PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
14
17
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
15
18
|
/**
|
|
16
19
|
* The `NextjsSite` construct is a higher level CDK construct that makes it easy to create a Next.js app.
|
|
@@ -26,9 +29,10 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
|
26
29
|
export class NextjsSite extends SsrSite {
|
|
27
30
|
constructor(scope, id, props) {
|
|
28
31
|
super(scope, id, {
|
|
29
|
-
buildCommand: "npx --yes open-next@~1.
|
|
32
|
+
buildCommand: "npx --yes open-next@~1.3.0 build",
|
|
30
33
|
...props,
|
|
31
34
|
});
|
|
35
|
+
this.createWarmer();
|
|
32
36
|
}
|
|
33
37
|
initBuildConfig() {
|
|
34
38
|
return {
|
|
@@ -41,7 +45,7 @@ export class NextjsSite extends SsrSite {
|
|
|
41
45
|
createFunctionForRegional() {
|
|
42
46
|
const { runtime, timeout, memorySize, bind, permissions, environment, cdk, } = this.props;
|
|
43
47
|
const ssrFn = new SsrFunction(this, `ServerFunction`, {
|
|
44
|
-
description: "
|
|
48
|
+
description: "Next.js server",
|
|
45
49
|
bundle: path.join(this.props.path, ".open-next", "server-function"),
|
|
46
50
|
handler: "index.handler",
|
|
47
51
|
runtime,
|
|
@@ -70,7 +74,7 @@ export class NextjsSite extends SsrSite {
|
|
|
70
74
|
createImageOptimizationFunction() {
|
|
71
75
|
const { imageOptimization, path: sitePath } = this.props;
|
|
72
76
|
return new CdkFunction(this, `ImageFunction`, {
|
|
73
|
-
description: "
|
|
77
|
+
description: "Next.js image optimizer",
|
|
74
78
|
handler: "index.handler",
|
|
75
79
|
currentVersionOptions: {
|
|
76
80
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
@@ -96,6 +100,56 @@ export class NextjsSite extends SsrSite {
|
|
|
96
100
|
],
|
|
97
101
|
});
|
|
98
102
|
}
|
|
103
|
+
createWarmer() {
|
|
104
|
+
const { warm, edge } = this.props;
|
|
105
|
+
if (!warm)
|
|
106
|
+
return;
|
|
107
|
+
if (warm && edge) {
|
|
108
|
+
throw new Error(`Warming is currently supported only for the regional mode.`);
|
|
109
|
+
}
|
|
110
|
+
if (!this.serverLambdaForRegional)
|
|
111
|
+
return;
|
|
112
|
+
// Create warmer function
|
|
113
|
+
const warmer = new CdkFunction(this, "WarmerFunction", {
|
|
114
|
+
description: "Next.js warmer",
|
|
115
|
+
code: Code.fromAsset(path.join(this.props.path, ".open-next/warmer-function")),
|
|
116
|
+
runtime: Runtime.NODEJS_18_X,
|
|
117
|
+
handler: "index.handler",
|
|
118
|
+
timeout: CdkDuration.minutes(15),
|
|
119
|
+
memorySize: 1024,
|
|
120
|
+
environment: {
|
|
121
|
+
FUNCTION_NAME: this.serverLambdaForRegional.functionName,
|
|
122
|
+
CONCURRENCY: warm.toString(),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
this.serverLambdaForRegional.grantInvoke(warmer);
|
|
126
|
+
// Create cron job
|
|
127
|
+
new Rule(this, "WarmerRule", {
|
|
128
|
+
schedule: Schedule.rate(CdkDuration.minutes(5)),
|
|
129
|
+
targets: [new LambdaFunction(warmer, { retryAttempts: 0 })],
|
|
130
|
+
});
|
|
131
|
+
// Create custom resource to prewarm on deploy
|
|
132
|
+
const stack = Stack.of(this);
|
|
133
|
+
const policy = new Policy(this, "PrewarmerPolicy", {
|
|
134
|
+
statements: [
|
|
135
|
+
new PolicyStatement({
|
|
136
|
+
effect: Effect.ALLOW,
|
|
137
|
+
actions: ["lambda:InvokeFunction"],
|
|
138
|
+
resources: [warmer.functionArn],
|
|
139
|
+
}),
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
stack.customResourceHandler.role?.attachInlinePolicy(policy);
|
|
143
|
+
const resource = new CustomResource(this, "Prewarmer", {
|
|
144
|
+
serviceToken: stack.customResourceHandler.functionArn,
|
|
145
|
+
resourceType: "Custom::FunctionInvoker",
|
|
146
|
+
properties: {
|
|
147
|
+
version: Date.now().toString(),
|
|
148
|
+
functionName: warmer.functionName,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
resource.node.addDependency(policy);
|
|
152
|
+
}
|
|
99
153
|
createCloudFrontDistributionForRegional() {
|
|
100
154
|
/**
|
|
101
155
|
* Next.js requests
|
|
@@ -195,12 +195,16 @@ export class WebSocketApi extends Construct {
|
|
|
195
195
|
/** @internal */
|
|
196
196
|
getFunctionBinding() {
|
|
197
197
|
return {
|
|
198
|
-
clientPackage: "api",
|
|
198
|
+
clientPackage: "websocket-api",
|
|
199
199
|
variables: {
|
|
200
200
|
url: {
|
|
201
201
|
type: "plain",
|
|
202
202
|
value: this.customDomainUrl || this.url,
|
|
203
203
|
},
|
|
204
|
+
httpsUrl: {
|
|
205
|
+
type: "plain",
|
|
206
|
+
value: (this.customDomainUrl || this.url).replace("wss://", "https://"),
|
|
207
|
+
},
|
|
204
208
|
},
|
|
205
209
|
permissions: {
|
|
206
210
|
"execute-api:ManageConnections": [this._connectionsArn],
|
package/context/handler.d.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import { APIGatewayProxyEventV2, APIGatewayProxyStructuredResultV2, Context as LambdaContext, SQSBatchResponse, SQSEvent } from "aws-lambda";
|
|
1
|
+
import { APIGatewayProxyEventHeaders, APIGatewayProxyEventMultiValueHeaders, APIGatewayProxyEventMultiValueQueryStringParameters, APIGatewayProxyEventQueryStringParameters, APIGatewayProxyEventV2, APIGatewayProxyResultV2, APIGatewayProxyStructuredResultV2, APIGatewayProxyWebsocketEventV2, Context as LambdaContext, SQSBatchResponse, SQSEvent } from "aws-lambda";
|
|
2
2
|
export interface Handlers {
|
|
3
3
|
api: {
|
|
4
4
|
event: APIGatewayProxyEventV2;
|
|
5
5
|
response: APIGatewayProxyStructuredResultV2 | void;
|
|
6
6
|
};
|
|
7
|
+
ws: {
|
|
8
|
+
event: APIGatewayProxyWebsocketEventV2 & {
|
|
9
|
+
headers?: APIGatewayProxyEventHeaders;
|
|
10
|
+
multiValueHeaders?: APIGatewayProxyEventMultiValueHeaders;
|
|
11
|
+
queryStringParameters?: APIGatewayProxyEventQueryStringParameters | null;
|
|
12
|
+
multiValueQueryStringParameters?: APIGatewayProxyEventMultiValueQueryStringParameters | null;
|
|
13
|
+
};
|
|
14
|
+
response: APIGatewayProxyResultV2;
|
|
15
|
+
};
|
|
7
16
|
sqs: {
|
|
8
17
|
event: SQSEvent;
|
|
9
18
|
response: SQSBatchResponse;
|
|
10
19
|
};
|
|
11
20
|
}
|
|
12
|
-
type HandlerTypes = keyof Handlers;
|
|
21
|
+
export type HandlerTypes = keyof Handlers;
|
|
22
|
+
export declare function useContextType(): HandlerTypes;
|
|
13
23
|
export declare function useEvent<Type extends HandlerTypes>(type: Type): Handlers[Type]["event"];
|
|
14
24
|
export declare function useLambdaContext(): LambdaContext;
|
|
15
25
|
export declare function Handler<Type extends HandlerTypes, Event = Handlers[Type]["event"], Response = Handlers[Type]["response"]>(type: Type, cb: (evt: Event, ctx: LambdaContext) => Promise<Response>): (event: Event, context: LambdaContext) => Promise<Response>;
|
|
16
|
-
export {};
|
package/context/handler.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Context } from "./context.js";
|
|
2
2
|
const RequestContext = Context.create("RequestContext");
|
|
3
|
+
export function useContextType() {
|
|
4
|
+
const ctx = RequestContext.use();
|
|
5
|
+
return ctx.type;
|
|
6
|
+
}
|
|
3
7
|
export function useEvent(type) {
|
|
4
8
|
const ctx = RequestContext.use();
|
|
5
9
|
if (ctx.type !== type)
|
package/node/api/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Handler } from "../../context/handler.js";
|
|
1
|
+
import { Handler, HandlerTypes } from "../../context/handler.js";
|
|
2
2
|
import { APIGatewayProxyStructuredResultV2 } from "aws-lambda";
|
|
3
3
|
export interface ApiResources {
|
|
4
4
|
}
|
|
@@ -6,12 +6,10 @@ export interface AppSyncApiResources {
|
|
|
6
6
|
}
|
|
7
7
|
export interface ApiGatewayV1ApiResources {
|
|
8
8
|
}
|
|
9
|
-
export
|
|
10
|
-
}
|
|
9
|
+
export type ApiHandlerTypes = Extract<HandlerTypes, "api" | "ws">;
|
|
11
10
|
export declare const Api: ApiResources;
|
|
12
11
|
export declare const AppSyncApi: AppSyncApiResources;
|
|
13
12
|
export declare const ApiGatewayV1Api: ApiGatewayV1ApiResources;
|
|
14
|
-
export declare const WebSocketApi: WebSocketApiResources;
|
|
15
13
|
/**
|
|
16
14
|
* Create a new api handler that can be used to create an authenticated session.
|
|
17
15
|
*
|
package/node/api/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { createProxy } from "../util/index.js";
|
|
2
2
|
import { Context } from "../../context/context.js";
|
|
3
|
-
import { useEvent, Handler } from "../../context/handler.js";
|
|
3
|
+
import { useEvent, Handler, useContextType, } from "../../context/handler.js";
|
|
4
4
|
export const Api = /* @__PURE__ */ createProxy("Api");
|
|
5
5
|
export const AppSyncApi =
|
|
6
6
|
/* @__PURE__ */ createProxy("AppSyncApi");
|
|
7
7
|
export const ApiGatewayV1Api =
|
|
8
8
|
/* @__PURE__ */ createProxy("ApiGatewayV1Api");
|
|
9
|
-
export const WebSocketApi =
|
|
10
|
-
/* @__PURE__ */ createProxy("WebSocketApi");
|
|
11
9
|
/**
|
|
12
10
|
* Create a new api handler that can be used to create an authenticated session.
|
|
13
11
|
*
|
|
@@ -34,7 +32,8 @@ export function useCookie(name) {
|
|
|
34
32
|
return cookies[name];
|
|
35
33
|
}
|
|
36
34
|
export const useBody = /* @__PURE__ */ Context.memo(() => {
|
|
37
|
-
const
|
|
35
|
+
const type = useContextType();
|
|
36
|
+
const evt = useEvent(type);
|
|
38
37
|
if (!evt.body)
|
|
39
38
|
return;
|
|
40
39
|
const body = evt.isBase64Encoded
|
|
@@ -118,7 +117,8 @@ export const useResponse = /* @__PURE__ */ Context.memo(() => {
|
|
|
118
117
|
return result;
|
|
119
118
|
});
|
|
120
119
|
export function useDomainName() {
|
|
121
|
-
const
|
|
120
|
+
const type = useContextType();
|
|
121
|
+
const evt = useEvent(type);
|
|
122
122
|
return evt.requestContext.domainName;
|
|
123
123
|
}
|
|
124
124
|
export function useMethod() {
|
|
@@ -126,7 +126,8 @@ export function useMethod() {
|
|
|
126
126
|
return evt.requestContext.http.method;
|
|
127
127
|
}
|
|
128
128
|
export function useHeaders() {
|
|
129
|
-
const
|
|
129
|
+
const type = useContextType();
|
|
130
|
+
const evt = useEvent(type);
|
|
130
131
|
return evt.headers || {};
|
|
131
132
|
}
|
|
132
133
|
export function useHeader(key) {
|
|
@@ -138,7 +139,8 @@ export function useFormValue(name) {
|
|
|
138
139
|
return params?.get(name);
|
|
139
140
|
}
|
|
140
141
|
export function useQueryParams() {
|
|
141
|
-
const
|
|
142
|
+
const type = useContextType();
|
|
143
|
+
const evt = useEvent(type);
|
|
142
144
|
const query = evt.queryStringParameters || {};
|
|
143
145
|
return query;
|
|
144
146
|
}
|
package/node/auth/session.js
CHANGED
|
@@ -2,14 +2,26 @@ import { createSigner, createVerifier } from "fast-jwt";
|
|
|
2
2
|
import { Context } from "../../context/context.js";
|
|
3
3
|
import { useCookie, useHeader } from "../api/index.js";
|
|
4
4
|
import { getPrivateKey, getPublicKey } from "./auth.js";
|
|
5
|
+
import { useContextType } from "../../context/handler.js";
|
|
5
6
|
const SessionMemo = /* @__PURE__ */ Context.memo(() => {
|
|
7
|
+
// Get the context type and hooks that match that type
|
|
6
8
|
let token = "";
|
|
7
9
|
const header = useHeader("authorization");
|
|
8
10
|
if (header)
|
|
9
11
|
token = header.substring(7);
|
|
10
|
-
const
|
|
12
|
+
const ctxType = useContextType();
|
|
13
|
+
const cookie = ctxType === "api" ? useCookie("auth-token") : undefined;
|
|
11
14
|
if (cookie)
|
|
12
15
|
token = cookie;
|
|
16
|
+
// WebSocket may also set the token in the protocol header
|
|
17
|
+
// TODO: Once https://github.com/serverless-stack/sst/pull/2838 is merged,
|
|
18
|
+
// then we should no longer need to check both casing for the header.
|
|
19
|
+
const wsProtocol = ctxType === "ws"
|
|
20
|
+
? useHeader("sec-websocket-protocol") ||
|
|
21
|
+
useHeader("Sec-WebSocket-Protocol")
|
|
22
|
+
: undefined;
|
|
23
|
+
if (wsProtocol)
|
|
24
|
+
token = wsProtocol.split(",")[0].trim();
|
|
13
25
|
if (token) {
|
|
14
26
|
const jwt = createVerifier({
|
|
15
27
|
algorithms: ["RS512"],
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OidcBasicConfig } from "./oidc.js";
|
|
2
|
+
type MicrosoftConfig = OidcBasicConfig & {
|
|
3
|
+
mode: "oidc";
|
|
4
|
+
};
|
|
5
|
+
export declare function MicrosoftAdapter(config: MicrosoftConfig): () => Promise<{
|
|
6
|
+
type: "success";
|
|
7
|
+
properties: {
|
|
8
|
+
tokenset: import("openid-client").TokenSet;
|
|
9
|
+
client: import("openid-client").BaseClient;
|
|
10
|
+
};
|
|
11
|
+
} | {
|
|
12
|
+
type: "step";
|
|
13
|
+
properties: {
|
|
14
|
+
statusCode: number;
|
|
15
|
+
headers: {
|
|
16
|
+
location: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Issuer } from "openid-client";
|
|
2
|
+
import { OidcAdapter } from "./oidc.js";
|
|
3
|
+
// These are the different Microsoft auth urls for different types of accounts:
|
|
4
|
+
// Common: https://login.microsoftonline.com/common/v2.0 (both business and private)
|
|
5
|
+
// Business: https://login.microsoftonline.com/{tenant}/v2.0
|
|
6
|
+
// Private: https://login.microsoftonline.com/consumers/v2.0
|
|
7
|
+
const issuer = await Issuer.discover("https://login.microsoftonline.com/common/v2.0");
|
|
8
|
+
export function MicrosoftAdapter(config) {
|
|
9
|
+
return OidcAdapter({
|
|
10
|
+
issuer,
|
|
11
|
+
scope: "openid email profile",
|
|
12
|
+
...config,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -6,6 +6,7 @@ export * from "./adapter/google.js";
|
|
|
6
6
|
export * from "./adapter/link.js";
|
|
7
7
|
export * from "./adapter/github.js";
|
|
8
8
|
export * from "./adapter/facebook.js";
|
|
9
|
+
export * from "./adapter/microsoft.js";
|
|
9
10
|
export * from "./adapter/oauth.js";
|
|
10
11
|
export type { Adapter } from "./adapter/adapter.js";
|
|
11
12
|
export * from "./session.js";
|
|
@@ -5,6 +5,7 @@ export * from "./adapter/google.js";
|
|
|
5
5
|
export * from "./adapter/link.js";
|
|
6
6
|
export * from "./adapter/github.js";
|
|
7
7
|
export * from "./adapter/facebook.js";
|
|
8
|
+
export * from "./adapter/microsoft.js";
|
|
8
9
|
export * from "./adapter/oauth.js";
|
|
9
10
|
export * from "./session.js";
|
|
10
11
|
export * from "./handler.js";
|
|
@@ -3,14 +3,26 @@ import { Context } from "../../../context/context.js";
|
|
|
3
3
|
import { useCookie, useHeader } from "../../api/index.js";
|
|
4
4
|
import { Auth } from "../../auth/index.js";
|
|
5
5
|
import { Config } from "../../config/index.js";
|
|
6
|
+
import { useContextType } from "../../../context/handler.js";
|
|
6
7
|
const SessionMemo = /* @__PURE__ */ Context.memo(() => {
|
|
8
|
+
// Get the context type and hooks that match that type
|
|
7
9
|
let token = "";
|
|
8
10
|
const header = useHeader("authorization");
|
|
9
11
|
if (header)
|
|
10
12
|
token = header.substring(7);
|
|
11
|
-
const
|
|
13
|
+
const ctxType = useContextType();
|
|
14
|
+
const cookie = ctxType === "api" ? useCookie("sst_auth_token") : undefined;
|
|
12
15
|
if (cookie)
|
|
13
16
|
token = cookie;
|
|
17
|
+
// WebSocket may also set the token in the protocol header
|
|
18
|
+
// TODO: Once https://github.com/serverless-stack/sst/pull/2838 is merged,
|
|
19
|
+
// then we should no longer need to check both casing for the header.
|
|
20
|
+
const wsProtocol = ctxType === "ws"
|
|
21
|
+
? useHeader("sec-websocket-protocol") ||
|
|
22
|
+
useHeader("Sec-WebSocket-Protocol")
|
|
23
|
+
: undefined;
|
|
24
|
+
if (wsProtocol)
|
|
25
|
+
token = wsProtocol.split(",")[0].trim();
|
|
14
26
|
if (token) {
|
|
15
27
|
return Session.verify(token);
|
|
16
28
|
}
|
package/node/graphql/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { createYoga } from "graphql-yoga";
|
|
2
2
|
import { Handler, useEvent, useLambdaContext } from "../../context/handler.js";
|
|
3
3
|
export function GraphQLHandler(options) {
|
|
4
|
-
const yoga = createYoga(
|
|
4
|
+
const yoga = createYoga({
|
|
5
|
+
graphqlEndpoint: process.env.GRAPHQL_ENDPOINT,
|
|
6
|
+
...options,
|
|
7
|
+
});
|
|
5
8
|
return Handler("api", async () => {
|
|
6
9
|
const event = useEvent("api");
|
|
7
10
|
const parameters = new URLSearchParams(event.queryStringParameters || {}).toString();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Handler } from "../../context/handler.js";
|
|
2
|
+
export interface WebSocketApiResources {
|
|
3
|
+
}
|
|
4
|
+
export declare const WebSocketApi: WebSocketApiResources;
|
|
5
|
+
/**
|
|
6
|
+
* Create a new WebSocketApi handler that can be used to create an
|
|
7
|
+
* authenticated session.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* export const handler = WebSocketApiHandler({
|
|
12
|
+
* })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function WebSocketApiHandler(cb: Parameters<typeof Handler<"ws">>[1]): (event: import("aws-lambda").APIGatewayProxyWebsocketEventV2 & {
|
|
16
|
+
headers?: import("aws-lambda").APIGatewayProxyEventHeaders | undefined;
|
|
17
|
+
multiValueHeaders?: import("aws-lambda").APIGatewayProxyEventMultiValueHeaders | undefined;
|
|
18
|
+
queryStringParameters?: import("aws-lambda").APIGatewayProxyEventQueryStringParameters | null | undefined;
|
|
19
|
+
multiValueQueryStringParameters?: import("aws-lambda").APIGatewayProxyEventMultiValueQueryStringParameters | null | undefined;
|
|
20
|
+
}, context: import("aws-lambda").Context) => Promise<any>;
|
|
21
|
+
export declare function useRequestContext(): import("aws-lambda").APIGatewayEventWebsocketRequestContextV2;
|
|
22
|
+
export declare function useConnectionId(): string;
|
|
23
|
+
export declare function useEventType(): "CONNECT" | "MESSAGE" | "DISCONNECT";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Handler, useEvent } from "../../context/handler.js";
|
|
2
|
+
import { useHeader } from "../api/index.js";
|
|
3
|
+
import { createProxy } from "../util/index.js";
|
|
4
|
+
export const WebSocketApi =
|
|
5
|
+
/* @__PURE__ */ createProxy("WebSocketApi");
|
|
6
|
+
/**
|
|
7
|
+
* Create a new WebSocketApi handler that can be used to create an
|
|
8
|
+
* authenticated session.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* export const handler = WebSocketApiHandler({
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function WebSocketApiHandler(cb) {
|
|
17
|
+
return Handler("ws", async (evt, ctx) => {
|
|
18
|
+
const result = await cb(evt, ctx);
|
|
19
|
+
// TODO: Once https://github.com/serverless-stack/sst/pull/2838 is merged,
|
|
20
|
+
// then we should no longer need to check both casing for the header.
|
|
21
|
+
const token = useHeader("Sec-WebSocket-Protocol") ||
|
|
22
|
+
useHeader("sec-websocket-protocol");
|
|
23
|
+
// If a token was set as part of the sec-websocket-protocol, we need to
|
|
24
|
+
// return it as a header in the response.
|
|
25
|
+
// https://docs.aws.amazon.com/apigateway/latest/developerguide/websocket-connect-route-subprotocol.html
|
|
26
|
+
if (token) {
|
|
27
|
+
return {
|
|
28
|
+
...(result || {}),
|
|
29
|
+
headers: {
|
|
30
|
+
"Sec-WebSocket-Protocol": token,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function useRequestContext() {
|
|
38
|
+
const evt = useEvent("ws");
|
|
39
|
+
return evt.requestContext;
|
|
40
|
+
}
|
|
41
|
+
export function useConnectionId() {
|
|
42
|
+
const requestContext = useRequestContext();
|
|
43
|
+
return requestContext.connectionId;
|
|
44
|
+
}
|
|
45
|
+
export function useEventType() {
|
|
46
|
+
const requestContext = useRequestContext();
|
|
47
|
+
return requestContext.eventType;
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sideEffects": false,
|
|
3
3
|
"name": "sst",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.25",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sst": "cli/sst.js"
|
|
7
7
|
},
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@babel/core": "^7.0.0-0",
|
|
49
49
|
"@babel/generator": "^7.20.5",
|
|
50
50
|
"@trpc/server": "9.16.0",
|
|
51
|
+
"adm-zip": "^0.5.10",
|
|
51
52
|
"aws-cdk-lib": "2.72.1",
|
|
52
53
|
"aws-iot-device-sdk": "^2.2.12",
|
|
53
54
|
"aws-sdk": "^2.1326.0",
|
|
@@ -85,8 +86,7 @@
|
|
|
85
86
|
"undici": "^5.12.0",
|
|
86
87
|
"uuid": "^9.0.0",
|
|
87
88
|
"ws": "^8.11.0",
|
|
88
|
-
"yargs": "^17.6.2"
|
|
89
|
-
"zip-local": "^0.3.5"
|
|
89
|
+
"yargs": "^17.6.2"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"@aws-sdk/client-api-gateway": "^3.208.0",
|
|
@@ -110,7 +110,6 @@
|
|
|
110
110
|
"@types/uuid": "^8.3.4",
|
|
111
111
|
"@types/ws": "^8.5.3",
|
|
112
112
|
"@types/yargs": "^17.0.13",
|
|
113
|
-
"adm-zip": "^0.5.10",
|
|
114
113
|
"archiver": "^5.3.1",
|
|
115
114
|
"tsx": "^3.12.1",
|
|
116
115
|
"typescript": "^4.9.5",
|
package/runtime/handlers/java.js
CHANGED
|
@@ -4,13 +4,13 @@ import os from "os";
|
|
|
4
4
|
import { useRuntimeHandlers } from "../handlers.js";
|
|
5
5
|
import { useRuntimeWorkers } from "../workers.js";
|
|
6
6
|
import { Context } from "../../context/context.js";
|
|
7
|
-
import zipLocal from "zip-local";
|
|
8
7
|
import { spawn } from "child_process";
|
|
9
8
|
import { useRuntimeServerConfig } from "../server.js";
|
|
10
9
|
import { existsAsync, findBelow, isChild } from "../../util/fs.js";
|
|
11
10
|
import { useProject } from "../../project.js";
|
|
12
11
|
import { execAsync } from "../../util/process.js";
|
|
13
12
|
import url from "url";
|
|
13
|
+
import AdmZip from "adm-zip";
|
|
14
14
|
export const useJavaHandler = Context.memo(async () => {
|
|
15
15
|
const workers = await useRuntimeWorkers();
|
|
16
16
|
const server = await useRuntimeServerConfig();
|
|
@@ -74,7 +74,7 @@ export const useJavaHandler = Context.memo(async () => {
|
|
|
74
74
|
});
|
|
75
75
|
const buildOutput = path.join(srcPath, "build", outputDir);
|
|
76
76
|
const zip = (await fs.readdir(buildOutput)).find((f) => f.endsWith(".zip"));
|
|
77
|
-
|
|
77
|
+
new AdmZip(path.join(buildOutput, zip)).extractAllTo(input.out);
|
|
78
78
|
return {
|
|
79
79
|
type: "success",
|
|
80
80
|
handler: input.props.handler,
|
package/sst.mjs
CHANGED
|
@@ -4848,9 +4848,9 @@ __export(java_exports, {
|
|
|
4848
4848
|
import path13 from "path";
|
|
4849
4849
|
import fs12 from "fs/promises";
|
|
4850
4850
|
import os5 from "os";
|
|
4851
|
-
import zipLocal from "zip-local";
|
|
4852
4851
|
import { spawn as spawn5 } from "child_process";
|
|
4853
4852
|
import url7 from "url";
|
|
4853
|
+
import AdmZip from "adm-zip";
|
|
4854
4854
|
async function getGradleBinary(srcPath) {
|
|
4855
4855
|
const gradleWrapperPath = path13.resolve(path13.join(srcPath, "gradlew"));
|
|
4856
4856
|
return await existsAsync(gradleWrapperPath) ? gradleWrapperPath : "gradle";
|
|
@@ -4940,7 +4940,7 @@ var init_java = __esm({
|
|
|
4940
4940
|
const zip = (await fs12.readdir(buildOutput)).find(
|
|
4941
4941
|
(f) => f.endsWith(".zip")
|
|
4942
4942
|
);
|
|
4943
|
-
|
|
4943
|
+
new AdmZip(path13.join(buildOutput, zip)).extractAllTo(input.out);
|
|
4944
4944
|
return {
|
|
4945
4945
|
type: "success",
|
|
4946
4946
|
handler: input.props.handler
|