@gullabs/google 0.5.2 → 0.6.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 +25 -4
- package/dist/index.cjs +264 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +265 -59
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import { LlmError,
|
|
1
|
+
import { LlmError, assertNever, classifyError, redactSecrets } from '@gullabs/core';
|
|
2
2
|
|
|
3
3
|
// src/adapter.ts
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
function requireApiKey(auth) {
|
|
5
|
+
if (!("apiKey" in auth) || typeof auth.apiKey !== "string" || auth.apiKey.trim() === "") {
|
|
6
|
+
throw new LlmError("@gullabs/google requires auth.apiKey", {
|
|
7
|
+
kind: "invalid_auth",
|
|
8
|
+
retryable: false,
|
|
9
|
+
provider: "google"
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
return auth.apiKey;
|
|
13
|
+
}
|
|
6
14
|
var FLEX_DEFAULT_TIMEOUT_MS = 15e5;
|
|
7
15
|
var STANDARD_DEFAULT_TIMEOUT_MS = 3e5;
|
|
8
16
|
var TRANSPORT_TIMEOUT_BUFFER_MS = 5e3;
|
|
9
17
|
async function buildGoogleClient(auth) {
|
|
10
18
|
const { GoogleGenAI } = await import('@google/genai');
|
|
11
|
-
const ai = new GoogleGenAI({ apiKey: auth
|
|
19
|
+
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
12
20
|
return {
|
|
13
21
|
models: {
|
|
14
22
|
async generateContent(params) {
|
|
@@ -19,6 +27,14 @@ async function buildGoogleClient(auth) {
|
|
|
19
27
|
};
|
|
20
28
|
}
|
|
21
29
|
|
|
30
|
+
// src/reasoning-budget.ts
|
|
31
|
+
var GOOGLE_REASONING_EFFORT_BUDGET = {
|
|
32
|
+
none: 0,
|
|
33
|
+
low: 1024,
|
|
34
|
+
medium: 8192,
|
|
35
|
+
high: 24576
|
|
36
|
+
};
|
|
37
|
+
|
|
22
38
|
// src/flex-fallback.ts
|
|
23
39
|
var CAPACITY_PATTERNS = [
|
|
24
40
|
/capacity/i,
|
|
@@ -49,6 +65,231 @@ function isGeminiCapacityError(err) {
|
|
|
49
65
|
}
|
|
50
66
|
|
|
51
67
|
// src/adapter.ts
|
|
68
|
+
var ALLOWED_GOOGLE_PROVIDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
69
|
+
"cachedContent",
|
|
70
|
+
"httpOptions",
|
|
71
|
+
"safetySettings",
|
|
72
|
+
"tools"
|
|
73
|
+
]);
|
|
74
|
+
var ALLOWED_GOOGLE_HTTP_OPTION_KEYS = /* @__PURE__ */ new Set(["timeout"]);
|
|
75
|
+
var RESERVED_GOOGLE_PROVIDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
76
|
+
"abortSignal",
|
|
77
|
+
"imageConfig",
|
|
78
|
+
"maxOutputTokens",
|
|
79
|
+
"mediaResolution",
|
|
80
|
+
"responseFormat",
|
|
81
|
+
"responseMimeType",
|
|
82
|
+
"responseModalities",
|
|
83
|
+
"responseSchema",
|
|
84
|
+
"responseJsonSchema",
|
|
85
|
+
"serviceTier",
|
|
86
|
+
"speechConfig",
|
|
87
|
+
"stopSequences",
|
|
88
|
+
"temperature",
|
|
89
|
+
"thinkingConfig",
|
|
90
|
+
"topK",
|
|
91
|
+
"topP",
|
|
92
|
+
"_responseJsonSchema"
|
|
93
|
+
]);
|
|
94
|
+
var GOOGLE_SEARCH_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
|
|
95
|
+
"gemini-2.5-flash",
|
|
96
|
+
"gemini-2.5-flash-lite",
|
|
97
|
+
"gemini-2.5-pro",
|
|
98
|
+
"gemini-3-flash-preview",
|
|
99
|
+
"gemini-3.1-flash-lite",
|
|
100
|
+
"gemini-3.1-pro-preview",
|
|
101
|
+
"gemini-3.5-flash"
|
|
102
|
+
]);
|
|
103
|
+
var STRUCTURED_OUTPUT_GOOGLE_SEARCH_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
104
|
+
"gemini-3.1-pro-preview",
|
|
105
|
+
"gemini-3.5-flash"
|
|
106
|
+
]);
|
|
107
|
+
function isPlainRecord(value) {
|
|
108
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
109
|
+
}
|
|
110
|
+
function isEmptyPlainObject(value) {
|
|
111
|
+
return isPlainRecord(value) && Object.keys(value).length === 0;
|
|
112
|
+
}
|
|
113
|
+
function badGoogleProviderOptions(message) {
|
|
114
|
+
return new LlmError(message, { kind: "bad_request", retryable: false });
|
|
115
|
+
}
|
|
116
|
+
function parseGoogleTool(tool, model) {
|
|
117
|
+
if (!isPlainRecord(tool)) {
|
|
118
|
+
throw badGoogleProviderOptions(
|
|
119
|
+
`providerOptions.google.tools entries must be objects for model "${model}".`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const keys = Object.keys(tool);
|
|
123
|
+
if (keys.length !== 1) {
|
|
124
|
+
throw badGoogleProviderOptions(
|
|
125
|
+
`providerOptions.google.tools entries must have exactly one supported tool key for model "${model}".`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const key = keys[0];
|
|
129
|
+
switch (key) {
|
|
130
|
+
case "googleSearch": {
|
|
131
|
+
if (!isEmptyPlainObject(tool["googleSearch"])) {
|
|
132
|
+
throw badGoogleProviderOptions(
|
|
133
|
+
`providerOptions.google.tools[].googleSearch must be an empty object for model "${model}".`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
return { googleSearch: {} };
|
|
137
|
+
}
|
|
138
|
+
default:
|
|
139
|
+
throw badGoogleProviderOptions(
|
|
140
|
+
`providerOptions.google.tools[].${key} is not supported for model "${model}".`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function parseGoogleSafetySetting(setting, index, model) {
|
|
145
|
+
if (!isPlainRecord(setting)) {
|
|
146
|
+
throw badGoogleProviderOptions(
|
|
147
|
+
`providerOptions.google.safetySettings[${index}] must be an object for model "${model}".`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const keys = Object.keys(setting);
|
|
151
|
+
const unknownKeys = keys.filter((key) => key !== "category" && key !== "threshold");
|
|
152
|
+
if (unknownKeys.length > 0) {
|
|
153
|
+
throw badGoogleProviderOptions(
|
|
154
|
+
`providerOptions.google.safetySettings[${index}] contains unsupported keys [${unknownKeys.join(
|
|
155
|
+
", "
|
|
156
|
+
)}] for model "${model}". Allowed keys: category, threshold.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (typeof setting["category"] !== "string" || setting["category"].length === 0) {
|
|
160
|
+
throw badGoogleProviderOptions(
|
|
161
|
+
`providerOptions.google.safetySettings[${index}].category must be a non-empty string for model "${model}".`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (typeof setting["threshold"] !== "string" || setting["threshold"].length === 0) {
|
|
165
|
+
throw badGoogleProviderOptions(
|
|
166
|
+
`providerOptions.google.safetySettings[${index}].threshold must be a non-empty string for model "${model}".`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
category: setting["category"],
|
|
171
|
+
threshold: setting["threshold"]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function mapGoogleProviderOptions(googleOpts, model, structuredOutputRequested, descriptorGrounding) {
|
|
175
|
+
if (googleOpts === void 0) {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
if (!isPlainRecord(googleOpts)) {
|
|
179
|
+
throw badGoogleProviderOptions(
|
|
180
|
+
`providerOptions.google must be an object for model "${model}".`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const reservedKeys = Object.keys(googleOpts).filter(
|
|
184
|
+
(key) => RESERVED_GOOGLE_PROVIDER_OPTION_KEYS.has(key)
|
|
185
|
+
);
|
|
186
|
+
if (reservedKeys.length > 0) {
|
|
187
|
+
throw badGoogleProviderOptions(
|
|
188
|
+
`providerOptions.google reserves keys [${reservedKeys.join(
|
|
189
|
+
", "
|
|
190
|
+
)}] for typed model config on "${model}".`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
const unknownKeys = Object.keys(googleOpts).filter(
|
|
194
|
+
(key) => !ALLOWED_GOOGLE_PROVIDER_OPTION_KEYS.has(key) && !RESERVED_GOOGLE_PROVIDER_OPTION_KEYS.has(key)
|
|
195
|
+
);
|
|
196
|
+
if (unknownKeys.length > 0) {
|
|
197
|
+
throw badGoogleProviderOptions(
|
|
198
|
+
`providerOptions.google contains unsupported keys [${unknownKeys.join(
|
|
199
|
+
", "
|
|
200
|
+
)}] for model "${model}". Allowed keys: cachedContent, httpOptions, safetySettings, tools.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
const mapped = {};
|
|
204
|
+
if (googleOpts["cachedContent"] !== void 0) {
|
|
205
|
+
if (typeof googleOpts["cachedContent"] !== "string" || googleOpts["cachedContent"].length === 0) {
|
|
206
|
+
throw badGoogleProviderOptions(
|
|
207
|
+
`providerOptions.google.cachedContent must be a non-empty string for model "${model}".`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
mapped.cachedContent = googleOpts["cachedContent"];
|
|
211
|
+
}
|
|
212
|
+
if (googleOpts["httpOptions"] !== void 0) {
|
|
213
|
+
if (!isPlainRecord(googleOpts["httpOptions"])) {
|
|
214
|
+
throw badGoogleProviderOptions(
|
|
215
|
+
`providerOptions.google.httpOptions must be an object for model "${model}".`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
const unknownHttpOptionKeys = Object.keys(googleOpts["httpOptions"]).filter(
|
|
219
|
+
(key) => !ALLOWED_GOOGLE_HTTP_OPTION_KEYS.has(key)
|
|
220
|
+
);
|
|
221
|
+
if (unknownHttpOptionKeys.length > 0) {
|
|
222
|
+
throw badGoogleProviderOptions(
|
|
223
|
+
`providerOptions.google.httpOptions contains unsupported keys [${unknownHttpOptionKeys.join(
|
|
224
|
+
", "
|
|
225
|
+
)}] for model "${model}". Allowed keys: timeout.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
const timeout = googleOpts["httpOptions"]["timeout"];
|
|
229
|
+
if (timeout !== void 0) {
|
|
230
|
+
if (typeof timeout !== "number" || !Number.isInteger(timeout) || timeout <= 0) {
|
|
231
|
+
throw badGoogleProviderOptions(
|
|
232
|
+
`providerOptions.google.httpOptions.timeout must be a positive integer for model "${model}".`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
mapped.httpOptions = { timeout };
|
|
236
|
+
} else {
|
|
237
|
+
mapped.httpOptions = {};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (googleOpts["safetySettings"] !== void 0) {
|
|
241
|
+
if (!Array.isArray(googleOpts["safetySettings"])) {
|
|
242
|
+
throw badGoogleProviderOptions(
|
|
243
|
+
`providerOptions.google.safetySettings must be an array for model "${model}".`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
mapped.safetySettings = googleOpts["safetySettings"].map(
|
|
247
|
+
(setting, index) => parseGoogleSafetySetting(setting, index, model)
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
if (googleOpts["tools"] !== void 0) {
|
|
251
|
+
if (!Array.isArray(googleOpts["tools"])) {
|
|
252
|
+
throw badGoogleProviderOptions(
|
|
253
|
+
`providerOptions.google.tools must be an array for model "${model}".`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
const tools = googleOpts["tools"].map((tool) => parseGoogleTool(tool, model));
|
|
257
|
+
const groundingSupported = descriptorGrounding === true || descriptorGrounding === void 0 && GOOGLE_SEARCH_SUPPORTED_MODELS.has(model);
|
|
258
|
+
if (!groundingSupported) {
|
|
259
|
+
throw badGoogleProviderOptions(
|
|
260
|
+
`providerOptions.google.tools is not supported for model "${model}".`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
if (structuredOutputRequested && !STRUCTURED_OUTPUT_GOOGLE_SEARCH_ALLOWLIST.has(model)) {
|
|
264
|
+
throw badGoogleProviderOptions(
|
|
265
|
+
`Structured output with googleSearch is supported only for models "gemini-3.1-pro-preview" and "gemini-3.5-flash"; got "${model}".`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
mapped.tools = tools;
|
|
269
|
+
}
|
|
270
|
+
return mapped;
|
|
271
|
+
}
|
|
272
|
+
function assertSamplingAllowed(config, model, sampling) {
|
|
273
|
+
if (sampling !== "fixed") {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const offendingSampling = [];
|
|
277
|
+
if ("temperature" in config) {
|
|
278
|
+
offendingSampling.push("temperature");
|
|
279
|
+
}
|
|
280
|
+
if ("topP" in config) {
|
|
281
|
+
offendingSampling.push("topP");
|
|
282
|
+
}
|
|
283
|
+
if ("topK" in config) {
|
|
284
|
+
offendingSampling.push("topK");
|
|
285
|
+
}
|
|
286
|
+
if (offendingSampling.length > 0) {
|
|
287
|
+
throw new LlmError(
|
|
288
|
+
`Sampling parameters [${offendingSampling.join(", ")}] are not supported for model "${model}" (fixed sampling).`,
|
|
289
|
+
{ kind: "bad_request", retryable: false }
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
52
293
|
function mapFinishReason(raw) {
|
|
53
294
|
if (raw === void 0) return void 0;
|
|
54
295
|
switch (raw) {
|
|
@@ -170,12 +411,6 @@ function geminiAdapter(opts) {
|
|
|
170
411
|
);
|
|
171
412
|
}
|
|
172
413
|
config.serviceTier = explicit;
|
|
173
|
-
} else {
|
|
174
|
-
if (req.modelDescriptor === void 0) {
|
|
175
|
-
config.serviceTier = "flex";
|
|
176
|
-
} else if (supported?.includes("flex") === true) {
|
|
177
|
-
config.serviceTier = "flex";
|
|
178
|
-
}
|
|
179
414
|
}
|
|
180
415
|
const reasoning = genConfig.reasoning;
|
|
181
416
|
if (reasoning !== void 0) {
|
|
@@ -187,7 +422,7 @@ function geminiAdapter(opts) {
|
|
|
187
422
|
);
|
|
188
423
|
}
|
|
189
424
|
if (reasoningApi === "budget") {
|
|
190
|
-
const budget = reasoning.budgetTokens !== void 0 ? reasoning.budgetTokens : reasoning.effort !== void 0 ?
|
|
425
|
+
const budget = reasoning.budgetTokens !== void 0 ? reasoning.budgetTokens : reasoning.effort !== void 0 ? GOOGLE_REASONING_EFFORT_BUDGET[reasoning.effort] : void 0;
|
|
191
426
|
config.thinkingConfig = {
|
|
192
427
|
...budget !== void 0 ? { thinkingBudget: budget } : {},
|
|
193
428
|
...reasoning.includeThoughts === true ? { includeThoughts: true } : {}
|
|
@@ -237,54 +472,25 @@ function geminiAdapter(opts) {
|
|
|
237
472
|
config.responseSchema = req.outputJsonSchema;
|
|
238
473
|
}
|
|
239
474
|
}
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
475
|
+
const googleProviderConfig = mapGoogleProviderOptions(
|
|
476
|
+
genConfig.providerOptions?.["google"],
|
|
477
|
+
model,
|
|
478
|
+
structuredOutputRequested,
|
|
479
|
+
req.modelDescriptor?.capabilities?.grounding
|
|
480
|
+
);
|
|
481
|
+
if (googleProviderConfig.cachedContent !== void 0) {
|
|
482
|
+
config.cachedContent = googleProviderConfig.cachedContent;
|
|
243
483
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const supportedAfterMerge = req.modelDescriptor.capabilities?.serviceTiers;
|
|
247
|
-
if (supportedAfterMerge === void 0 || !supportedAfterMerge.includes(mergedServiceTier)) {
|
|
248
|
-
throw new LlmError(
|
|
249
|
-
`serviceTier "${mergedServiceTier}" is not supported for model "${model}".`,
|
|
250
|
-
{ kind: "bad_request", retryable: false }
|
|
251
|
-
);
|
|
252
|
-
}
|
|
484
|
+
if (googleProviderConfig.httpOptions !== void 0) {
|
|
485
|
+
config.httpOptions = googleProviderConfig.httpOptions;
|
|
253
486
|
}
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
if ("temperature" in config) {
|
|
257
|
-
offendingSampling.push("temperature");
|
|
258
|
-
}
|
|
259
|
-
if ("topP" in config) {
|
|
260
|
-
offendingSampling.push("topP");
|
|
261
|
-
}
|
|
262
|
-
if ("topK" in config) {
|
|
263
|
-
offendingSampling.push("topK");
|
|
264
|
-
}
|
|
265
|
-
if (offendingSampling.length > 0) {
|
|
266
|
-
throw new LlmError(
|
|
267
|
-
`Sampling parameters [${offendingSampling.join(
|
|
268
|
-
", "
|
|
269
|
-
)}] are not supported for model "${model}" (fixed sampling); they were supplied via providerOptions.google.`,
|
|
270
|
-
{ kind: "bad_request", retryable: false }
|
|
271
|
-
);
|
|
272
|
-
}
|
|
487
|
+
if (googleProviderConfig.safetySettings !== void 0) {
|
|
488
|
+
config.safetySettings = googleProviderConfig.safetySettings;
|
|
273
489
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (t !== null && typeof t === "object") {
|
|
277
|
-
const tool = t;
|
|
278
|
-
return "googleSearch" in tool || "googleSearchRetrieval" in tool;
|
|
279
|
-
}
|
|
280
|
-
return false;
|
|
281
|
-
});
|
|
282
|
-
if (groundingRequested && structuredOutputRequested) {
|
|
283
|
-
throw new LlmError(
|
|
284
|
-
"Grounding (googleSearch) cannot be combined with structured output (output.jsonSchema) on Gemini; choose one.",
|
|
285
|
-
{ kind: "bad_request", retryable: false }
|
|
286
|
-
);
|
|
490
|
+
if (googleProviderConfig.tools !== void 0) {
|
|
491
|
+
config.tools = googleProviderConfig.tools;
|
|
287
492
|
}
|
|
493
|
+
assertSamplingAllowed(config, model, req.modelDescriptor?.capabilities?.sampling);
|
|
288
494
|
let tierTimeoutHandle;
|
|
289
495
|
const clearTierTimeout = () => {
|
|
290
496
|
if (tierTimeoutHandle !== void 0) {
|
|
@@ -471,11 +677,11 @@ var DEFAULT_TIMEOUT_MS = 3e5;
|
|
|
471
677
|
var realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
472
678
|
async function buildFilesClient(auth) {
|
|
473
679
|
const { GoogleGenAI } = await import('@google/genai');
|
|
474
|
-
const ai = new GoogleGenAI({ apiKey: auth
|
|
680
|
+
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
475
681
|
return {
|
|
476
682
|
async upload(params) {
|
|
477
683
|
const fileArg = params.file instanceof Uint8Array ? new Blob(
|
|
478
|
-
[params.file],
|
|
684
|
+
[Uint8Array.from(params.file)],
|
|
479
685
|
params.config?.mimeType !== void 0 && params.config.mimeType.length > 0 ? { type: params.config.mimeType } : {}
|
|
480
686
|
) : params.file;
|
|
481
687
|
const result = await ai.files.upload({
|
|
@@ -658,7 +864,7 @@ var DEFAULT_SKEW_SECONDS = 30;
|
|
|
658
864
|
var DEFAULT_EXTENSION_SECONDS = 3600;
|
|
659
865
|
async function buildCachesClient(auth) {
|
|
660
866
|
const { GoogleGenAI } = await import('@google/genai');
|
|
661
|
-
const ai = new GoogleGenAI({ apiKey: auth
|
|
867
|
+
const ai = new GoogleGenAI({ apiKey: requireApiKey(auth) });
|
|
662
868
|
return {
|
|
663
869
|
async create(params) {
|
|
664
870
|
const result = await ai.caches.create(params);
|
|
@@ -904,6 +1110,6 @@ function normalizeGroundingCitations(groundingMetadata) {
|
|
|
904
1110
|
return citations;
|
|
905
1111
|
}
|
|
906
1112
|
|
|
907
|
-
export { FLEX_DEFAULT_TIMEOUT_MS, GoogleCacheStore, GoogleFileStore, STANDARD_DEFAULT_TIMEOUT_MS, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, geminiAdapter, isGeminiCapacityError, normalizeGroundingCitations };
|
|
1113
|
+
export { FLEX_DEFAULT_TIMEOUT_MS, GoogleCacheStore, GoogleFileStore, STANDARD_DEFAULT_TIMEOUT_MS, TRANSPORT_TIMEOUT_BUFFER_MS, buildGoogleClient, geminiAdapter, isGeminiCapacityError, normalizeGroundingCitations, requireApiKey };
|
|
908
1114
|
//# sourceMappingURL=index.js.map
|
|
909
1115
|
//# sourceMappingURL=index.js.map
|