@queue-it/fastly 4.4.3 → 5.0.0-beta.1
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/README.md +2 -154
- package/package.json +4 -3
- package/src/contextProvider.ts +27 -5
- package/src/fastlyDirectActionProvider.ts +137 -0
- package/src/helper.ts +4 -2
- package/src/index.ts +2 -0
- package/src/integrationConfigProvider.ts +61 -5
- package/src/requestResponseHandler.ts +1 -1
package/README.md
CHANGED
|
@@ -1,156 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Queue-it Connector for Fastly
|
|
2
2
|
|
|
3
|
-
The Queue-it
|
|
4
|
-
going through the queue for any and all `protected` areas and paths on your sites. The queue system is implemented by
|
|
5
|
-
adding a server-side (request-level) integration that protects your online application by redirecting users to a waiting
|
|
6
|
-
room according to web traffic settings in the Queue-it GO Platform. After the integration is complete, queue system
|
|
7
|
-
behavior and operations are managed in Queue-it's Go Platform and/or via the Queue-it Admin API.
|
|
3
|
+
The package enables you to add traffic management support to your website. The Connector Implementation Guide can be found via the Queue-it GO Platform | Help | Connector Integration Documentation. In order to get access please reach out to your Queue-it representative.
|
|
8
4
|
|
|
9
|
-
This Fastly Queue-it Connector SDK (aka, Queue-it's server-side KnownUser connector) uses a Compute@Edge service to
|
|
10
|
-
integrate Queue-it's functionality into Fastly's network.
|
|
11
|
-
|
|
12
|
-
A Wasm service is required to utilize this connector.
|
|
13
|
-
|
|
14
|
-
> You can find the latest released version [here](https://github.com/queueit/KnownUser.V3.Fastly/releases/latest).
|
|
15
|
-
|
|
16
|
-
## Introduction
|
|
17
|
-
|
|
18
|
-
When a user makes a request to your Fastly service our connector validates the request and if it is needed, it will
|
|
19
|
-
redirect the user to the waiting room. After waiting in the waiting room, the queue engine will redirect the user back
|
|
20
|
-
to your end attaching a query string parameter ( `queueittoken` ) containing some information about the user to the URL.
|
|
21
|
-
The most important fields of the `queueittoken` are:
|
|
22
|
-
|
|
23
|
-
- q - The user's unique queue identifier
|
|
24
|
-
- ts - A timestamp of how long this redirect is valid
|
|
25
|
-
- h - A hash of the token
|
|
26
|
-
|
|
27
|
-
After the user returns from the queue, the connector will let the user continue his request to your backend ( without
|
|
28
|
-
redirecting to the queue since the request has a valid queueittoken as query string) .
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
There are two methods of installation:
|
|
33
|
-
|
|
34
|
-
### As a standalone service
|
|
35
|
-
|
|
36
|
-
- Go to the Fastly services page and create a new **Wasm** service.
|
|
37
|
-
- Go to Domains and fill in the domain that you want your service to be reachable at. You may need to register a CNAME
|
|
38
|
-
record if you have your own domain.
|
|
39
|
-
- Then click on *Origins* and add a new host that has the hostname of your origin server.
|
|
40
|
-
You need to edit the Host and name it **origin**.
|
|
41
|
-
- Create a second host that has the hostname of `{yourCustomerId}.queue-it.net` and name it **queue-it**.
|
|
42
|
-
Edit the host, go to advanced options and fill in the same hostname in **Override host**
|
|
43
|
-
- Go to **Resources -> Config stores** and create a new config store named `IntegrationConfiguration`.
|
|
44
|
-
- Add the following items in the config store (you can find these values in the Go Queue-It self-service platform):
|
|
45
|
-
- customerId: Your customer ID
|
|
46
|
-
- apiKey: The API key for your account
|
|
47
|
-
- secret: Your KnownUserV3 secret
|
|
48
|
-
- queueItOrigin: The name of the queue-it host, in this case it's `queue-it`
|
|
49
|
-
- Go to **Linked Services** and click on `Link Service`
|
|
50
|
-
- Select your service and click `Next`
|
|
51
|
-
- Click `Link and activate` to link the `Config store` to your service. It should generate a new version
|
|
52
|
-
- You can verify that the `Config store` has been linked by going to your service and see it in the section `Config stores`
|
|
53
|
-
- Download the latest package from the releases page and unarchive it.
|
|
54
|
-
- Edit the `fastly.toml` file and copy the ID of your service (you can see this by opening up the service in Fastly) and
|
|
55
|
-
replace **{YourServiceId}** with it.
|
|
56
|
-
- Archive the directory in the same format (tar.gz).
|
|
57
|
-
- Go to `Package` in the Fastly service page and upload the package.
|
|
58
|
-
- To finish up and deploy your service click on the **Activate** button.
|
|
59
|
-
|
|
60
|
-
### Customizable service with the connector
|
|
61
|
-
|
|
62
|
-
- Go to the Fastly services page and create a new **Wasm** service and copy it's ID.
|
|
63
|
-
- Clone this repository and edit the fastly.toml file, make sure to set the `service_id` field to the ID you copied.
|
|
64
|
-
- Then click on *Origins* and add a new host that has the hostname of your origin server.
|
|
65
|
-
You can name the host **origin** or whatever you choose.
|
|
66
|
-
- Create a host that has the hostname of `{yourCustomerId}.queue-it.net` and name it **queue-it**.
|
|
67
|
-
Edit the host, go to advanced options and fill in the same hostname in **Override host**
|
|
68
|
-
- Go to **Resources -> Config stores** and create a new config store named `IntegrationConfiguration`.
|
|
69
|
-
- Add the following items in the config store (you can find these values in the Go Queue-It self-service platform):
|
|
70
|
-
- customerId: Your customer ID
|
|
71
|
-
- apiKey: The API key for your account
|
|
72
|
-
- secret: Your KnownUserV3 secret
|
|
73
|
-
- queueItOrigin: The name of the queue-it host, in this case it's `queue-it`
|
|
74
|
-
- Go to **Linked Services** and click on `Link Service`
|
|
75
|
-
- Select your service and click `Next`
|
|
76
|
-
- Click `Link and activate` to link the `Config store` to your service. It should generate a new version
|
|
77
|
-
- You can verify that the `Config store` has been linked by going to your service and see it in the section `Config stores`
|
|
78
|
-
- You need to add some code that uses this connector. Here is an example:
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
import {Fastly} from "@fastly/as-compute";
|
|
82
|
-
import {onQueueITRequest, IntegrationDetails, onQueueITResponse} from "@queue-it/fastly";
|
|
83
|
-
|
|
84
|
-
const req = Fastly.getClientRequest();
|
|
85
|
-
|
|
86
|
-
// This is optional and can be null if it's specified in your Config Store
|
|
87
|
-
const integrationDetails = new IntegrationDetails(
|
|
88
|
-
"QueueItOriginName",
|
|
89
|
-
"CustomerId",
|
|
90
|
-
"SecretKey",
|
|
91
|
-
"ApiKey");
|
|
92
|
-
let res = onQueueITRequest(req, integrationDetails);
|
|
93
|
-
|
|
94
|
-
if (res != null) {
|
|
95
|
-
Fastly.respondWith(res!);
|
|
96
|
-
} else {
|
|
97
|
-
const myOrigin = 'Ticketania';
|
|
98
|
-
const cacheOverride = new Fastly.CacheOverride();
|
|
99
|
-
const res = Fastly.fetch(req, {
|
|
100
|
-
backend: myOrigin,
|
|
101
|
-
cacheOverride,
|
|
102
|
-
}).wait();
|
|
103
|
-
onQueueITResponse(res);
|
|
104
|
-
Fastly.respondWith(res);
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
- Build and deploy the package running `fastly compute build` and `fastly compute deploy` in the same directory.
|
|
109
|
-
- Create desired waiting room(s), triggers, and actions in the Go Queue-It self-service platform.
|
|
110
|
-
Then, save/publish the configuration.
|
|
111
|
-
|
|
112
|
-
## Enqueue Token Settings
|
|
113
|
-
|
|
114
|
-
The connector supports enqueue tokens, which are used to secure the queue redirect flow. These settings are read at runtime from the Fastly `IntegrationConfiguration` Config Store. They are optional — if not set, the defaults below apply.
|
|
115
|
-
|
|
116
|
-
| Key | Default | Description |
|
|
117
|
-
|-----|---------|-------------|
|
|
118
|
-
| `enqueueTokenEnabled` | `"true"` | Enables enqueue token generation. Set to `"false"` to disable. |
|
|
119
|
-
| `enqueueTokenValidityTime` | `"240000"` | Token validity time in milliseconds. |
|
|
120
|
-
| `enqueueTokenKeyEnabled` | `"false"` | Enables key-based enqueue tokens. Set to `"true"` to enable. |
|
|
121
|
-
|
|
122
|
-
To configure these, add them as items in the `IntegrationConfiguration` Config Store alongside the other settings (`customerId`, `apiKey`, `secret`, etc.) — either via the Fastly UI or the Fastly API.
|
|
123
|
-
|
|
124
|
-
## Request Body Trigger Matching
|
|
125
|
-
|
|
126
|
-
The connector supports matching triggers based on the request body content. This is disabled by default. When enabled, up to 2048 characters of the request body are read and passed to the SDK for trigger evaluation.
|
|
127
|
-
|
|
128
|
-
To enable it, add the following key to the `IntegrationConfiguration` Config Store:
|
|
129
|
-
|
|
130
|
-
| Key | Default | Description |
|
|
131
|
-
|-----|---------|-------------|
|
|
132
|
-
| `requestBodyEnabled` | `"false"` | Set to `"true"` to enable request body trigger matching. |
|
|
133
|
-
|
|
134
|
-
## Providing the queue configuration
|
|
135
|
-
|
|
136
|
-
The recommended way is to use the Go Queue-it self-service portal to setup the configuration. The configuration
|
|
137
|
-
specifies a set of Triggers and Actions. A Trigger is an expression matching one, more or all URLs on your website. When
|
|
138
|
-
a user enter your website and the URL matches a Trigger-expression the corresponding Action will be triggered. The
|
|
139
|
-
Action specifies which waiting room the users should be send to. In this way you can specify which waiting room(s)
|
|
140
|
-
should protect which page(s) on the fly without changing the server-side integration.
|
|
141
|
-
|
|
142
|
-
## Protecting AJAX calls
|
|
143
|
-
|
|
144
|
-
If you need to protect AJAX calls beside page loads you need to add the below JavaScript tags to your pages:
|
|
145
|
-
|
|
146
|
-
```html
|
|
147
|
-
|
|
148
|
-
<script type="text/javascript" src="//static.queue-it.net/script/queueclient.min.js"></script>
|
|
149
|
-
<script
|
|
150
|
-
data-queueit-intercept-domain="{YOUR_CURRENT_DOMAIN}"
|
|
151
|
-
data-queueit-intercept="true"
|
|
152
|
-
data-queueit-c="{YOUR_CUSTOMER_ID}"
|
|
153
|
-
type="text/javascript"
|
|
154
|
-
src="//static.queue-it.net/script/queueconfigloader.min.js">
|
|
155
|
-
</script>
|
|
156
|
-
```
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@queue-it/fastly",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-beta.1",
|
|
4
4
|
"description": "Queue-it connector for Fastly",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"author": "devs@queue-it.com",
|
|
7
|
-
"repository": "https://github.com/queueit/
|
|
7
|
+
"repository": "https://github.com/queueit/connector-fastly",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"files": [
|
|
10
10
|
"package.json",
|
|
11
11
|
"README.md",
|
|
12
12
|
"src/helpers",
|
|
13
13
|
"src/fastlyCryptoProvider.ts",
|
|
14
|
+
"src/fastlyDirectActionProvider.ts",
|
|
14
15
|
"src/contextProvider.ts",
|
|
15
16
|
"src/helper.ts",
|
|
16
17
|
"src/integrationConfigProvider.ts",
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@fastly/js-compute": "^3.0.0",
|
|
28
|
-
"@queue-it/connector-javascript": "
|
|
29
|
+
"@queue-it/connector-javascript": "~5.0.1",
|
|
29
30
|
"@queue-it/queue-token": "~1.0.4"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
package/src/contextProvider.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
DefaultEnqueueTokenProvider,
|
|
3
3
|
IConnectorContextProvider,
|
|
4
4
|
ICryptoProvider,
|
|
5
|
+
IDirectActionProvider,
|
|
5
6
|
IEnqueueTokenProvider,
|
|
6
7
|
INormalizationProvider,
|
|
7
8
|
DefaultNormalizationProvider,
|
|
@@ -10,9 +11,15 @@ import {
|
|
|
10
11
|
} from '@queue-it/connector-javascript';
|
|
11
12
|
import { Token, Payload } from '@queue-it/queue-token';
|
|
12
13
|
import { FastlyCryptoProvider } from './fastlyCryptoProvider';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
import { FastlyDirectActionProvider, FastlyDirectActionsSettings } from './fastlyDirectActionProvider';
|
|
15
|
+
|
|
16
|
+
export function getHttpHandler(
|
|
17
|
+
req: Request,
|
|
18
|
+
clientIp: string = '',
|
|
19
|
+
bodyString: string = '',
|
|
20
|
+
directActionsSettings?: FastlyDirectActionsSettings
|
|
21
|
+
): FastlyHttpContextProvider {
|
|
22
|
+
return new FastlyHttpContextProvider(req, clientIp, bodyString, directActionsSettings);
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export class FastlyHttpContextProvider implements IConnectorContextProvider {
|
|
@@ -22,12 +29,23 @@ export class FastlyHttpContextProvider implements IConnectorContextProvider {
|
|
|
22
29
|
private _enqueueTokenProvider: IEnqueueTokenProvider | null = null;
|
|
23
30
|
private readonly _normalizationProvider: INormalizationProvider;
|
|
24
31
|
private readonly _cryptoProvider: ICryptoProvider;
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
private readonly _directActionProvider: IDirectActionProvider;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
fReq: Request,
|
|
36
|
+
clientIp: string = '',
|
|
37
|
+
bodyString: string = '',
|
|
38
|
+
directActionsSettings?: FastlyDirectActionsSettings
|
|
39
|
+
) {
|
|
27
40
|
this._httpRequest = new FastlyHttpRequest(fReq, clientIp, bodyString);
|
|
28
41
|
this._httpResponse = new FastlyHttpResponse();
|
|
29
42
|
this._normalizationProvider = new DefaultNormalizationProvider();
|
|
30
43
|
this._cryptoProvider = new FastlyCryptoProvider();
|
|
44
|
+
this._directActionProvider = new FastlyDirectActionProvider(
|
|
45
|
+
this._httpRequest,
|
|
46
|
+
this._httpResponse,
|
|
47
|
+
directActionsSettings
|
|
48
|
+
);
|
|
31
49
|
}
|
|
32
50
|
|
|
33
51
|
getHttpRequest(): IHttpRequest {
|
|
@@ -72,6 +90,10 @@ export class FastlyHttpContextProvider implements IConnectorContextProvider {
|
|
|
72
90
|
return this._normalizationProvider;
|
|
73
91
|
}
|
|
74
92
|
|
|
93
|
+
getDirectActionProvider(): IDirectActionProvider {
|
|
94
|
+
return this._directActionProvider;
|
|
95
|
+
}
|
|
96
|
+
|
|
75
97
|
getResponseHeaders(): Headers {
|
|
76
98
|
return this._httpResponse.getHeaders();
|
|
77
99
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IDebugService,
|
|
3
|
+
IDirectActionProvider,
|
|
4
|
+
IDirectActionSettings,
|
|
5
|
+
IDirectPassRequestDTO,
|
|
6
|
+
IDirectPassResponseDTO,
|
|
7
|
+
IDirectPassResult,
|
|
8
|
+
IHttpRequest,
|
|
9
|
+
IHttpResponse,
|
|
10
|
+
} from "@queue-it/connector-javascript";
|
|
11
|
+
import { PLATFORM_VERSION } from "./helper";
|
|
12
|
+
|
|
13
|
+
export interface FastlyDirectActionsSettings {
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
proxyKey: string | null;
|
|
16
|
+
directPassTimeoutMillis?: number;
|
|
17
|
+
isTestEnvironment?: boolean;
|
|
18
|
+
// Fastly backend name used to reach `*.queue-it.net`. Reuses the same backend
|
|
19
|
+
// as the integration config fetch so no extra backend setup is required.
|
|
20
|
+
queueItOrigin?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class FastlyDirectActionProvider implements IDirectActionProvider {
|
|
24
|
+
private _settings: IDirectActionSettings;
|
|
25
|
+
private _isTestEnvironment: boolean;
|
|
26
|
+
private _backend?: string;
|
|
27
|
+
|
|
28
|
+
constructor(
|
|
29
|
+
protected httpRequest: IHttpRequest,
|
|
30
|
+
protected httpResponse: IHttpResponse,
|
|
31
|
+
protected settings?: FastlyDirectActionsSettings
|
|
32
|
+
) {
|
|
33
|
+
this._settings = {
|
|
34
|
+
disabled: settings?.disabled === true,
|
|
35
|
+
proxyKey: settings?.proxyKey ?? "",
|
|
36
|
+
directPass: {
|
|
37
|
+
timeoutMillis: settings?.directPassTimeoutMillis,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
this._isTestEnvironment = settings?.isTestEnvironment === true;
|
|
41
|
+
this._backend = settings?.queueItOrigin;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getSettings(): IDirectActionSettings {
|
|
45
|
+
return this._settings;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async tryDirectPass(
|
|
49
|
+
customerId: string,
|
|
50
|
+
waitingRoomId: string,
|
|
51
|
+
actionName: string,
|
|
52
|
+
protectedUrl: string,
|
|
53
|
+
proxyKey: string,
|
|
54
|
+
clientIp: string,
|
|
55
|
+
userAgent: string,
|
|
56
|
+
referer: string,
|
|
57
|
+
timeout: number,
|
|
58
|
+
sdkVersion: string,
|
|
59
|
+
debugService: IDebugService
|
|
60
|
+
): Promise<IDirectPassResult> {
|
|
61
|
+
const requestDto: IDirectPassRequestDTO = {
|
|
62
|
+
protectedUrl,
|
|
63
|
+
connectorPlatformVersion: PLATFORM_VERSION,
|
|
64
|
+
sdkVersion,
|
|
65
|
+
actionName,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const requestBody = JSON.stringify(requestDto);
|
|
69
|
+
const envSuffix = this._isTestEnvironment ? ".test" : "";
|
|
70
|
+
const url = `https://${customerId}${envSuffix}.queue-it.net/front-door/api/${customerId}/waiting-rooms/${waitingRoomId}/try-pass`;
|
|
71
|
+
|
|
72
|
+
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const fetchInit: RequestInit & { backend?: string; cacheOverride?: CacheOverride } = {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: requestBody,
|
|
78
|
+
headers: {
|
|
79
|
+
"Accept": "application/json",
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
"User-Agent": userAgent,
|
|
82
|
+
"Referer": referer,
|
|
83
|
+
"x-queueit-proxykey": proxyKey,
|
|
84
|
+
"x-queueit-clientip-yb85x": clientIp,
|
|
85
|
+
},
|
|
86
|
+
cacheOverride: new CacheOverride("pass"),
|
|
87
|
+
};
|
|
88
|
+
if (this._backend) {
|
|
89
|
+
fetchInit.backend = this._backend;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Fastly Compute does not expose AbortController; per Fastly's "set a timeout
|
|
93
|
+
// on a request" example we race the fetch against a setTimeout. The in-flight
|
|
94
|
+
// request keeps running in the background until the backend's first_byte_timeout
|
|
95
|
+
// kills it.
|
|
96
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
97
|
+
timeoutId = setTimeout(
|
|
98
|
+
() => reject(new Error(`Direct pass timeout after ${timeout}ms`)),
|
|
99
|
+
timeout
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
const response = await Promise.race([fetch(url, fetchInit), timeoutPromise]);
|
|
103
|
+
|
|
104
|
+
if (debugService.isConnectorDiagnosticEnabled()) {
|
|
105
|
+
debugService.addDebugEntry("DirectActionHttpReponseCode", response.status.toString());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
if (response.status >= 500) {
|
|
110
|
+
throw new Error(`Try pass did not receive proper response. Status: ${response.status}`);
|
|
111
|
+
}
|
|
112
|
+
return { hasPassed: false };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const responseBody: IDirectPassResponseDTO = await response.json();
|
|
116
|
+
|
|
117
|
+
if (debugService.isConnectorDiagnosticEnabled()) {
|
|
118
|
+
debugService.addDebugEntry(
|
|
119
|
+
"DirectActionHttpResponseBody",
|
|
120
|
+
`HasPassed:${responseBody.HasPassed}&QueueItToken:${responseBody.QueueItToken}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!responseBody || !Object.prototype.hasOwnProperty.call(responseBody, "HasPassed")) {
|
|
125
|
+
return { hasPassed: false };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { hasPassed: responseBody.HasPassed, queueitToken: responseBody.QueueItToken };
|
|
129
|
+
} catch (err) {
|
|
130
|
+
const message = err instanceof Error ? err.message : JSON.stringify(err);
|
|
131
|
+
console.error(`Direct pass error: ${message}`);
|
|
132
|
+
throw err;
|
|
133
|
+
} finally {
|
|
134
|
+
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/helper.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export class QueueITHelper {
|
|
2
|
-
static readonly KUP_VERSION: string = "fastly-
|
|
2
|
+
static readonly KUP_VERSION: string = "fastly-5.0.0";
|
|
3
3
|
|
|
4
4
|
static addKUPlatformVersion(redirectQueueUrl: string): string {
|
|
5
|
-
return redirectQueueUrl
|
|
5
|
+
return `${redirectQueueUrl}&kupver=${QueueITHelper.KUP_VERSION}`;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export const PLATFORM_VERSION = QueueITHelper.KUP_VERSION;
|
|
10
|
+
|
|
9
11
|
export interface RequestLogger {
|
|
10
12
|
log(message: string): void;
|
|
11
13
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export {IntegrationDetails, EnqueueTokenProviderFactory, IntegrationEndpointProvider, IntegrationEndpointCacheConfig, resolveIntegrationDetails} from "./integrationConfigProvider"
|
|
2
2
|
export {onQueueITRequest, onQueueITResponse} from "./requestResponseHandler";
|
|
3
3
|
export {RequestLogger} from "./helper";
|
|
4
|
+
export {FastlyDirectActionProvider} from "./fastlyDirectActionProvider";
|
|
5
|
+
export type {FastlyDirectActionsSettings} from "./fastlyDirectActionProvider";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConfigStore } from "fastly:config-store";
|
|
2
2
|
import { IEnqueueTokenProvider } from "@queue-it/connector-javascript";
|
|
3
3
|
import { RequestLogger } from "./helper";
|
|
4
|
+
import { FastlyDirectActionsSettings } from "./fastlyDirectActionProvider";
|
|
4
5
|
|
|
5
6
|
export type EnqueueTokenProviderFactory = (
|
|
6
7
|
customerId: string,
|
|
@@ -59,7 +60,11 @@ const integrationCustomerId = "customerId",
|
|
|
59
60
|
enqueueTokenEnabledKey = "enqueueTokenEnabled",
|
|
60
61
|
enqueueTokenValidityTimeKey = "enqueueTokenValidityTime",
|
|
61
62
|
enqueueTokenKeyEnabledKey = "enqueueTokenKeyEnabled",
|
|
62
|
-
requestBodyEnabledKey = "requestBodyEnabled"
|
|
63
|
+
requestBodyEnabledKey = "requestBodyEnabled",
|
|
64
|
+
directActionsDisabledKey = "directActionsDisabled",
|
|
65
|
+
directActionsProxyKeyKey = "directActionsProxyKey",
|
|
66
|
+
directPassTimeoutKey = "directPassTimeout",
|
|
67
|
+
isTestEnvironmentKey = "isTestEnvironment";
|
|
63
68
|
|
|
64
69
|
export function resolveIntegrationDetails(): IntegrationDetails | null {
|
|
65
70
|
const dict = new ConfigStore(integrationDictionary);
|
|
@@ -102,8 +107,41 @@ export function resolveIntegrationDetails(): IntegrationDetails | null {
|
|
|
102
107
|
requestBodyEnabled = requestBodyEnabledVal.toLowerCase() === "true";
|
|
103
108
|
}
|
|
104
109
|
|
|
110
|
+
let directActionsDisabled = false;
|
|
111
|
+
const directActionsDisabledVal = dict.get(directActionsDisabledKey);
|
|
112
|
+
if (directActionsDisabledVal !== null) {
|
|
113
|
+
directActionsDisabled = directActionsDisabledVal.toLowerCase() === "true";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const directActionsProxyKeyVal = dict.get(directActionsProxyKeyKey);
|
|
117
|
+
const directActionsProxyKey: string | null =
|
|
118
|
+
directActionsProxyKeyVal && directActionsProxyKeyVal.length > 0
|
|
119
|
+
? directActionsProxyKeyVal
|
|
120
|
+
: null;
|
|
121
|
+
|
|
122
|
+
let directPassTimeoutMillis: number | undefined;
|
|
123
|
+
const directPassTimeoutVal = dict.get(directPassTimeoutKey);
|
|
124
|
+
if (directPassTimeoutVal !== null) {
|
|
125
|
+
const parsed = parseInt(directPassTimeoutVal, 10);
|
|
126
|
+
if (!Number.isNaN(parsed)) directPassTimeoutMillis = parsed;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let isTestEnvironment = false;
|
|
130
|
+
const isTestEnvironmentVal = dict.get(isTestEnvironmentKey);
|
|
131
|
+
if (isTestEnvironmentVal !== null) {
|
|
132
|
+
isTestEnvironment = isTestEnvironmentVal.toLowerCase() === "true";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!directActionsDisabled && !directActionsProxyKey) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
"Direct Actions are enabled but no proxy key is provided. Set directActionsDisabled to true to disable, or provide directActionsProxyKey."
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const queueItOrigin = dict.get(integrationQueueItOrigin)!;
|
|
142
|
+
|
|
105
143
|
return new IntegrationDetails(
|
|
106
|
-
|
|
144
|
+
queueItOrigin,
|
|
107
145
|
dict.get(integrationCustomerId)!,
|
|
108
146
|
dict.get(integrationSecret)!,
|
|
109
147
|
dict.get(integrationApiKey)!,
|
|
@@ -111,7 +149,16 @@ export function resolveIntegrationDetails(): IntegrationDetails | null {
|
|
|
111
149
|
enqueueTokenEnabled,
|
|
112
150
|
enqueueTokenValidityTime,
|
|
113
151
|
enqueueTokenKeyEnabled,
|
|
114
|
-
requestBodyEnabled
|
|
152
|
+
requestBodyEnabled,
|
|
153
|
+
new QueueItIntegrationEndpointProvider(),
|
|
154
|
+
new MockLogger(),
|
|
155
|
+
{
|
|
156
|
+
disabled: directActionsDisabled,
|
|
157
|
+
proxyKey: directActionsProxyKey,
|
|
158
|
+
directPassTimeoutMillis,
|
|
159
|
+
isTestEnvironment,
|
|
160
|
+
queueItOrigin,
|
|
161
|
+
}
|
|
115
162
|
);
|
|
116
163
|
}
|
|
117
164
|
|
|
@@ -168,6 +215,8 @@ export class IntegrationDetails {
|
|
|
168
215
|
*/
|
|
169
216
|
public clientIp: string = '';
|
|
170
217
|
|
|
218
|
+
public directActionsSettings: FastlyDirectActionsSettings;
|
|
219
|
+
|
|
171
220
|
constructor(
|
|
172
221
|
public queueItOrigin: string,
|
|
173
222
|
public customerId: string,
|
|
@@ -179,8 +228,15 @@ export class IntegrationDetails {
|
|
|
179
228
|
public enqueueTokenKeyEnabled: boolean = false,
|
|
180
229
|
public requestBodyEnabled: boolean = false,
|
|
181
230
|
public provider: IntegrationEndpointProvider = new QueueItIntegrationEndpointProvider(),
|
|
182
|
-
public logger: RequestLogger = new MockLogger()
|
|
183
|
-
|
|
231
|
+
public logger: RequestLogger = new MockLogger(),
|
|
232
|
+
directActionsSettings?: FastlyDirectActionsSettings
|
|
233
|
+
) {
|
|
234
|
+
this.directActionsSettings = directActionsSettings ?? {
|
|
235
|
+
disabled: false,
|
|
236
|
+
proxyKey: null,
|
|
237
|
+
queueItOrigin,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
184
240
|
|
|
185
241
|
resolveWorkerRequestUrl(pureUrl: string): string {
|
|
186
242
|
if (this.workerHost == "") {
|
|
@@ -38,7 +38,7 @@ export async function onQueueITRequest(
|
|
|
38
38
|
bodyString = ((await req.clone().text()) || '').substring(0, 2048);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
httpProvider = getHttpHandler(req, conf.clientIp, bodyString);
|
|
41
|
+
httpProvider = getHttpHandler(req, conf.clientIp, bodyString, conf.directActionsSettings);
|
|
42
42
|
sendNoCacheHeaders = false;
|
|
43
43
|
|
|
44
44
|
if (conf.enqueueTokenEnabled) {
|