@rocicorp/zero 0.25.10-canary.20 → 0.25.10-canary.22
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/out/zero/package.json.js +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +3 -3
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +116 -76
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +0 -1
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +2 -2
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +1 -3
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +8 -5
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +21 -17
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/error-with-level.d.ts +1 -1
- package/out/zero-cache/src/types/error-with-level.d.ts.map +1 -1
- package/out/zero-cache/src/types/error-with-level.js +1 -1
- package/out/zero-cache/src/types/error-with-level.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +3 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +10 -3
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +5 -1
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js +3 -3
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/package.json +1 -1
package/out/zero/package.json.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LogContext
|
|
1
|
+
import type { LogContext } from '@rocicorp/logger';
|
|
2
2
|
import 'urlpattern-polyfill';
|
|
3
3
|
import type { ReadonlyJSONValue } from '../../../shared/src/json.ts';
|
|
4
4
|
import { type Type } from '../../../shared/src/valita.ts';
|
|
@@ -19,8 +19,8 @@ export type HeaderOptions = {
|
|
|
19
19
|
token?: string | undefined;
|
|
20
20
|
cookie?: string | undefined;
|
|
21
21
|
};
|
|
22
|
-
export declare const getBodyPreview: (res: Response, lc: LogContext
|
|
23
|
-
export declare function fetchFromAPIServer<TValidator extends Type>(validator: TValidator, source: 'push' | 'transform', lc: LogContext, url: string,
|
|
22
|
+
export declare const getBodyPreview: (res: Response, lc: LogContext) => Promise<string | undefined>;
|
|
23
|
+
export declare function fetchFromAPIServer<TValidator extends Type>(validator: TValidator, source: 'push' | 'transform', lc: LogContext, url: string, allowedUrlPatterns: URLPattern[], shard: ShardID, headerOptions: HeaderOptions, body: ReadonlyJSONValue): Promise<import("../../../shared/src/valita.ts").Infer<TValidator>>;
|
|
24
24
|
/**
|
|
25
25
|
* Returns true if the url matches one of the allowedUrlPatterns.
|
|
26
26
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/custom/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/custom/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAW,MAAM,kBAAkB,CAAC;AAC3D,OAAO,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAC,KAAK,IAAI,EAAC,MAAM,+BAA+B,CAAC;AAMxD,OAAO,EAAiB,KAAK,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAKhE;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAQ7D;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,KAAK,QAAQ,EACb,IAAI,UAAU,KACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAkB5B,CAAC;AAIF,wBAAsB,kBAAkB,CAAC,UAAU,SAAS,IAAI,EAC9D,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,MAAM,GAAG,WAAW,EAC5B,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,UAAU,EAAE,EAChC,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE,iBAAiB,sEAuMxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,kBAAkB,EAAE,UAAU,EAAE,GAC/B,OAAO,CAOT"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "urlpattern-polyfill";
|
|
2
|
-
import { assert } from "../../../shared/src/asserts.js";
|
|
2
|
+
import { assert, unreachable } from "../../../shared/src/asserts.js";
|
|
3
3
|
import { getErrorMessage } from "../../../shared/src/error.js";
|
|
4
|
+
import { sleep } from "../../../shared/src/sleep.js";
|
|
4
5
|
import "../../../shared/src/valita.js";
|
|
5
6
|
import { PushFailed, TransformFailed } from "../../../zero-protocol/src/error-kind-enum.js";
|
|
6
7
|
import { ZeroCache } from "../../../zero-protocol/src/error-origin-enum.js";
|
|
@@ -8,6 +9,7 @@ import { Internal, HTTP, Parse } from "../../../zero-protocol/src/error-reason-e
|
|
|
8
9
|
import { isProtocolError } from "../../../zero-protocol/src/error.js";
|
|
9
10
|
import { ProtocolErrorWithLevel } from "../types/error-with-level.js";
|
|
10
11
|
import { upstreamSchema } from "../types/shards.js";
|
|
12
|
+
import { randInt } from "../../../shared/src/rand.js";
|
|
11
13
|
const reservedParams = ["schema", "appID"];
|
|
12
14
|
function compileUrlPattern(pattern) {
|
|
13
15
|
try {
|
|
@@ -18,7 +20,7 @@ function compileUrlPattern(pattern) {
|
|
|
18
20
|
);
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
|
-
const getBodyPreview = async (res, lc
|
|
23
|
+
const getBodyPreview = async (res, lc) => {
|
|
22
24
|
try {
|
|
23
25
|
const body = await res.clone().text();
|
|
24
26
|
if (body.length > 512) {
|
|
@@ -26,14 +28,20 @@ const getBodyPreview = async (res, lc, level) => {
|
|
|
26
28
|
}
|
|
27
29
|
return body;
|
|
28
30
|
} catch (e) {
|
|
29
|
-
lc
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
lc.warn?.(
|
|
32
|
+
"failed to get body preview",
|
|
33
|
+
{
|
|
34
|
+
url: res.url
|
|
35
|
+
},
|
|
36
|
+
e
|
|
37
|
+
);
|
|
33
38
|
}
|
|
34
39
|
return void 0;
|
|
35
40
|
};
|
|
36
|
-
|
|
41
|
+
const MAX_ATTEMPTS = 4;
|
|
42
|
+
async function fetchFromAPIServer(validator, source, lc, url, allowedUrlPatterns, shard, headerOptions, body) {
|
|
43
|
+
const fetchFromAPIServerID = randInt(1, Number.MAX_SAFE_INTEGER).toString(36);
|
|
44
|
+
lc = lc.withContext("fetchFromAPIServerID", fetchFromAPIServerID);
|
|
37
45
|
lc.debug?.("fetchFromAPIServer called", {
|
|
38
46
|
url
|
|
39
47
|
});
|
|
@@ -51,7 +59,8 @@ async function fetchFromAPIServer(validator, source, lc, url, isUserUrl, allowed
|
|
|
51
59
|
reason: Internal,
|
|
52
60
|
message: `URL "${url}" is not allowed by the ZERO_QUERY_URL configuration`,
|
|
53
61
|
queryIDs: []
|
|
54
|
-
}
|
|
62
|
+
},
|
|
63
|
+
"warn"
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
66
|
const headers = {
|
|
@@ -81,93 +90,121 @@ async function fetchFromAPIServer(validator, source, lc, url, isUserUrl, allowed
|
|
|
81
90
|
params.append("appID", shard.appID);
|
|
82
91
|
urlObj.search = params.toString();
|
|
83
92
|
const finalUrl = urlObj.toString();
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
lc
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
94
|
+
lc = lc.withContext("fetchFromAPIServerAttempt", attempt);
|
|
95
|
+
lc.debug?.("fetch from API server attempt");
|
|
96
|
+
const shouldRetry = async () => {
|
|
97
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
98
|
+
const delayMs = getBackoffDelayMs(attempt);
|
|
99
|
+
lc.debug?.(`fetch from API server retrying in ${delayMs} ms`);
|
|
100
|
+
await sleep(delayMs);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
lc.debug?.("fetch from API server reached max attempts, not retrying");
|
|
104
|
+
return false;
|
|
105
|
+
};
|
|
106
|
+
try {
|
|
107
|
+
const response = await fetch(finalUrl, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers,
|
|
110
|
+
body: JSON.stringify(body)
|
|
98
111
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
reason: HTTP,
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
const bodyPreview = await getBodyPreview(response, lc);
|
|
114
|
+
lc.warn?.("fetch from API server returned non-OK status", {
|
|
115
|
+
url: finalUrl,
|
|
104
116
|
status: response.status,
|
|
105
|
-
bodyPreview
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
kind: TransformFailed,
|
|
110
|
-
origin: ZeroCache,
|
|
111
|
-
reason: HTTP,
|
|
112
|
-
status: response.status,
|
|
113
|
-
bodyPreview,
|
|
114
|
-
message: `Fetch from API server returned non-OK status ${response.status}`,
|
|
115
|
-
queryIDs: []
|
|
117
|
+
bodyPreview
|
|
118
|
+
});
|
|
119
|
+
if ((response.status === 502 || response.status === 504) && await shouldRetry()) {
|
|
120
|
+
continue;
|
|
116
121
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
throw new ProtocolErrorWithLevel(
|
|
123
|
+
source === "push" ? {
|
|
124
|
+
kind: PushFailed,
|
|
125
|
+
origin: ZeroCache,
|
|
126
|
+
reason: HTTP,
|
|
127
|
+
status: response.status,
|
|
128
|
+
bodyPreview,
|
|
129
|
+
message: `Fetch from API server returned non-OK status ${response.status}`,
|
|
130
|
+
mutationIDs: []
|
|
131
|
+
} : {
|
|
132
|
+
kind: TransformFailed,
|
|
133
|
+
origin: ZeroCache,
|
|
134
|
+
reason: HTTP,
|
|
135
|
+
status: response.status,
|
|
136
|
+
bodyPreview,
|
|
137
|
+
message: `Fetch from API server returned non-OK status ${response.status}`,
|
|
138
|
+
queryIDs: []
|
|
139
|
+
},
|
|
140
|
+
"warn"
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const json = await response.json();
|
|
145
|
+
const result = validator.parse(json);
|
|
146
|
+
lc.debug?.("fetch from API server succeeded");
|
|
147
|
+
return result;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
lc.warn?.(
|
|
150
|
+
"failed to parse response",
|
|
151
|
+
{
|
|
152
|
+
url: finalUrl
|
|
153
|
+
},
|
|
154
|
+
error
|
|
155
|
+
);
|
|
156
|
+
throw new ProtocolErrorWithLevel(
|
|
157
|
+
source === "push" ? {
|
|
158
|
+
kind: PushFailed,
|
|
159
|
+
origin: ZeroCache,
|
|
160
|
+
reason: Parse,
|
|
161
|
+
message: `Failed to parse response from API server: ${getErrorMessage(error)}`,
|
|
162
|
+
mutationIDs: []
|
|
163
|
+
} : {
|
|
164
|
+
kind: TransformFailed,
|
|
165
|
+
origin: ZeroCache,
|
|
166
|
+
reason: Parse,
|
|
167
|
+
message: `Failed to parse response from API server: ${getErrorMessage(error)}`,
|
|
168
|
+
queryIDs: []
|
|
169
|
+
},
|
|
170
|
+
"warn",
|
|
171
|
+
{ cause: error }
|
|
172
|
+
);
|
|
173
|
+
}
|
|
122
174
|
} catch (error) {
|
|
123
|
-
|
|
124
|
-
|
|
175
|
+
if (isProtocolError(error)) {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
const isFetchFailed = error instanceof TypeError && error.message === "fetch failed";
|
|
179
|
+
let logLevel = isFetchFailed ? "warn" : "error";
|
|
180
|
+
lc[logLevel]?.(
|
|
181
|
+
"fetch from API server threw error",
|
|
182
|
+
{ url: finalUrl },
|
|
125
183
|
error
|
|
126
|
-
|
|
184
|
+
);
|
|
185
|
+
if (isFetchFailed && await shouldRetry()) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
127
188
|
throw new ProtocolErrorWithLevel(
|
|
128
189
|
source === "push" ? {
|
|
129
190
|
kind: PushFailed,
|
|
130
191
|
origin: ZeroCache,
|
|
131
|
-
reason:
|
|
132
|
-
message: `
|
|
192
|
+
reason: Internal,
|
|
193
|
+
message: `Fetch from API server threw error: ${getErrorMessage(error)}`,
|
|
133
194
|
mutationIDs: []
|
|
134
195
|
} : {
|
|
135
196
|
kind: TransformFailed,
|
|
136
197
|
origin: ZeroCache,
|
|
137
|
-
reason:
|
|
138
|
-
message: `
|
|
198
|
+
reason: Internal,
|
|
199
|
+
message: `Fetch from API server threw error: ${getErrorMessage(error)}`,
|
|
139
200
|
queryIDs: []
|
|
140
201
|
},
|
|
141
|
-
|
|
202
|
+
logLevel,
|
|
142
203
|
{ cause: error }
|
|
143
204
|
);
|
|
144
205
|
}
|
|
145
|
-
} catch (error) {
|
|
146
|
-
if (isProtocolError(error)) {
|
|
147
|
-
throw error;
|
|
148
|
-
}
|
|
149
|
-
lc[errLevel]?.("failed to fetch from API server with unknown error", {
|
|
150
|
-
url: finalUrl,
|
|
151
|
-
error
|
|
152
|
-
});
|
|
153
|
-
throw new ProtocolErrorWithLevel(
|
|
154
|
-
source === "push" ? {
|
|
155
|
-
kind: PushFailed,
|
|
156
|
-
origin: ZeroCache,
|
|
157
|
-
reason: Internal,
|
|
158
|
-
message: `Fetch from API server failed with unknown error: ${getErrorMessage(error)}`,
|
|
159
|
-
mutationIDs: []
|
|
160
|
-
} : {
|
|
161
|
-
kind: TransformFailed,
|
|
162
|
-
origin: ZeroCache,
|
|
163
|
-
reason: Internal,
|
|
164
|
-
message: `Fetch from API server failed with unknown error: ${getErrorMessage(error)}`,
|
|
165
|
-
queryIDs: []
|
|
166
|
-
},
|
|
167
|
-
"error",
|
|
168
|
-
{ cause: error }
|
|
169
|
-
);
|
|
170
206
|
}
|
|
207
|
+
unreachable();
|
|
171
208
|
}
|
|
172
209
|
function urlMatch(url, allowedUrlPatterns) {
|
|
173
210
|
for (const pattern of allowedUrlPatterns) {
|
|
@@ -177,6 +214,9 @@ function urlMatch(url, allowedUrlPatterns) {
|
|
|
177
214
|
}
|
|
178
215
|
return false;
|
|
179
216
|
}
|
|
217
|
+
function getBackoffDelayMs(attempt) {
|
|
218
|
+
return Math.min(1e3, 100 * Math.pow(2, attempt - 1) + Math.random() * 100);
|
|
219
|
+
}
|
|
180
220
|
export {
|
|
181
221
|
compileUrlPattern,
|
|
182
222
|
fetchFromAPIServer,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sources":["../../../../../zero-cache/src/custom/fetch.ts"],"sourcesContent":["import type {LogContext, LogLevel} from '@rocicorp/logger';\nimport 'urlpattern-polyfill';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {getErrorMessage} from '../../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {type Type} from '../../../shared/src/valita.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../zero-protocol/src/error-reason.ts';\nimport {isProtocolError} from '../../../zero-protocol/src/error.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\nimport {upstreamSchema, type ShardID} from '../types/shards.ts';\n\nconst reservedParams = ['schema', 'appID'];\n\n/**\n * Compiles and validates a URLPattern from configuration.\n *\n * Patterns must be full URLs (e.g., \"https://api.example.com/endpoint\").\n * URLPattern automatically sets search and hash to wildcard ('*'),\n * which means query parameters and fragments are ignored during matching.\n *\n * @throws Error if the pattern is an invalid URLPattern\n */\nexport function compileUrlPattern(pattern: string): URLPattern {\n try {\n return new URLPattern(pattern);\n } catch (e) {\n throw new Error(\n `Invalid URLPattern in URL configuration: \"${pattern}\". Error: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n}\n\nexport type HeaderOptions = {\n apiKey?: string | undefined;\n customHeaders?: Record<string, string> | undefined;\n token?: string | undefined;\n cookie?: string | undefined;\n};\n\nexport const getBodyPreview = async (\n res: Response,\n lc: LogContext,\n level: LogLevel,\n): Promise<string | undefined> => {\n try {\n const body = await res.clone().text();\n if (body.length > 512) {\n return body.slice(0, 512) + '...';\n }\n return body;\n } catch (e) {\n lc[level]?.('failed to get body preview', {\n url: res.url,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n\n return undefined;\n};\n\nexport async function fetchFromAPIServer<TValidator extends Type>(\n validator: TValidator,\n source: 'push' | 'transform',\n lc: LogContext,\n url: string,\n isUserUrl: boolean,\n allowedUrlPatterns: URLPattern[],\n shard: ShardID,\n headerOptions: HeaderOptions,\n body: ReadonlyJSONValue,\n) {\n lc.debug?.('fetchFromAPIServer called', {\n url,\n });\n\n if (!urlMatch(url, allowedUrlPatterns)) {\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `URL \"${url}\" is not allowed by the ZERO_MUTATE_URL configuration`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `URL \"${url}\" is not allowed by the ZERO_QUERY_URL configuration`,\n queryIDs: [],\n },\n );\n }\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (headerOptions.apiKey) {\n headers['X-Api-Key'] = headerOptions.apiKey;\n }\n if (headerOptions.customHeaders) {\n Object.assign(headers, headerOptions.customHeaders);\n }\n if (headerOptions.token) {\n headers['Authorization'] = `Bearer ${headerOptions.token}`;\n }\n if (headerOptions.cookie) {\n headers['Cookie'] = headerOptions.cookie;\n }\n\n const urlObj = new URL(url);\n const params = new URLSearchParams(urlObj.search);\n\n for (const reserved of reservedParams) {\n assert(\n !params.has(reserved),\n `The push URL cannot contain the reserved query param \"${reserved}\"`,\n );\n }\n\n params.append('schema', upstreamSchema(shard));\n params.append('appID', shard.appID);\n\n urlObj.search = params.toString();\n\n const finalUrl = urlObj.toString();\n\n // Errors from a user-specified url are treated 4xx errors\n // (e.g. bad request) as they are developer driven and should not\n // trigger error-log based alerts.\n const errLevel: LogLevel = isUserUrl ? 'warn' : 'error';\n try {\n const response = await fetch(finalUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const bodyPreview = await getBodyPreview(response, lc, errLevel);\n\n // Bad Gateway or Gateway Timeout indicate the server was not reached\n const level =\n response.status === 502 || response.status === 504 ? errLevel : 'info';\n lc[level]?.('fetch from API server returned non-OK status', {\n url: finalUrl,\n status: response.status,\n bodyPreview,\n });\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n queryIDs: [],\n },\n );\n }\n\n try {\n const json = await response.json();\n\n return validator.parse(json);\n } catch (error) {\n lc[errLevel]?.('failed to parse response', {\n url: finalUrl,\n error,\n });\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Parse,\n message: `Failed to parse response from API server: ${getErrorMessage(error)}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Parse,\n message: `Failed to parse response from API server: ${getErrorMessage(error)}`,\n queryIDs: [],\n },\n 'error',\n {cause: error},\n );\n }\n } catch (error) {\n if (isProtocolError(error)) {\n throw error;\n }\n\n lc[errLevel]?.('failed to fetch from API server with unknown error', {\n url: finalUrl,\n error,\n });\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Fetch from API server failed with unknown error: ${getErrorMessage(error)}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Fetch from API server failed with unknown error: ${getErrorMessage(error)}`,\n queryIDs: [],\n },\n 'error',\n {cause: error},\n );\n }\n}\n\n/**\n * Returns true if the url matches one of the allowedUrlPatterns.\n *\n * URLPattern automatically ignores query parameters and hash fragments during matching\n * because it sets search and hash to wildcard ('*') by default.\n *\n * Example URLPattern patterns:\n * - \"https://api.example.com/endpoint\" - Exact match for a specific URL\n * - \"https://*.example.com/endpoint\" - Matches any single subdomain (e.g., \"https://api.example.com/endpoint\")\n * - \"https://*.*.example.com/endpoint\" - Matches two subdomains (e.g., \"https://api.v1.example.com/endpoint\")\n * - \"https://api.example.com/*\" - Matches any path under /\n * - \"https://api.example.com/:version/endpoint\" - Matches with named parameter (e.g., \"https://api.example.com/v1/endpoint\")\n */\nexport function urlMatch(\n url: string,\n allowedUrlPatterns: URLPattern[],\n): boolean {\n for (const pattern of allowedUrlPatterns) {\n if (pattern.test(url)) {\n return true;\n }\n }\n return false;\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.ZeroCache","ErrorReason.Internal","ErrorKind.TransformFailed","ErrorReason.HTTP","ErrorReason.Parse"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fetch.js","sources":["../../../../../zero-cache/src/custom/fetch.ts"],"sourcesContent":["import type {LogContext, LogLevel} from '@rocicorp/logger';\nimport 'urlpattern-polyfill';\nimport {assert, unreachable} from '../../../shared/src/asserts.ts';\nimport {getErrorMessage} from '../../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {sleep} from '../../../shared/src/sleep.ts';\nimport {type Type} from '../../../shared/src/valita.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../zero-protocol/src/error-reason.ts';\nimport {isProtocolError} from '../../../zero-protocol/src/error.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\nimport {upstreamSchema, type ShardID} from '../types/shards.ts';\nimport {randInt} from '../../../shared/src/rand.ts';\n\nconst reservedParams = ['schema', 'appID'];\n\n/**\n * Compiles and validates a URLPattern from configuration.\n *\n * Patterns must be full URLs (e.g., \"https://api.example.com/endpoint\").\n * URLPattern automatically sets search and hash to wildcard ('*'),\n * which means query parameters and fragments are ignored during matching.\n *\n * @throws Error if the pattern is an invalid URLPattern\n */\nexport function compileUrlPattern(pattern: string): URLPattern {\n try {\n return new URLPattern(pattern);\n } catch (e) {\n throw new Error(\n `Invalid URLPattern in URL configuration: \"${pattern}\". Error: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n}\n\nexport type HeaderOptions = {\n apiKey?: string | undefined;\n customHeaders?: Record<string, string> | undefined;\n token?: string | undefined;\n cookie?: string | undefined;\n};\n\nexport const getBodyPreview = async (\n res: Response,\n lc: LogContext,\n): Promise<string | undefined> => {\n try {\n const body = await res.clone().text();\n if (body.length > 512) {\n return body.slice(0, 512) + '...';\n }\n return body;\n } catch (e) {\n lc.warn?.(\n 'failed to get body preview',\n {\n url: res.url,\n },\n e,\n );\n }\n\n return undefined;\n};\n\nconst MAX_ATTEMPTS = 4;\n\nexport async function fetchFromAPIServer<TValidator extends Type>(\n validator: TValidator,\n source: 'push' | 'transform',\n lc: LogContext,\n url: string,\n allowedUrlPatterns: URLPattern[],\n shard: ShardID,\n headerOptions: HeaderOptions,\n body: ReadonlyJSONValue,\n) {\n const fetchFromAPIServerID = randInt(1, Number.MAX_SAFE_INTEGER).toString(36);\n lc = lc.withContext('fetchFromAPIServerID', fetchFromAPIServerID);\n\n lc.debug?.('fetchFromAPIServer called', {\n url,\n });\n\n if (!urlMatch(url, allowedUrlPatterns)) {\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `URL \"${url}\" is not allowed by the ZERO_MUTATE_URL configuration`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `URL \"${url}\" is not allowed by the ZERO_QUERY_URL configuration`,\n queryIDs: [],\n },\n 'warn',\n );\n }\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (headerOptions.apiKey) {\n headers['X-Api-Key'] = headerOptions.apiKey;\n }\n if (headerOptions.customHeaders) {\n Object.assign(headers, headerOptions.customHeaders);\n }\n if (headerOptions.token) {\n headers['Authorization'] = `Bearer ${headerOptions.token}`;\n }\n if (headerOptions.cookie) {\n headers['Cookie'] = headerOptions.cookie;\n }\n\n const urlObj = new URL(url);\n const params = new URLSearchParams(urlObj.search);\n\n for (const reserved of reservedParams) {\n assert(\n !params.has(reserved),\n `The push URL cannot contain the reserved query param \"${reserved}\"`,\n );\n }\n\n params.append('schema', upstreamSchema(shard));\n params.append('appID', shard.appID);\n\n urlObj.search = params.toString();\n\n const finalUrl = urlObj.toString();\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n lc = lc.withContext('fetchFromAPIServerAttempt', attempt);\n lc.debug?.('fetch from API server attempt');\n const shouldRetry = async () => {\n if (attempt < MAX_ATTEMPTS) {\n const delayMs = getBackoffDelayMs(attempt);\n lc.debug?.(`fetch from API server retrying in ${delayMs} ms`);\n await sleep(delayMs);\n return true;\n }\n lc.debug?.('fetch from API server reached max attempts, not retrying');\n return false;\n };\n try {\n const response = await fetch(finalUrl, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const bodyPreview = await getBodyPreview(response, lc);\n lc.warn?.('fetch from API server returned non-OK status', {\n url: finalUrl,\n status: response.status,\n bodyPreview,\n });\n // Bad Gateway or Gateway Timeout indicate the server was not reached\n // We retry these if we have retries remaining.\n if (\n (response.status === 502 || response.status === 504) &&\n (await shouldRetry())\n ) {\n continue;\n }\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n queryIDs: [],\n },\n 'warn',\n );\n }\n\n try {\n const json = await response.json();\n const result = validator.parse(json);\n lc.debug?.('fetch from API server succeeded');\n return result;\n } catch (error) {\n lc.warn?.(\n 'failed to parse response',\n {\n url: finalUrl,\n },\n error,\n );\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Parse,\n message: `Failed to parse response from API server: ${getErrorMessage(error)}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Parse,\n message: `Failed to parse response from API server: ${getErrorMessage(error)}`,\n queryIDs: [],\n },\n 'warn',\n {cause: error},\n );\n }\n } catch (error) {\n if (isProtocolError(error)) {\n throw error;\n }\n\n const isFetchFailed =\n error instanceof TypeError && error.message === 'fetch failed';\n // unexpected/unknown errors should be logged at 'error' level so they\n // are investigated\n let logLevel: LogLevel = isFetchFailed ? 'warn' : 'error';\n lc[logLevel]?.(\n 'fetch from API server threw error',\n {url: finalUrl},\n error,\n );\n\n if (isFetchFailed && (await shouldRetry())) {\n continue;\n }\n\n throw new ProtocolErrorWithLevel(\n source === 'push'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Fetch from API server threw error: ${getErrorMessage(error)}`,\n mutationIDs: [],\n }\n : {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Fetch from API server threw error: ${getErrorMessage(error)}`,\n queryIDs: [],\n },\n logLevel,\n {cause: error},\n );\n }\n }\n unreachable();\n}\n\n/**\n * Returns true if the url matches one of the allowedUrlPatterns.\n *\n * URLPattern automatically ignores query parameters and hash fragments during matching\n * because it sets search and hash to wildcard ('*') by default.\n *\n * Example URLPattern patterns:\n * - \"https://api.example.com/endpoint\" - Exact match for a specific URL\n * - \"https://*.example.com/endpoint\" - Matches any single subdomain (e.g., \"https://api.example.com/endpoint\")\n * - \"https://*.*.example.com/endpoint\" - Matches two subdomains (e.g., \"https://api.v1.example.com/endpoint\")\n * - \"https://api.example.com/*\" - Matches any path under /\n * - \"https://api.example.com/:version/endpoint\" - Matches with named parameter (e.g., \"https://api.example.com/v1/endpoint\")\n */\nexport function urlMatch(\n url: string,\n allowedUrlPatterns: URLPattern[],\n): boolean {\n for (const pattern of allowedUrlPatterns) {\n if (pattern.test(url)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Returns the delay in milliseconds for the next retry attempt using exponential backoff with jitter.\n *\n * The delay assumes the first retry is attempt 1.\n * The formula is: `min(1000, 100 * 2^(attempt - 1) + jitter)` where jitter is between 0 and 100ms.\n */\nfunction getBackoffDelayMs(attempt: number): number {\n return Math.min(1000, 100 * Math.pow(2, attempt - 1) + Math.random() * 100);\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.ZeroCache","ErrorReason.Internal","ErrorKind.TransformFailed","ErrorReason.HTTP","ErrorReason.Parse"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-query.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/custom-queries/transform-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,8CAA8C,CAAC;AAItD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,sBAAsB;;gBAW/B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,EAAE,CAAC;QACd,cAAc,EAAE,OAAO,CAAC;KACzB,EACD,KAAK,EAAE,OAAO;IASV,SAAS,CACb,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACpC,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,CAAC,oBAAoB,GAAG,YAAY,CAAC,EAAE,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"transform-query.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/custom-queries/transform-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,8CAA8C,CAAC;AAItD,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,sBAAsB;;gBAW/B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,EAAE,CAAC;QACd,cAAc,EAAE,OAAO,CAAC;KACzB,EACD,KAAK,EAAE,OAAO;IASV,SAAS,CACb,aAAa,EAAE,aAAa,EAC5B,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACpC,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,CAAC,oBAAoB,GAAG,YAAY,CAAC,EAAE,GAAG,mBAAmB,CAAC;CA6F1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-query.js","sources":["../../../../../zero-cache/src/custom-queries/transform-query.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {TimedCache} from '../../../shared/src/cache.ts';\nimport {getErrorMessage} from '../../../shared/src/error.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {\n transformResponseMessageSchema,\n type ErroredQuery,\n type TransformRequestBody,\n type TransformRequestMessage,\n} from '../../../zero-protocol/src/custom-queries.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../zero-protocol/src/error-reason.ts';\nimport {\n isProtocolError,\n type TransformFailedBody,\n} from '../../../zero-protocol/src/error.ts';\nimport {hashOfAST} from '../../../zero-protocol/src/query-hash.ts';\nimport type {TransformedAndHashed} from '../auth/read-authorizer.ts';\nimport {\n compileUrlPattern,\n fetchFromAPIServer,\n type HeaderOptions,\n} from '../custom/fetch.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport type {ShardID} from '../types/shards.ts';\n\n/**\n * Transforms a custom query by calling the user's API server.\n * Caches the transformed queries for 5 seconds to avoid unnecessary API calls.\n *\n * Error responses are not cached as the user may want to retry the query\n * and the error may be transient.\n *\n * The TTL was chosen to be 5 seconds since custom query requests come with\n * a token which itself may have a short TTL (e.g., 10 seconds).\n *\n * Token expiration isn't expected to be exact so this 5 second\n * caching shouldn't cause unexpected behavior. E.g., many JWT libraries\n * implement leeway for expiration checks: https://github.com/panva/jose/blob/main/docs/jwt/verify/interfaces/JWTVerifyOptions.md#clocktolerance\n *\n * The ViewSyncer will call the API server 3-4 times with the exact same queries\n * if we do not cache requests.\n *\n * Caching is safe here because the cache key encodes both\n * the user's cookies and auth token. A user cannot see another user's\n * transformed queries unless they share the same token and cookies.\n */\nexport class CustomQueryTransformer {\n readonly #shard: ShardID;\n readonly #cache: TimedCache<TransformedAndHashed>;\n readonly #config: {\n url: string[];\n forwardCookies: boolean;\n };\n readonly #urlPatterns: URLPattern[];\n readonly #lc: LogContext;\n\n constructor(\n lc: LogContext,\n config: {\n url: string[];\n forwardCookies: boolean;\n },\n shard: ShardID,\n ) {\n this.#config = config;\n this.#shard = shard;\n this.#lc = lc;\n this.#urlPatterns = config.url.map(compileUrlPattern);\n this.#cache = new TimedCache(5000); // 5 seconds cache TTL\n }\n\n async transform(\n headerOptions: HeaderOptions,\n queries: Iterable<CustomQueryRecord>,\n userQueryURL: string | undefined,\n ): Promise<(TransformedAndHashed | ErroredQuery)[] | TransformFailedBody> {\n const request: TransformRequestBody = [];\n const cachedResponses: TransformedAndHashed[] = [];\n\n if (!this.#config.forwardCookies && headerOptions.cookie) {\n headerOptions = {\n ...headerOptions,\n cookie: undefined, // remove cookies if not forwarded\n };\n }\n\n // split queries into cached and uncached\n for (const query of queries) {\n const cacheKey = getCacheKey(headerOptions, query.id);\n const cached = this.#cache.get(cacheKey);\n if (cached) {\n cachedResponses.push(cached);\n } else {\n request.push({\n id: query.id,\n name: query.name,\n args: query.args,\n });\n }\n }\n\n if (request.length === 0) {\n return cachedResponses;\n }\n\n const queryIDs = request.map(r => r.id);\n\n try {\n const transformResponse = await fetchFromAPIServer(\n transformResponseMessageSchema,\n 'transform',\n this.#lc,\n userQueryURL ??\n must(\n this.#config.url[0],\n 'A ZERO_QUERY_URL must be configured for custom queries',\n ),\n
|
|
1
|
+
{"version":3,"file":"transform-query.js","sources":["../../../../../zero-cache/src/custom-queries/transform-query.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {TimedCache} from '../../../shared/src/cache.ts';\nimport {getErrorMessage} from '../../../shared/src/error.ts';\nimport {must} from '../../../shared/src/must.ts';\nimport {\n transformResponseMessageSchema,\n type ErroredQuery,\n type TransformRequestBody,\n type TransformRequestMessage,\n} from '../../../zero-protocol/src/custom-queries.ts';\nimport {ErrorKind} from '../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../zero-protocol/src/error-reason.ts';\nimport {\n isProtocolError,\n type TransformFailedBody,\n} from '../../../zero-protocol/src/error.ts';\nimport {hashOfAST} from '../../../zero-protocol/src/query-hash.ts';\nimport type {TransformedAndHashed} from '../auth/read-authorizer.ts';\nimport {\n compileUrlPattern,\n fetchFromAPIServer,\n type HeaderOptions,\n} from '../custom/fetch.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport type {ShardID} from '../types/shards.ts';\n\n/**\n * Transforms a custom query by calling the user's API server.\n * Caches the transformed queries for 5 seconds to avoid unnecessary API calls.\n *\n * Error responses are not cached as the user may want to retry the query\n * and the error may be transient.\n *\n * The TTL was chosen to be 5 seconds since custom query requests come with\n * a token which itself may have a short TTL (e.g., 10 seconds).\n *\n * Token expiration isn't expected to be exact so this 5 second\n * caching shouldn't cause unexpected behavior. E.g., many JWT libraries\n * implement leeway for expiration checks: https://github.com/panva/jose/blob/main/docs/jwt/verify/interfaces/JWTVerifyOptions.md#clocktolerance\n *\n * The ViewSyncer will call the API server 3-4 times with the exact same queries\n * if we do not cache requests.\n *\n * Caching is safe here because the cache key encodes both\n * the user's cookies and auth token. A user cannot see another user's\n * transformed queries unless they share the same token and cookies.\n */\nexport class CustomQueryTransformer {\n readonly #shard: ShardID;\n readonly #cache: TimedCache<TransformedAndHashed>;\n readonly #config: {\n url: string[];\n forwardCookies: boolean;\n };\n readonly #urlPatterns: URLPattern[];\n readonly #lc: LogContext;\n\n constructor(\n lc: LogContext,\n config: {\n url: string[];\n forwardCookies: boolean;\n },\n shard: ShardID,\n ) {\n this.#config = config;\n this.#shard = shard;\n this.#lc = lc;\n this.#urlPatterns = config.url.map(compileUrlPattern);\n this.#cache = new TimedCache(5000); // 5 seconds cache TTL\n }\n\n async transform(\n headerOptions: HeaderOptions,\n queries: Iterable<CustomQueryRecord>,\n userQueryURL: string | undefined,\n ): Promise<(TransformedAndHashed | ErroredQuery)[] | TransformFailedBody> {\n const request: TransformRequestBody = [];\n const cachedResponses: TransformedAndHashed[] = [];\n\n if (!this.#config.forwardCookies && headerOptions.cookie) {\n headerOptions = {\n ...headerOptions,\n cookie: undefined, // remove cookies if not forwarded\n };\n }\n\n // split queries into cached and uncached\n for (const query of queries) {\n const cacheKey = getCacheKey(headerOptions, query.id);\n const cached = this.#cache.get(cacheKey);\n if (cached) {\n cachedResponses.push(cached);\n } else {\n request.push({\n id: query.id,\n name: query.name,\n args: query.args,\n });\n }\n }\n\n if (request.length === 0) {\n return cachedResponses;\n }\n\n const queryIDs = request.map(r => r.id);\n\n try {\n const transformResponse = await fetchFromAPIServer(\n transformResponseMessageSchema,\n 'transform',\n this.#lc,\n userQueryURL ??\n must(\n this.#config.url[0],\n 'A ZERO_QUERY_URL must be configured for custom queries',\n ),\n this.#urlPatterns,\n this.#shard,\n headerOptions,\n ['transform', request] satisfies TransformRequestMessage,\n );\n\n if (transformResponse[0] === 'transformFailed') {\n return transformResponse[1];\n }\n\n const newResponses = transformResponse[1].map(transformed => {\n if ('error' in transformed) {\n return transformed;\n }\n return {\n id: transformed.id,\n transformedAst: transformed.ast,\n transformationHash: hashOfAST(transformed.ast),\n } satisfies TransformedAndHashed;\n });\n\n for (const transformed of newResponses) {\n if ('error' in transformed) {\n // do not cache error responses\n continue;\n }\n const cacheKey = getCacheKey(headerOptions, transformed.id);\n this.#cache.set(cacheKey, transformed);\n }\n\n return newResponses.concat(cachedResponses);\n } catch (e) {\n if (\n isProtocolError(e) &&\n e.errorBody.kind === ErrorKind.TransformFailed\n ) {\n return {\n ...e.errorBody,\n queryIDs,\n } as const satisfies TransformFailedBody;\n }\n\n return {\n kind: ErrorKind.TransformFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Failed to transform queries: ${getErrorMessage(e)}`,\n queryIDs,\n } as const satisfies TransformFailedBody;\n }\n }\n}\n\nfunction getCacheKey(headerOptions: HeaderOptions, queryID: string) {\n // For custom queries, queryID is a hash of the name + args.\n // the APIKey from headerOptions is static. Not needed for the cache key.\n // The token is used to identify the user and should be included in the cache key.\n return `${headerOptions.token}:${headerOptions.cookie}:${queryID}`;\n}\n"],"names":["ErrorKind.TransformFailed","ErrorOrigin.ZeroCache","ErrorReason.Internal"],"mappings":";;;;;;;;;;AAgDO,MAAM,uBAAuB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EAIA;AAAA,EACA;AAAA,EAET,YACE,IACA,QAIA,OACA;AACA,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,eAAe,OAAO,IAAI,IAAI,iBAAiB;AACpD,SAAK,SAAS,IAAI,WAAW,GAAI;AAAA,EACnC;AAAA,EAEA,MAAM,UACJ,eACA,SACA,cACwE;AACxE,UAAM,UAAgC,CAAA;AACtC,UAAM,kBAA0C,CAAA;AAEhD,QAAI,CAAC,KAAK,QAAQ,kBAAkB,cAAc,QAAQ;AACxD,sBAAgB;AAAA,QACd,GAAG;AAAA,QACH,QAAQ;AAAA;AAAA,MAAA;AAAA,IAEZ;AAGA,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,YAAY,eAAe,MAAM,EAAE;AACpD,YAAM,SAAS,KAAK,OAAO,IAAI,QAAQ;AACvC,UAAI,QAAQ;AACV,wBAAgB,KAAK,MAAM;AAAA,MAC7B,OAAO;AACL,gBAAQ,KAAK;AAAA,UACX,IAAI,MAAM;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,MAAM,MAAM;AAAA,QAAA,CACb;AAAA,MACH;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,QAAQ,IAAI,CAAA,MAAK,EAAE,EAAE;AAEtC,QAAI;AACF,YAAM,oBAAoB,MAAM;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,gBACE;AAAA,UACE,KAAK,QAAQ,IAAI,CAAC;AAAA,UAClB;AAAA,QAAA;AAAA,QAEJ,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,QACA,CAAC,aAAa,OAAO;AAAA,MAAA;AAGvB,UAAI,kBAAkB,CAAC,MAAM,mBAAmB;AAC9C,eAAO,kBAAkB,CAAC;AAAA,MAC5B;AAEA,YAAM,eAAe,kBAAkB,CAAC,EAAE,IAAI,CAAA,gBAAe;AAC3D,YAAI,WAAW,aAAa;AAC1B,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,UACL,IAAI,YAAY;AAAA,UAChB,gBAAgB,YAAY;AAAA,UAC5B,oBAAoB,UAAU,YAAY,GAAG;AAAA,QAAA;AAAA,MAEjD,CAAC;AAED,iBAAW,eAAe,cAAc;AACtC,YAAI,WAAW,aAAa;AAE1B;AAAA,QACF;AACA,cAAM,WAAW,YAAY,eAAe,YAAY,EAAE;AAC1D,aAAK,OAAO,IAAI,UAAU,WAAW;AAAA,MACvC;AAEA,aAAO,aAAa,OAAO,eAAe;AAAA,IAC5C,SAAS,GAAG;AACV,UACE,gBAAgB,CAAC,KACjB,EAAE,UAAU,SAASA,iBACrB;AACA,eAAO;AAAA,UACL,GAAG,EAAE;AAAA,UACL;AAAA,QAAA;AAAA,MAEJ;AAEA,aAAO;AAAA,QACL,MAAMA;AAAAA,QACN,QAAQC;AAAAA,QACR,QAAQC;AAAAA,QACR,SAAS,gCAAgC,gBAAgB,CAAC,CAAC;AAAA,QAC3D;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AACF;AAEA,SAAS,YAAY,eAA8B,SAAiB;AAIlE,SAAO,GAAG,cAAc,KAAK,IAAI,cAAc,MAAM,IAAI,OAAO;AAClE;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector-delegate.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AACvD,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"inspector-delegate.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,6BAA6B,CAAC;AAEnE,OAAO,EAAC,OAAO,EAAC,MAAM,gCAAgC,CAAC;AACvD,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,mCAAmC,CAAC;AAC3D,OAAO,KAAK,EAAC,aAAa,IAAI,iBAAiB,EAAC,MAAM,4CAA4C,CAAC;AAEnG,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,eAAe,EACrB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,sCAAsC,CAAC;AACjF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AAItD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,8BAA8B,EAAE,OAAO,CAAC;IACxC,qBAAqB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,KAAK,aAAa,GAAG,MAAM,CAAC;AAQ5B,qBAAa,iBAAkB,YAAW,eAAe;;gBAQ3C,sBAAsB,EAAE,sBAAsB,GAAG,SAAS;IAItE,SAAS,CAAC,CAAC,SAAS,MAAM,SAAS,EACjC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GACpB,IAAI;IAeP,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAKjE,cAAc;;;;IAId,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS;IAOhD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAalC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI;IAWrE;;;OAGG;IACH,eAAe,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO;IAMtD,gBAAgB,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI;IAIpD,kBAAkB,CAAC,aAAa,EAAE,aAAa;IAI/C;;;;OAIG;IACG,oBAAoB,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,iBAAiB,EAAE,EAClC,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,GAAG,CAAC;CA2ChB"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { assert } from "../../../shared/src/asserts.js";
|
|
2
2
|
import { mapValues } from "../../../shared/src/objects.js";
|
|
3
3
|
import { TDigest } from "../../../shared/src/tdigest.js";
|
|
4
|
-
import { ProtocolError } from "../../../zero-protocol/src/error.js";
|
|
5
4
|
import { hashOfNameAndArgs } from "../../../zero-protocol/src/query-hash.js";
|
|
6
5
|
import { isServerMetric } from "../../../zql/src/query/metrics-delegate.js";
|
|
7
6
|
import { isDevelopmentMode } from "../config/normalize.js";
|
|
7
|
+
import { ProtocolErrorWithLevel } from "../types/error-with-level.js";
|
|
8
8
|
const authenticatedClientGroupIDs = /* @__PURE__ */ new Set();
|
|
9
9
|
class InspectorDelegate {
|
|
10
10
|
#globalMetrics = newMetrics();
|
|
@@ -100,7 +100,7 @@ class InspectorDelegate {
|
|
|
100
100
|
userQueryURL
|
|
101
101
|
);
|
|
102
102
|
if ("kind" in results) {
|
|
103
|
-
throw new
|
|
103
|
+
throw new ProtocolErrorWithLevel(results, "warn");
|
|
104
104
|
}
|
|
105
105
|
const result = results[0];
|
|
106
106
|
if (!result) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector-delegate.js","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport
|
|
1
|
+
{"version":3,"file":"inspector-delegate.js","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {ServerMetrics as ServerMetricsJSON} from '../../../zero-protocol/src/inspect-down.ts';\nimport {hashOfNameAndArgs} from '../../../zero-protocol/src/query-hash.ts';\nimport {\n isServerMetric,\n type MetricMap,\n type MetricsDelegate,\n} from '../../../zql/src/query/metrics-delegate.ts';\nimport {isDevelopmentMode} from '../config/normalize.ts';\nimport type {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport type {HeaderOptions} from '../custom/fetch.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\n\n/**\n * Server-side metrics collected for queries during materialization and update.\n * These metrics are reported via the inspector and complement client-side metrics.\n */\nexport type ServerMetrics = {\n 'query-materialization-server': TDigest;\n 'query-update-server': TDigest;\n};\n\ntype ClientGroupID = string;\n\n/**\n * Set of authenticated client group IDs. We keep this outside of the class to\n * share this state across all instances of the InspectorDelegate.\n */\nconst authenticatedClientGroupIDs = new Set<ClientGroupID>();\n\nexport class InspectorDelegate implements MetricsDelegate {\n readonly #globalMetrics: ServerMetrics = newMetrics();\n readonly #perQueryServerMetrics = new Map<string, ServerMetrics>();\n readonly #hashToIDs = new Map<string, Set<string>>();\n readonly #queryIDToTransformationHash = new Map<string, string>();\n readonly #transformationASTs: Map<string, AST> = new Map();\n readonly #customQueryTransformer: CustomQueryTransformer | undefined;\n\n constructor(customQueryTransformer: CustomQueryTransformer | undefined) {\n this.#customQueryTransformer = customQueryTransformer;\n }\n\n addMetric<K extends keyof MetricMap>(\n metric: K,\n value: number,\n ...args: MetricMap[K]\n ): void {\n assert(isServerMetric(metric), `Invalid server metric: ${metric}`);\n const transformationHash = args[0];\n\n for (const queryID of this.#hashToIDs.get(transformationHash) ?? []) {\n let serverMetrics = this.#perQueryServerMetrics.get(queryID);\n if (!serverMetrics) {\n serverMetrics = newMetrics();\n this.#perQueryServerMetrics.set(queryID, serverMetrics);\n }\n serverMetrics[metric].add(value);\n }\n this.#globalMetrics[metric].add(value);\n }\n\n getMetricsJSONForQuery(queryID: string): ServerMetricsJSON | null {\n const serverMetrics = this.#perQueryServerMetrics.get(queryID);\n return serverMetrics ? mapValues(serverMetrics, v => v.toJSON()) : null;\n }\n\n getMetricsJSON() {\n return mapValues(this.#globalMetrics, v => v.toJSON());\n }\n\n getASTForQuery(queryID: string): AST | undefined {\n const transformationHash = this.#queryIDToTransformationHash.get(queryID);\n return transformationHash\n ? this.#transformationASTs.get(transformationHash)\n : undefined;\n }\n\n removeQuery(queryID: string): void {\n this.#perQueryServerMetrics.delete(queryID);\n this.#queryIDToTransformationHash.delete(queryID);\n // Remove queryID from all hash-to-ID mappings\n for (const [transformationHash, idSet] of this.#hashToIDs.entries()) {\n idSet.delete(queryID);\n if (idSet.size === 0) {\n this.#hashToIDs.delete(transformationHash);\n this.#transformationASTs.delete(transformationHash);\n }\n }\n }\n\n addQuery(transformationHash: string, queryID: string, ast: AST): void {\n const existing = this.#hashToIDs.get(transformationHash);\n if (existing === undefined) {\n this.#hashToIDs.set(transformationHash, new Set([queryID]));\n } else {\n existing.add(queryID);\n }\n this.#queryIDToTransformationHash.set(queryID, transformationHash);\n this.#transformationASTs.set(transformationHash, ast);\n }\n\n /**\n * Check if the client is authenticated. We only require authentication once\n * per \"worker\".\n */\n isAuthenticated(clientGroupID: ClientGroupID): boolean {\n return (\n isDevelopmentMode() || authenticatedClientGroupIDs.has(clientGroupID)\n );\n }\n\n setAuthenticated(clientGroupID: ClientGroupID): void {\n authenticatedClientGroupIDs.add(clientGroupID);\n }\n\n clearAuthenticated(clientGroupID: ClientGroupID) {\n authenticatedClientGroupIDs.delete(clientGroupID);\n }\n\n /**\n * Transforms a single custom query by name and args using the configured\n * CustomQueryTransformer. This is primarily used by the inspector to transform\n * queries for analysis.\n */\n async transformCustomQuery(\n name: string,\n args: readonly ReadonlyJSONValue[],\n headerOptions: HeaderOptions,\n userQueryURL: string | undefined,\n ): Promise<AST> {\n assert(\n this.#customQueryTransformer,\n 'Custom query transformation requested but no CustomQueryTransformer is configured',\n );\n\n // Create a fake CustomQueryRecord for the single query\n const queryID = hashOfNameAndArgs(name, args);\n const queries: CustomQueryRecord[] = [\n {\n id: queryID,\n type: 'custom',\n name,\n args,\n clientState: {},\n },\n ];\n\n const results = await this.#customQueryTransformer.transform(\n headerOptions,\n queries,\n userQueryURL,\n );\n\n if ('kind' in results) {\n throw new ProtocolErrorWithLevel(results, 'warn');\n }\n\n const result = results[0];\n if (!result) {\n throw new Error('No transformation result returned');\n }\n\n if ('error' in result) {\n const message =\n result.message ?? 'Unknown application error from custom query';\n throw new Error(\n `Error transforming custom query ${name} (${result.error}): ${message} ${JSON.stringify(result.details)}`,\n );\n }\n\n return result.transformedAst;\n }\n}\n\nfunction newMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n"],"names":[],"mappings":";;;;;;;AAiCA,MAAM,kDAAkC,IAAA;AAEjC,MAAM,kBAA6C;AAAA,EAC/C,iBAAgC,WAAA;AAAA,EAChC,6CAA6B,IAAA;AAAA,EAC7B,iCAAiB,IAAA;AAAA,EACjB,mDAAmC,IAAA;AAAA,EACnC,0CAA4C,IAAA;AAAA,EAC5C;AAAA,EAET,YAAY,wBAA4D;AACtE,SAAK,0BAA0B;AAAA,EACjC;AAAA,EAEA,UACE,QACA,UACG,MACG;AACN,WAAO,eAAe,MAAM,GAAG,0BAA0B,MAAM,EAAE;AACjE,UAAM,qBAAqB,KAAK,CAAC;AAEjC,eAAW,WAAW,KAAK,WAAW,IAAI,kBAAkB,KAAK,IAAI;AACnE,UAAI,gBAAgB,KAAK,uBAAuB,IAAI,OAAO;AAC3D,UAAI,CAAC,eAAe;AAClB,wBAAgB,WAAA;AAChB,aAAK,uBAAuB,IAAI,SAAS,aAAa;AAAA,MACxD;AACA,oBAAc,MAAM,EAAE,IAAI,KAAK;AAAA,IACjC;AACA,SAAK,eAAe,MAAM,EAAE,IAAI,KAAK;AAAA,EACvC;AAAA,EAEA,uBAAuB,SAA2C;AAChE,UAAM,gBAAgB,KAAK,uBAAuB,IAAI,OAAO;AAC7D,WAAO,gBAAgB,UAAU,eAAe,OAAK,EAAE,OAAA,CAAQ,IAAI;AAAA,EACrE;AAAA,EAEA,iBAAiB;AACf,WAAO,UAAU,KAAK,gBAAgB,CAAA,MAAK,EAAE,QAAQ;AAAA,EACvD;AAAA,EAEA,eAAe,SAAkC;AAC/C,UAAM,qBAAqB,KAAK,6BAA6B,IAAI,OAAO;AACxE,WAAO,qBACH,KAAK,oBAAoB,IAAI,kBAAkB,IAC/C;AAAA,EACN;AAAA,EAEA,YAAY,SAAuB;AACjC,SAAK,uBAAuB,OAAO,OAAO;AAC1C,SAAK,6BAA6B,OAAO,OAAO;AAEhD,eAAW,CAAC,oBAAoB,KAAK,KAAK,KAAK,WAAW,WAAW;AACnE,YAAM,OAAO,OAAO;AACpB,UAAI,MAAM,SAAS,GAAG;AACpB,aAAK,WAAW,OAAO,kBAAkB;AACzC,aAAK,oBAAoB,OAAO,kBAAkB;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAS,oBAA4B,SAAiB,KAAgB;AACpE,UAAM,WAAW,KAAK,WAAW,IAAI,kBAAkB;AACvD,QAAI,aAAa,QAAW;AAC1B,WAAK,WAAW,IAAI,oBAAoB,oBAAI,IAAI,CAAC,OAAO,CAAC,CAAC;AAAA,IAC5D,OAAO;AACL,eAAS,IAAI,OAAO;AAAA,IACtB;AACA,SAAK,6BAA6B,IAAI,SAAS,kBAAkB;AACjE,SAAK,oBAAoB,IAAI,oBAAoB,GAAG;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,eAAuC;AACrD,WACE,kBAAA,KAAuB,4BAA4B,IAAI,aAAa;AAAA,EAExE;AAAA,EAEA,iBAAiB,eAAoC;AACnD,gCAA4B,IAAI,aAAa;AAAA,EAC/C;AAAA,EAEA,mBAAmB,eAA8B;AAC/C,gCAA4B,OAAO,aAAa;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBACJ,MACA,MACA,eACA,cACc;AACd;AAAA,MACE,KAAK;AAAA,MACL;AAAA,IAAA;AAIF,UAAM,UAAU,kBAAkB,MAAM,IAAI;AAC5C,UAAM,UAA+B;AAAA,MACnC;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,aAAa,CAAA;AAAA,MAAC;AAAA,IAChB;AAGF,UAAM,UAAU,MAAM,KAAK,wBAAwB;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,QAAI,UAAU,SAAS;AACrB,YAAM,IAAI,uBAAuB,SAAS,MAAM;AAAA,IAClD;AAEA,UAAM,SAAS,QAAQ,CAAC;AACxB,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAEA,QAAI,WAAW,QAAQ;AACrB,YAAM,UACJ,OAAO,WAAW;AACpB,YAAM,IAAI;AAAA,QACR,mCAAmC,IAAI,KAAK,OAAO,KAAK,MAAM,OAAO,IAAI,KAAK,UAAU,OAAO,OAAO,CAAC;AAAA,MAAA;AAAA,IAE3G;AAEA,WAAO,OAAO;AAAA,EAChB;AACF;AAEA,SAAS,aAA4B;AACnC,SAAO;AAAA,IACL,gCAAgC,IAAI,QAAA;AAAA,IACpC,uBAAuB,IAAI,QAAA;AAAA,EAAQ;AAEvC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uCAAuC,CAAC;AAQtE,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,QAAQ,EAEd,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,6BAA6B,CAAC;AAK5D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,iBAAiB,EAAE,OAAO,EAAC,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,MAAO,SAAQ,iBAAiB;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAErC,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAClD,MAAM,CAAC,UAAU,CAAC,CAAC;IACtB,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,aAAa,CAAC;IACjB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAED,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAc,YAAW,OAAO,EAAE,MAAM;;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAWlB,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG;QAAC,GAAG,EAAE,MAAM,EAAE,CAAA;KAAC,EAChD,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,MAAM;IAgBvB,IAAI,OAAO,IAAI,MAAM,GAAG,SAAS,CAEhC;IAED,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAUrD,WAAW,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,aAAa,EAAE,YAAY,CAAC;IAWjC,oBAAoB,CAAC,MAAM,EAAE,UAAU;IAW7C,GAAG;IAKH,KAAK;IAQL,OAAO,IAAI,OAAO;IAIlB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAKpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQtB;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,KAAK,iBAAiB,GAAG,WAAW,GAAG,MAAM,CAAC;AA6T9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,CAAC,iBAAiB,GAAG,SAAS,CAAC,EAAE,GAClD,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAqC1B"}
|
|
@@ -299,7 +299,6 @@ class PushWorker {
|
|
|
299
299
|
"push",
|
|
300
300
|
this.#lc,
|
|
301
301
|
url,
|
|
302
|
-
url === this.#userPushURL,
|
|
303
302
|
this.#pushURLPatterns,
|
|
304
303
|
{
|
|
305
304
|
appID: this.#config.app.id,
|
|
@@ -330,8 +329,7 @@ class PushWorker {
|
|
|
330
329
|
}
|
|
331
330
|
}
|
|
332
331
|
#failDownstream(downstream, errorBody) {
|
|
333
|
-
|
|
334
|
-
downstream.fail(new ProtocolErrorWithLevel(errorBody, logLevel));
|
|
332
|
+
downstream.fail(new ProtocolErrorWithLevel(errorBody, "warn"));
|
|
335
333
|
}
|
|
336
334
|
}
|
|
337
335
|
function combinePushes(entries) {
|