@queue-it/fastly 3.6.0 → 4.4.3
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 +156 -58
- package/package.json +23 -16
- package/src/contextProvider.ts +175 -0
- package/src/fastlyCryptoProvider.ts +8 -0
- package/src/helper.ts +11 -0
- package/{assembly/sdk → src}/helpers/crypto.ts +338 -340
- package/src/index.ts +3 -0
- package/src/integrationConfigProvider.ts +199 -0
- package/src/requestResponseHandler.ts +200 -0
- package/README-INTERNAL.md +0 -21
- package/asconfig.json +0 -17
- package/assembly/__tests__/CustomerIntegrationDecodingHandler.spec.ts +0 -1086
- package/assembly/__tests__/IntegrationConfigHelpersTest.spec.ts +0 -574
- package/assembly/__tests__/KnownUserTest.spec.ts +0 -1894
- package/assembly/__tests__/Mocks.ts +0 -321
- package/assembly/__tests__/QueueParameterHelper.spec.ts +0 -59
- package/assembly/__tests__/UserInQueueService.spec.ts +0 -418
- package/assembly/__tests__/UserInQueueStateCookieRepository.spec.ts +0 -337
- package/assembly/__tests__/as-pect.config.js +0 -57
- package/assembly/__tests__/as-pect.d.ts +0 -1
- package/assembly/contextProvider.ts +0 -123
- package/assembly/helper.ts +0 -23
- package/assembly/index.ts +0 -10
- package/assembly/integrationConfigProvider.ts +0 -32
- package/assembly/requestResponseHandler.ts +0 -92
- package/assembly/sdk/HttpContextProvider.ts +0 -24
- package/assembly/sdk/IntegrationConfig/CustomerIntegrationDecodingHandler.ts +0 -198
- package/assembly/sdk/IntegrationConfig/IntegrationConfigHelpers.ts +0 -232
- package/assembly/sdk/IntegrationConfig/IntegrationConfigModel.ts +0 -93
- package/assembly/sdk/KnownUser.ts +0 -396
- package/assembly/sdk/Models.ts +0 -105
- package/assembly/sdk/QueueITHelpers.ts +0 -263
- package/assembly/sdk/UserInQueueService.ts +0 -245
- package/assembly/sdk/UserInQueueStateCookieRepository.ts +0 -189
- package/assembly/sdk/helpers/Date.ts +0 -194
- package/assembly/sdk/helpers/Uri.ts +0 -308
- package/assembly/tsconfig.json +0 -6
- package/index.js +0 -5
- package/pipelines/ci.yaml +0 -28
package/src/index.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export {IntegrationDetails, EnqueueTokenProviderFactory, IntegrationEndpointProvider, IntegrationEndpointCacheConfig, resolveIntegrationDetails} from "./integrationConfigProvider"
|
|
2
|
+
export {onQueueITRequest, onQueueITResponse} from "./requestResponseHandler";
|
|
3
|
+
export {RequestLogger} from "./helper";
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { ConfigStore } from "fastly:config-store";
|
|
2
|
+
import { IEnqueueTokenProvider } from "@queue-it/connector-javascript";
|
|
3
|
+
import { RequestLogger } from "./helper";
|
|
4
|
+
|
|
5
|
+
export type EnqueueTokenProviderFactory = (
|
|
6
|
+
customerId: string,
|
|
7
|
+
secretKey: string,
|
|
8
|
+
validityTime: number,
|
|
9
|
+
clientIp: string,
|
|
10
|
+
withKey: boolean
|
|
11
|
+
) => IEnqueueTokenProvider;
|
|
12
|
+
|
|
13
|
+
export async function getIntegrationConfig(
|
|
14
|
+
details: IntegrationDetails,
|
|
15
|
+
endpointProvider: IntegrationEndpointProvider
|
|
16
|
+
): Promise<string> {
|
|
17
|
+
const headers = new Headers();
|
|
18
|
+
headers.set("api-key", details.apiKey);
|
|
19
|
+
headers.set("host", endpointProvider.getHostname(details.customerId));
|
|
20
|
+
const request = new Request(
|
|
21
|
+
endpointProvider.getEndpoint(details.customerId),
|
|
22
|
+
{
|
|
23
|
+
method: "GET",
|
|
24
|
+
body: null,
|
|
25
|
+
headers: headers,
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
const cacheConf = endpointProvider.getCacheConfig();
|
|
29
|
+
const cacheInit: { ttl?: number; swr?: number } = {};
|
|
30
|
+
if (cacheConf.maxAge !== -1) cacheInit.ttl = cacheConf.maxAge;
|
|
31
|
+
if (cacheConf.staleWhileRevalidate !== -1) cacheInit.swr = cacheConf.staleWhileRevalidate;
|
|
32
|
+
const cacheOverride = new CacheOverride("override", cacheInit);
|
|
33
|
+
|
|
34
|
+
const beresp = await fetch(request, {
|
|
35
|
+
backend: details.queueItOrigin,
|
|
36
|
+
cacheOverride: cacheOverride,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!(details.logger instanceof MockLogger)) {
|
|
40
|
+
let cacheState = beresp.headers.get("x-cache");
|
|
41
|
+
let hits = beresp.headers.get("x-cache-hits");
|
|
42
|
+
if (hits == null) hits = "-1";
|
|
43
|
+
if (cacheState == null) cacheState = "n";
|
|
44
|
+
details.logger.log("IgnFetch:" + cacheState! + ":" + hits!);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (beresp.status != 200) {
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
50
|
+
return await beresp.text();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const integrationCustomerId = "customerId",
|
|
54
|
+
integrationApiKey = "apiKey",
|
|
55
|
+
integrationSecret = "secret",
|
|
56
|
+
integrationQueueItOrigin = "queueItOrigin",
|
|
57
|
+
integrationDictionary = "IntegrationConfiguration",
|
|
58
|
+
workerHost = "workerHost",
|
|
59
|
+
enqueueTokenEnabledKey = "enqueueTokenEnabled",
|
|
60
|
+
enqueueTokenValidityTimeKey = "enqueueTokenValidityTime",
|
|
61
|
+
enqueueTokenKeyEnabledKey = "enqueueTokenKeyEnabled",
|
|
62
|
+
requestBodyEnabledKey = "requestBodyEnabled";
|
|
63
|
+
|
|
64
|
+
export function resolveIntegrationDetails(): IntegrationDetails | null {
|
|
65
|
+
const dict = new ConfigStore(integrationDictionary);
|
|
66
|
+
if (
|
|
67
|
+
dict.get(integrationCustomerId) === null ||
|
|
68
|
+
dict.get(integrationApiKey) === null ||
|
|
69
|
+
dict.get(integrationSecret) === null ||
|
|
70
|
+
dict.get(integrationQueueItOrigin) === null
|
|
71
|
+
) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let workerHostValue = "";
|
|
76
|
+
const workerHostVal = dict.get(workerHost);
|
|
77
|
+
if (workerHostVal !== null) {
|
|
78
|
+
workerHostValue = workerHostVal;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let enqueueTokenEnabled = true;
|
|
82
|
+
const enqueueTokenEnabledVal = dict.get(enqueueTokenEnabledKey);
|
|
83
|
+
if (enqueueTokenEnabledVal !== null) {
|
|
84
|
+
enqueueTokenEnabled = enqueueTokenEnabledVal.toLowerCase() === "true";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let enqueueTokenValidityTime = 240000;
|
|
88
|
+
const enqueueTokenValidityTimeVal = dict.get(enqueueTokenValidityTimeKey);
|
|
89
|
+
if (enqueueTokenValidityTimeVal !== null) {
|
|
90
|
+
enqueueTokenValidityTime = parseInt(enqueueTokenValidityTimeVal, 10);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let enqueueTokenKeyEnabled = false;
|
|
94
|
+
const enqueueTokenKeyEnabledVal = dict.get(enqueueTokenKeyEnabledKey);
|
|
95
|
+
if (enqueueTokenKeyEnabledVal !== null) {
|
|
96
|
+
enqueueTokenKeyEnabled = enqueueTokenKeyEnabledVal.toLowerCase() === "true";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let requestBodyEnabled = false;
|
|
100
|
+
const requestBodyEnabledVal = dict.get(requestBodyEnabledKey);
|
|
101
|
+
if (requestBodyEnabledVal !== null) {
|
|
102
|
+
requestBodyEnabled = requestBodyEnabledVal.toLowerCase() === "true";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return new IntegrationDetails(
|
|
106
|
+
dict.get(integrationQueueItOrigin)!,
|
|
107
|
+
dict.get(integrationCustomerId)!,
|
|
108
|
+
dict.get(integrationSecret)!,
|
|
109
|
+
dict.get(integrationApiKey)!,
|
|
110
|
+
workerHostValue,
|
|
111
|
+
enqueueTokenEnabled,
|
|
112
|
+
enqueueTokenValidityTime,
|
|
113
|
+
enqueueTokenKeyEnabled,
|
|
114
|
+
requestBodyEnabled
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export class IntegrationEndpointCacheConfig {
|
|
119
|
+
maxAge: number = -1;
|
|
120
|
+
staleWhileRevalidate: number = -1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface IntegrationEndpointProvider {
|
|
124
|
+
getHostname(customerId: string): string;
|
|
125
|
+
|
|
126
|
+
getEndpoint(customerId: string): string;
|
|
127
|
+
|
|
128
|
+
getCacheConfig(): IntegrationEndpointCacheConfig;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export class QueueItIntegrationEndpointProvider
|
|
132
|
+
implements IntegrationEndpointProvider
|
|
133
|
+
{
|
|
134
|
+
private readonly cacheConfig: IntegrationEndpointCacheConfig;
|
|
135
|
+
|
|
136
|
+
constructor() {
|
|
137
|
+
this.cacheConfig = new IntegrationEndpointCacheConfig();
|
|
138
|
+
this.cacheConfig.maxAge = 60 * 5;
|
|
139
|
+
this.cacheConfig.staleWhileRevalidate = 60 * 5;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getCacheConfig(): IntegrationEndpointCacheConfig {
|
|
143
|
+
return this.cacheConfig;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getHostname(customerId: string): string {
|
|
147
|
+
return customerId + ".queue-it.net";
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
getEndpoint(customerId: string): string {
|
|
151
|
+
const host = this.getHostname(customerId);
|
|
152
|
+
return "https://" + host + "/status/integrationconfig/secure/" + customerId;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
class MockLogger implements RequestLogger {
|
|
157
|
+
log(message: string): void {}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class IntegrationDetails {
|
|
161
|
+
public enqueueTokenProviderFactory: EnqueueTokenProviderFactory | null = null;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The client IP address of the end user. In Fastly Compute, the client IP is not available
|
|
165
|
+
* via request headers (unlike Cloudflare's cf-connecting-ip or Akamai's True-Client-IP).
|
|
166
|
+
* Instead, it must be obtained from event.client.address in the fetch event handler and
|
|
167
|
+
* passed here. Used by the SDK for IP-based trigger matching and enqueue token generation.
|
|
168
|
+
*/
|
|
169
|
+
public clientIp: string = '';
|
|
170
|
+
|
|
171
|
+
constructor(
|
|
172
|
+
public queueItOrigin: string,
|
|
173
|
+
public customerId: string,
|
|
174
|
+
public secretKey: string,
|
|
175
|
+
public apiKey: string,
|
|
176
|
+
public workerHost: string,
|
|
177
|
+
public enqueueTokenEnabled: boolean = true,
|
|
178
|
+
public enqueueTokenValidityTime: number = 240000,
|
|
179
|
+
public enqueueTokenKeyEnabled: boolean = false,
|
|
180
|
+
public requestBodyEnabled: boolean = false,
|
|
181
|
+
public provider: IntegrationEndpointProvider = new QueueItIntegrationEndpointProvider(),
|
|
182
|
+
public logger: RequestLogger = new MockLogger()
|
|
183
|
+
) {}
|
|
184
|
+
|
|
185
|
+
resolveWorkerRequestUrl(pureUrl: string): string {
|
|
186
|
+
if (this.workerHost == "") {
|
|
187
|
+
return pureUrl;
|
|
188
|
+
}
|
|
189
|
+
const protoEnding = pureUrl.indexOf("://") + 3;
|
|
190
|
+
const protocol = pureUrl.substr(0, protoEnding);
|
|
191
|
+
const urlWithoutProto = pureUrl.substr(protoEnding);
|
|
192
|
+
const pathAndQuery =
|
|
193
|
+
urlWithoutProto.indexOf("/") != -1
|
|
194
|
+
? urlWithoutProto.substr(urlWithoutProto.indexOf("/"))
|
|
195
|
+
: "";
|
|
196
|
+
const rewrittenUrl = protocol + this.workerHost + pathAndQuery;
|
|
197
|
+
return rewrittenUrl;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { KnownUser } from "@queue-it/connector-javascript";
|
|
2
|
+
import { QueueITHelper } from "./helper";
|
|
3
|
+
import { FastlyHttpContextProvider, getHttpHandler } from "./contextProvider";
|
|
4
|
+
import {
|
|
5
|
+
getIntegrationConfig,
|
|
6
|
+
resolveIntegrationDetails,
|
|
7
|
+
IntegrationDetails,
|
|
8
|
+
QueueItIntegrationEndpointProvider,
|
|
9
|
+
} from "./integrationConfigProvider";
|
|
10
|
+
|
|
11
|
+
const QUEUEIT_FAILED_HEADERNAME = "x-queueit-failed";
|
|
12
|
+
const QUEUEIT_CONNECTOR_EXECUTED_HEADER_NAME = "x-queueit-connector";
|
|
13
|
+
|
|
14
|
+
let httpProvider: FastlyHttpContextProvider | null = null;
|
|
15
|
+
let sendNoCacheHeaders: boolean = false;
|
|
16
|
+
|
|
17
|
+
export async function onQueueITRequest(
|
|
18
|
+
req: Request,
|
|
19
|
+
conf: IntegrationDetails | null = null
|
|
20
|
+
): Promise<Response | null> {
|
|
21
|
+
if (conf == null) {
|
|
22
|
+
conf = resolveIntegrationDetails();
|
|
23
|
+
}
|
|
24
|
+
if (conf == null) {
|
|
25
|
+
return new Response("No integration details found.", {
|
|
26
|
+
headers: new Headers(),
|
|
27
|
+
status: 404,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const integrationProvider =
|
|
32
|
+
conf.provider == null
|
|
33
|
+
? new QueueItIntegrationEndpointProvider()
|
|
34
|
+
: conf.provider;
|
|
35
|
+
|
|
36
|
+
let bodyString = '';
|
|
37
|
+
if (conf.requestBodyEnabled) {
|
|
38
|
+
bodyString = ((await req.clone().text()) || '').substring(0, 2048);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
httpProvider = getHttpHandler(req, conf.clientIp, bodyString);
|
|
42
|
+
sendNoCacheHeaders = false;
|
|
43
|
+
|
|
44
|
+
if (conf.enqueueTokenEnabled) {
|
|
45
|
+
const clientIp = httpProvider.getHttpRequest().getUserHostAddress();
|
|
46
|
+
if (conf.enqueueTokenProviderFactory) {
|
|
47
|
+
httpProvider.setCustomEnqueueTokenProvider(
|
|
48
|
+
conf.enqueueTokenProviderFactory(
|
|
49
|
+
conf.customerId,
|
|
50
|
+
conf.secretKey,
|
|
51
|
+
conf.enqueueTokenValidityTime,
|
|
52
|
+
clientIp,
|
|
53
|
+
conf.enqueueTokenKeyEnabled
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
} else {
|
|
57
|
+
httpProvider.setEnqueueTokenProvider(
|
|
58
|
+
conf.customerId,
|
|
59
|
+
conf.secretKey,
|
|
60
|
+
conf.enqueueTokenValidityTime,
|
|
61
|
+
clientIp,
|
|
62
|
+
conf.enqueueTokenKeyEnabled
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const integrationConfigJson = await getIntegrationConfig(conf, integrationProvider);
|
|
69
|
+
const requestUrl: string = conf.resolveWorkerRequestUrl(req.url);
|
|
70
|
+
|
|
71
|
+
const queueItToken = getQueueItToken(requestUrl, httpProvider);
|
|
72
|
+
const requestUrlWithoutToken = requestUrl.replace(
|
|
73
|
+
new RegExp("([?&])(" + KnownUser.QueueITTokenKey + "=[^&]*)", "i"),
|
|
74
|
+
""
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// The requestUrlWithoutToken is used to match Triggers and as the Target url (where to return the users to).
|
|
78
|
+
// It is therefor important that this is exactly the url of the users browsers. So, if your webserver is
|
|
79
|
+
// behind e.g. a load balancer that modifies the host name or port, reformat requestUrlWithoutToken before proceeding.
|
|
80
|
+
|
|
81
|
+
const validationResult = await KnownUser.validateRequestByIntegrationConfig(
|
|
82
|
+
requestUrlWithoutToken,
|
|
83
|
+
queueItToken,
|
|
84
|
+
integrationConfigJson,
|
|
85
|
+
conf.customerId,
|
|
86
|
+
conf.secretKey,
|
|
87
|
+
httpProvider!
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (validationResult.doRedirect()) {
|
|
91
|
+
if (validationResult.isAjaxResult) {
|
|
92
|
+
const response = new Response(null, {
|
|
93
|
+
status: 200,
|
|
94
|
+
headers: httpProvider!.getResponseHeaders(),
|
|
95
|
+
});
|
|
96
|
+
const headerKey = validationResult.getAjaxQueueRedirectHeaderKey();
|
|
97
|
+
const queueRedirectUrl = validationResult.getAjaxRedirectUrl();
|
|
98
|
+
|
|
99
|
+
// In case of ajax call send the user to the queue by sending a custom queue-it header and redirecting user to queue from javascript
|
|
100
|
+
response.headers.set(
|
|
101
|
+
headerKey,
|
|
102
|
+
QueueITHelper.addKUPlatformVersion(queueRedirectUrl)
|
|
103
|
+
);
|
|
104
|
+
response.headers.set("Access-Control-Expose-Headers", headerKey);
|
|
105
|
+
sendNoCacheHeaders = true;
|
|
106
|
+
return response;
|
|
107
|
+
} else {
|
|
108
|
+
const response = new Response(null, {
|
|
109
|
+
status: 302,
|
|
110
|
+
headers: httpProvider!.getResponseHeaders(),
|
|
111
|
+
});
|
|
112
|
+
// Send the user to the queue - either because hash was missing or because is was invalid
|
|
113
|
+
response.headers.set(
|
|
114
|
+
"Location",
|
|
115
|
+
QueueITHelper.addKUPlatformVersion(validationResult.redirectUrl)
|
|
116
|
+
);
|
|
117
|
+
sendNoCacheHeaders = true;
|
|
118
|
+
return response;
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
// Request can continue - we remove queueittoken from querystring parameter to avoid sharing of user specific token
|
|
122
|
+
if (
|
|
123
|
+
requestUrl !== requestUrlWithoutToken &&
|
|
124
|
+
validationResult.actionType === "Queue"
|
|
125
|
+
) {
|
|
126
|
+
const response = new Response(null, {
|
|
127
|
+
status: 302,
|
|
128
|
+
headers: httpProvider!.getResponseHeaders(),
|
|
129
|
+
});
|
|
130
|
+
response.headers.set("Location", requestUrlWithoutToken);
|
|
131
|
+
sendNoCacheHeaders = true;
|
|
132
|
+
return response;
|
|
133
|
+
} else {
|
|
134
|
+
// lets caller decide the next step, or just serve the request normally
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (e) {
|
|
139
|
+
if (console && console.log) {
|
|
140
|
+
console.log("ERROR:" + e);
|
|
141
|
+
}
|
|
142
|
+
httpProvider!.isError = true;
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Fill in the Queue-it headers
|
|
148
|
+
export function onQueueITResponse(res: Response): void {
|
|
149
|
+
res.headers.set(QUEUEIT_CONNECTOR_EXECUTED_HEADER_NAME, "fastly");
|
|
150
|
+
|
|
151
|
+
if (httpProvider) {
|
|
152
|
+
const contextHeaders = httpProvider.getResponseHeaders();
|
|
153
|
+
for (const key of contextHeaders.keys()) {
|
|
154
|
+
if (key.length == 0) continue;
|
|
155
|
+
const value = contextHeaders.get(key);
|
|
156
|
+
if (value != null && value.length > 0)
|
|
157
|
+
res.headers.append(key, value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (httpProvider.isError) {
|
|
161
|
+
res.headers.append(QUEUEIT_FAILED_HEADERNAME, "true");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (sendNoCacheHeaders) {
|
|
166
|
+
addNoCacheHeaders(res);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function addNoCacheHeaders(res: Response): void {
|
|
171
|
+
res.headers.set('Cache-Control', 'no-cache, no-store, must-revalidate, max-age=0');
|
|
172
|
+
res.headers.set('Pragma', 'no-cache');
|
|
173
|
+
res.headers.set('Expires', 'Fri, 01 Jan 1990 00:00:00 GMT');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getQueueItToken(
|
|
177
|
+
requestUrl: string,
|
|
178
|
+
httpContext: FastlyHttpContextProvider
|
|
179
|
+
): string {
|
|
180
|
+
const queueItToken = getParameterByName(requestUrl, KnownUser.QueueITTokenKey);
|
|
181
|
+
if (queueItToken) {
|
|
182
|
+
return queueItToken;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const tokenHeaderName = `x-${KnownUser.QueueITTokenKey}`;
|
|
186
|
+
return httpContext.getHttpRequest().getHeader(tokenHeaderName);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getParameterByName(url: string, name: string): string {
|
|
190
|
+
name = name.replace(/[\[\]]/g, '\\$&');
|
|
191
|
+
const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
|
|
192
|
+
const results = regex.exec(url);
|
|
193
|
+
if (!results) return '';
|
|
194
|
+
if (!results[2]) return '';
|
|
195
|
+
try {
|
|
196
|
+
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
|
197
|
+
} catch {
|
|
198
|
+
return results[2];
|
|
199
|
+
}
|
|
200
|
+
}
|
package/README-INTERNAL.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
## Getting started
|
|
2
|
-
- Install the [Fastly CLI](https://developer.fastly.com/reference/cli/)
|
|
3
|
-
- Configure the CLI with the Fastly token.
|
|
4
|
-
You can get a token in the Fastly platform.
|
|
5
|
-
To configure the CLI run `fastly configure` and fill in the details.
|
|
6
|
-
- You can list the Fastly services with `fastly service list`
|
|
7
|
-
|
|
8
|
-
## Development workflow
|
|
9
|
-
- Build and test locally
|
|
10
|
-
- Align version in package.json and UserInQueueService.ts
|
|
11
|
-
- Commit changes
|
|
12
|
-
- Run the CI pipeline
|
|
13
|
-
- Update Sample site with new changes.
|
|
14
|
-
This can be done by running `fastly compute build && fastly compute deploy`.
|
|
15
|
-
- Sync with github
|
|
16
|
-
|
|
17
|
-
## Deploying to the sample site
|
|
18
|
-
- Make sure you have the right configuration in `fastly.toml`
|
|
19
|
-
|
|
20
|
-
## Limitations
|
|
21
|
-
- Since dictionary item values have a limit of 8k chars we poll the integration config with a 5 min TTL.
|
package/asconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"targets": {
|
|
3
|
-
"debug": {
|
|
4
|
-
"binaryFile": "bin/untouched.wasm",
|
|
5
|
-
"textFile": "bin/untouched.wat",
|
|
6
|
-
"sourceMap": true,
|
|
7
|
-
"debug": true
|
|
8
|
-
},
|
|
9
|
-
"release": {
|
|
10
|
-
"binaryFile": "bin/main.wasm",
|
|
11
|
-
"textFile": "bin/main.wat",
|
|
12
|
-
"sourceMap": true,
|
|
13
|
-
"optimize": true
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"options": {}
|
|
17
|
-
}
|