@mnemonik/shared 7.152.1 → 7.154.0

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.
@@ -1,3 +1,4 @@
1
+ import diagnosticsChannel from 'node:diagnostics_channel';
1
2
  /**
2
3
  * Hook dispatcher HTTP timeout budgets + AbortSignal helper.
3
4
  *
@@ -96,47 +97,59 @@ export function withHookTimeout(ms) {
96
97
  return { signal: ac.signal, cleanup: () => clearTimeout(timer) };
97
98
  }
98
99
  /**
99
- * One second attempt on the main hook call (POST /api/v1/hooks/injections).
100
+ * The main hook call (POST /api/v1/hooks/injections) is hedged: when the first
101
+ * request has not answered by HOOK_HEDGE_SHARE of the budget, a second request
102
+ * starts beside it on a fresh connection, and whichever answers first is used.
100
103
  *
101
- * Why it exists: on 24 October 2026 about a third of one machine's hook calls
102
- * were lost for 50 minutes to a stall between Cloudflare and one load-balancer
103
- * node. The server had accepted those requests and was waiting for a body that
104
- * never finished arriving. A second request opens a new connection and
105
- * normally lands on a healthy path. The call is idempotent by design (the
106
- * injection bus dedups on the server), so repeating it is safe.
104
+ * Why a second request at all: on 24 October 2026 about a third of one
105
+ * machine's hook calls were lost for 50 minutes to a stall between Cloudflare
106
+ * and one load-balancer node. The server had accepted those requests and was
107
+ * waiting for a body that never finished arriving. A second request opens a new
108
+ * connection and normally lands on a healthy path.
107
109
  *
108
- * Shape: the whole call, both attempts included, still ends inside `budgetMs`,
109
- * so the budget every hook event is checked against (tests/HookEventBudgets
110
- * .test.ts) and the host's kill limit do not move. The first attempt gets
111
- * HOOK_FIRST_ATTEMPT_SHARE of the budget; the second gets whatever is left.
112
- * A first attempt that fails fast leaves the second nearly the whole budget.
110
+ * Why it is a hedge and not a retry: v7.149.0 abandoned the first request at
111
+ * 65% of the budget and then retried. Every hook process opens its own
112
+ * connection (DNS, TCP and TLS from the user's machine to Cloudflare), and the
113
+ * credential is read before the request leaves, so on 25 October that first
114
+ * request had often been on the wire for only a few hundred milliseconds when
115
+ * it was abandoned. Answers that were merely slow were thrown away, half the
116
+ * calls on the owner's machine needed two requests, about 8% lost both, and the
117
+ * load balancer counted each abandoned request as a client close (ELB 460). A
118
+ * hedge never abandons an answer that is on its way: the first request keeps
119
+ * running to the end of the budget.
113
120
  *
114
- * What is retried: a timeout, a connection error, and the gateway statuses
115
- * that mean the request never reached the application (408, 502, 503, 504 and
116
- * Cloudflare's 52x). Nothing else is: a 4xx or a 500 repeats exactly, and a
117
- * response that arrives is final.
121
+ * Both requests share one deadline, `budgetMs` from the call, so the budget
122
+ * every hook event is checked against (tests/HookEventBudgets.test.ts) and the
123
+ * host's kill limit do not move. A first request that fails fast (a connection
124
+ * error or a gateway status) starts the second at once instead of at the hedge
125
+ * point.
118
126
  *
119
- * Nothing is queued or stored on the client. A call that fails twice is dropped,
120
- * as before. The server keeps an answer for 15 s so the second attempt can have
121
- * it when the first attempt gave up on an answer that was already decided.
127
+ * What counts as an answer: any response other than a gateway status (408, 502,
128
+ * 503, 504, Cloudflare's 52x) and other than the server's "the first request is
129
+ * still working" reply (HOOK_REPLAY_HEADER: pending). A 4xx or a 500 is an
130
+ * answer (null to the caller): repeating it would repeat the failure.
131
+ *
132
+ * The server de-duplicates the two requests by HOOK_REQUEST_ID_HEADER
133
+ * (src/server/hookReplay.ts): the second request is handed the first one's
134
+ * answer, or waits for it, and nothing is counted twice. Nothing is queued or
135
+ * stored on the client; a call with no answer by the deadline is dropped.
122
136
  */
123
- export const HOOK_FIRST_ATTEMPT_SHARE = 0.65;
124
- /** Below this much budget left, a second attempt cannot complete a round trip. */
137
+ export const HOOK_HEDGE_SHARE = 0.65;
138
+ /** Below this much budget left, a second request cannot complete a round trip. */
125
139
  export const HOOK_SECOND_ATTEMPT_MIN_MS = 300;
126
- /** Sent on every attempt so the server can count how many calls needed a second one. */
140
+ /** Sent on every request: 1 for the first, 2 for the hedge. */
127
141
  export const HOOK_ATTEMPT_HEADER = 'x-mnemonik-hook-attempt';
128
142
  /**
129
- * Sent on both attempts with the same value. The server keeps the first
130
- * attempt's answer for a few seconds under this id and hands it to the second
131
- * attempt, so an answer decided after the first attempt gave up is delivered
132
- * rather than lost, and nothing is counted twice (src/server/hookReplay.ts).
143
+ * Sent on both requests with the same value. The server keeps the first
144
+ * request's answer for a few seconds under this id and hands it to the second,
145
+ * so an answer decided by one request is delivered through either, and nothing
146
+ * is counted twice (src/server/hookReplay.ts).
133
147
  */
134
148
  export const HOOK_REQUEST_ID_HEADER = 'x-mnemonik-hook-request-id';
135
149
  /**
136
- * Sent on every attempt: how many milliseconds this attempt may still take.
137
- * The server never waits for a first attempt's answer longer than this less a
138
- * margin for the return trip, so it does not hold a request for a client that
139
- * has already given up.
150
+ * Sent on every request: how many milliseconds the caller will still wait. The
151
+ * server fits its own work inside this less the return trip, so it never
152
+ * decides an answer the client will not be there to receive.
140
153
  */
141
154
  export const HOOK_BUDGET_HEADER = 'x-mnemonik-hook-budget-ms';
142
155
  /**
@@ -149,10 +162,61 @@ export const HOOK_BUDGET_HEADER = 'x-mnemonik-hook-budget-ms';
149
162
  export const HOOK_VERSION_HEADER = 'x-mnemonik-hook-version';
150
163
  /** `init` with the hook-version header added; the caller's headers are kept. */
151
164
  export function withHookVersion(init, runtime, version) {
152
- const headers = new Headers(init.headers);
165
+ const raw = init.headers;
166
+ if (raw && typeof raw === 'object' && !(raw instanceof Headers) && !Array.isArray(raw)) {
167
+ // A plain record is copied with its property descriptors, not its values:
168
+ // the hedged hook client's budget header is a getter read when the
169
+ // request is sent, after the credential is read (hedgedHookRequest).
170
+ const headers = Object.defineProperties({}, Object.getOwnPropertyDescriptors(raw));
171
+ for (const name of Object.keys(headers)) {
172
+ if (name.toLowerCase() === HOOK_VERSION_HEADER)
173
+ delete headers[name];
174
+ }
175
+ headers[HOOK_VERSION_HEADER] = `${runtime}/${version}`;
176
+ return { ...init, headers };
177
+ }
178
+ const headers = new Headers(raw);
153
179
  headers.set(HOOK_VERSION_HEADER, `${runtime}/${version}`);
154
180
  return { ...init, headers: Object.fromEntries(headers.entries()) };
155
181
  }
182
+ /**
183
+ * Sent on every request by a hedging client (hedgedHookRequest). Its budget
184
+ * header is what the whole call still has; clients v7.149 to v7.151 sent the
185
+ * first attempt's own 1.3 s cut-off instead, so a server that sees no marker
186
+ * assumes the whole-call 2 s budget rather than trusting that header.
187
+ */
188
+ export const HOOK_HEDGED_HEADER = 'x-mnemonik-hook-hedged';
189
+ /**
190
+ * Sent on the second request only: what had become of the first when the second
191
+ * left. `pending; sent=812` (still waiting, its body finished sending 812 ms
192
+ * earlier), `pending; sent=none` (it had not finished sending, so the client
193
+ * itself was slow), `gateway; sent=<ms>` (the edge answered 502/503/504/52x) or
194
+ * `transport; sent=<ms>` (the connection failed). The server uses it to count
195
+ * requests the network lost on the way in, which is what the edge alarm reads
196
+ * (src/server/hookReplay.ts, hookEdgeMetrics.ts).
197
+ */
198
+ export const HOOK_FIRST_ATTEMPT_HEADER = 'x-mnemonik-hook-first-attempt';
199
+ /**
200
+ * Set by the server on a reply that is not an answer: the request found the
201
+ * other request of the same call still working on it and could not wait any
202
+ * longer. The client keeps waiting for the other request.
203
+ */
204
+ export const HOOK_REPLAY_HEADER = 'x-mnemonik-hook-replay';
205
+ export const HOOK_REPLAY_PENDING = 'pending';
206
+ export function formatHookFirstAttempt(first) {
207
+ return `${first.state}; sent=${first.sentAgoMs === null ? 'none' : Math.max(0, Math.round(first.sentAgoMs))}`;
208
+ }
209
+ export function parseHookFirstAttempt(value) {
210
+ if (typeof value !== 'string')
211
+ return null;
212
+ const match = /^(pending|gateway|transport); sent=(none|\d{1,6})$/.exec(value.trim());
213
+ if (!match)
214
+ return null;
215
+ return {
216
+ state: match[1],
217
+ sentAgoMs: match[2] === 'none' ? null : Number(match[2]),
218
+ };
219
+ }
156
220
  /** Statuses that mean the request did not reach, or was not served by, the application. */
157
221
  export function isRetryableHookStatus(status) {
158
222
  return (status === 408 ||
@@ -174,36 +238,158 @@ export function isTransientHookFetchError(error) {
174
238
  (error.message === 'fetch failed' || error.message === 'terminated'));
175
239
  }
176
240
  /**
177
- * Run `attempt` and, when it ends in a transient failure, run it once more
178
- * inside the rest of `budgetMs`. Returns the value of the attempt that
179
- * finished, or null when neither did. `attempt` returns `{ done: false }` for
180
- * a retryable response and throws for a transport failure; anything else it
181
- * returns is final.
241
+ * When the first request finished sending its body, read from Node's fetch
242
+ * (undici) diagnostics channels. Matched by the request id header, so other
243
+ * requests the process makes at the same time are ignored. Reports null when
244
+ * the channels are unavailable or the body never finished sending; nothing
245
+ * depends on it except the HOOK_FIRST_ATTEMPT_HEADER the server counts.
182
246
  */
183
- export async function withSecondAttempt(budgetMs, attempt, clock = Date.now) {
184
- const startedAt = clock();
185
- const requestId = globalThis.crypto.randomUUID();
186
- const run = async (attemptNumber, timeoutMs) => {
187
- const { signal, cleanup } = withHookTimeout(timeoutMs);
188
- try {
189
- return await attempt(signal, attemptNumber, requestId, timeoutMs);
190
- }
191
- catch (error) {
192
- if (!isTransientHookFetchError(error))
193
- throw error;
194
- return { done: false };
195
- }
196
- finally {
197
- cleanup();
247
+ function watchFirstRequestSent(requestId, clock) {
248
+ let sentAt = null;
249
+ let request = null;
250
+ const onCreate = (message) => {
251
+ const candidate = message?.request;
252
+ if (request || !candidate)
253
+ return;
254
+ if (String(candidate.headers ?? '').includes(requestId))
255
+ request = candidate;
256
+ };
257
+ const onBodySent = (message) => {
258
+ if (sentAt === null && request && message?.request === request) {
259
+ sentAt = clock();
198
260
  }
199
261
  };
200
- const first = await run(1, Math.floor(budgetMs * HOOK_FIRST_ATTEMPT_SHARE));
201
- if (first.done)
202
- return first.value;
203
- const remainingMs = budgetMs - (clock() - startedAt);
204
- if (remainingMs < HOOK_SECOND_ATTEMPT_MIN_MS)
205
- return null;
206
- const second = await run(2, Math.floor(remainingMs));
207
- return second.done ? second.value : null;
262
+ try {
263
+ diagnosticsChannel.subscribe('undici:request:create', onCreate);
264
+ diagnosticsChannel.subscribe('undici:request:bodySent', onBodySent);
265
+ }
266
+ catch {
267
+ return { sentAt: () => null, stop: () => undefined };
268
+ }
269
+ return {
270
+ sentAt: () => sentAt,
271
+ stop: () => {
272
+ try {
273
+ diagnosticsChannel.unsubscribe('undici:request:create', onCreate);
274
+ diagnosticsChannel.unsubscribe('undici:request:bodySent', onBodySent);
275
+ }
276
+ catch {
277
+ // Nothing to undo.
278
+ }
279
+ },
280
+ };
281
+ }
282
+ /**
283
+ * Send one hook call as up to two hedged requests inside `budgetMs` (see
284
+ * HOOK_HEDGE_SHARE). `send` performs one request with the headers and signal it
285
+ * is given; `parse` reads an answer. Returns the first answer, null when no
286
+ * request answered in time or the answer was an error status, and rejects only
287
+ * when `send` or `parse` fails in a way that is not a transport failure.
288
+ */
289
+ export function hedgedHookRequest(budgetMs, send, parse, clock = Date.now) {
290
+ const startedAt = clock();
291
+ const deadline = startedAt + budgetMs;
292
+ const requestId = globalThis.crypto.randomUUID();
293
+ const sent = watchFirstRequestSent(requestId, clock);
294
+ const controllers = [];
295
+ return new Promise((resolve, reject) => {
296
+ let settled = false;
297
+ let running = 0;
298
+ let secondStarted = false;
299
+ let firstFailure = null;
300
+ let hedgeTimer;
301
+ const finish = (value, error, winner) => {
302
+ if (settled)
303
+ return;
304
+ settled = true;
305
+ clearTimeout(deadlineTimer);
306
+ clearTimeout(hedgeTimer);
307
+ sent.stop();
308
+ // Cancel whatever is still in flight; the request that answered is done.
309
+ for (const controller of controllers)
310
+ if (controller !== winner)
311
+ controller.abort();
312
+ if (error !== undefined)
313
+ reject(error);
314
+ else
315
+ resolve(value);
316
+ };
317
+ const deadlineTimer = setTimeout(() => finish(null), budgetMs);
318
+ const startSecond = () => {
319
+ if (settled || secondStarted)
320
+ return secondStarted;
321
+ if (deadline - clock() < HOOK_SECOND_ATTEMPT_MIN_MS)
322
+ return false;
323
+ secondStarted = true;
324
+ clearTimeout(hedgeTimer);
325
+ launch(2);
326
+ return true;
327
+ };
328
+ const launch = (attemptNumber) => {
329
+ const controller = new AbortController();
330
+ controllers.push(controller);
331
+ const now = clock();
332
+ const headers = {
333
+ [HOOK_ATTEMPT_HEADER]: String(attemptNumber),
334
+ [HOOK_REQUEST_ID_HEADER]: requestId,
335
+ [HOOK_HEDGED_HEADER]: '1',
336
+ };
337
+ // Read when the request is actually built (after the credential read or
338
+ // rotation and the conversation lock), not when the attempt starts, so
339
+ // the server's deadline does not include time already spent here.
340
+ Object.defineProperty(headers, HOOK_BUDGET_HEADER, {
341
+ enumerable: true,
342
+ get: () => String(Math.max(0, Math.floor(deadline - clock()))),
343
+ });
344
+ if (attemptNumber === 2) {
345
+ const sentAt = sent.sentAt();
346
+ headers[HOOK_FIRST_ATTEMPT_HEADER] = formatHookFirstAttempt({
347
+ state: firstFailure ?? 'pending',
348
+ sentAgoMs: sentAt === null ? null : now - sentAt,
349
+ });
350
+ }
351
+ running += 1;
352
+ void (async () => {
353
+ let outcome;
354
+ try {
355
+ const response = await send(headers, controller.signal);
356
+ if (isRetryableHookStatus(response.status))
357
+ outcome = { final: false, kind: 'gateway' };
358
+ else if (response.headers.get(HOOK_REPLAY_HEADER) === HOOK_REPLAY_PENDING)
359
+ outcome = { final: false, kind: 'pending' };
360
+ else if (!response.ok)
361
+ outcome = { final: true, value: null };
362
+ else
363
+ outcome = { final: true, value: await parse(response) };
364
+ }
365
+ catch (error) {
366
+ if (!settled && !isTransientHookFetchError(error)) {
367
+ running -= 1;
368
+ finish(null, error);
369
+ return;
370
+ }
371
+ outcome = { final: false, kind: 'transport' };
372
+ }
373
+ running -= 1;
374
+ if (settled)
375
+ return;
376
+ if (outcome.final) {
377
+ finish(outcome.value, undefined, controller);
378
+ return;
379
+ }
380
+ // Not an answer. The first request's failure starts the second at once;
381
+ // with no request left running there is no answer to wait for.
382
+ if (attemptNumber === 1) {
383
+ if (outcome.kind !== 'pending')
384
+ firstFailure = outcome.kind;
385
+ startSecond();
386
+ }
387
+ if (running === 0)
388
+ finish(null);
389
+ })();
390
+ };
391
+ launch(1);
392
+ hedgeTimer = setTimeout(startSecond, Math.floor(budgetMs * HOOK_HEDGE_SHARE));
393
+ });
208
394
  }
209
395
  //# sourceMappingURL=hookTimeouts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookTimeouts.js","sourceRoot":"","sources":["../src/hookTimeouts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hookTimeouts.js","sourceRoot":"","sources":["../src/hookTimeouts.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ export type VueTemplateNode = TemplateRoot | TemplateRoot['children'][number];
7
7
  type ParsedVueSource = {
8
8
  descriptor: SFCDescriptor;
9
9
  nodeTypes: typeof import('@vue/compiler-core').NodeTypes;
10
+ /** Set on the sanitation path only; the template walk throws past it. */
11
+ templateNodeLimit?: number;
10
12
  };
11
13
  export declare function parseVueSource(source: string, forSanitation?: boolean): Promise<ParsedVueSource | {
12
14
  reason: string;
@@ -1 +1 @@
1
- {"version":3,"file":"vueSource.d.ts","sourceRoot":"","sources":["../src/vueSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,sDAAsD,CAAC;AACvF,KAAK,YAAY,GAAG,WAAW,CAAC,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/E,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,sFAAsF;AACtF,KAAK,eAAe,GAAG;IACrB,UAAU,EAAE,aAAa,CAAC;IAC1B,SAAS,EAAE,cAAc,oBAAoB,EAAE,SAAS,CAAC;CAC1D,CAAC;AACF,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,aAAa,UAAQ,GACpB,OAAO,CAAC,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAiC/C;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GACtD,IAAI,CAqBN"}
1
+ {"version":3,"file":"vueSource.d.ts","sourceRoot":"","sources":["../src/vueSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAIvD,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,sDAAsD,CAAC;AACvF,KAAK,YAAY,GAAG,WAAW,CAAC,WAAW,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/E,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9E,sFAAsF;AACtF,KAAK,eAAe,GAAG;IACrB,UAAU,EAAE,aAAa,CAAC;IAC1B,SAAS,EAAE,cAAc,oBAAoB,EAAE,SAAS,CAAC;IACzD,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAUF,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,aAAa,UAAQ,GACpB,OAAO,CAAC,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAuC/C;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GACtD,IAAI,CAuBN"}
package/dist/vueSource.js CHANGED
@@ -1,11 +1,21 @@
1
1
  import { MAX_AST_PARSE_BYTES } from './ast/astChunker.js';
2
+ import { MAX_SCANNED_FILE_BYTES } from './codeScanner.js';
2
3
  /** A fallback scrub may repair syntax; it must never become graph evidence. */
3
4
  export const VUE_FIDELITY_MARKER = '<!-- mnemonik:vue-source-fidelity-unavailable -->';
5
+ /**
6
+ * Sanitation runs on the API server's event loop (scan push, file push, documents), and
7
+ * its edit loop costs the file's length per edit, so it keeps the 2 MiB and 200,000-node
8
+ * bounds until it moves off that loop. Connected-code reads run in the parse pool and
9
+ * take any file up to the product's 10 MB ceiling.
10
+ */
11
+ const SANITATION_MAX_BYTES = MAX_AST_PARSE_BYTES;
12
+ const SANITATION_TEMPLATE_NODE_LIMIT = 200_000;
4
13
  export async function parseVueSource(source, forSanitation = false) {
5
14
  // Sanitation still inspects marked bytes; graph extraction must continue to reject them.
6
15
  if (!forSanitation && source.includes(VUE_FIDELITY_MARKER))
7
16
  return { reason: 'vue_source_fidelity_unavailable' };
8
- if (Buffer.byteLength(source, 'utf8') > MAX_AST_PARSE_BYTES)
17
+ if (Buffer.byteLength(source, 'utf8') >
18
+ (forSanitation ? SANITATION_MAX_BYTES : MAX_SCANNED_FILE_BYTES))
9
19
  return { reason: 'file_too_large' };
10
20
  let clearCache;
11
21
  try {
@@ -27,7 +37,9 @@ export async function parseVueSource(source, forSanitation = false) {
27
37
  (descriptor.template?.lang && descriptor.template.lang !== 'html') ||
28
38
  descriptor.customBlocks.length)
29
39
  return { reason: 'vue_preprocessor_or_custom_block_unsupported' };
30
- return { descriptor, nodeTypes };
40
+ return forSanitation
41
+ ? { descriptor, nodeTypes, templateNodeLimit: SANITATION_TEMPLATE_NODE_LIMIT }
42
+ : { descriptor, nodeTypes };
31
43
  }
32
44
  catch {
33
45
  return { reason: 'vue_parse_failed' };
@@ -43,12 +55,14 @@ export function walkVueTemplate(parsed, visit) {
43
55
  const pending = descriptor.template?.ast
44
56
  ? [{ node: descriptor.template.ast, scoped: false }]
45
57
  : [];
58
+ // Iterative and linear in the template's nodes; only sanitation is bounded by count.
59
+ const limit = parsed.templateNodeLimit ?? Infinity;
46
60
  let count = 0;
47
61
  while (pending.length) {
48
62
  const item = pending.pop();
49
63
  if (!item)
50
64
  break;
51
- if (++count > 200_000)
65
+ if (++count > limit)
52
66
  throw new Error('vue_template_work_limit');
53
67
  const { node } = item;
54
68
  const scoped = item.scoped ||
@@ -1 +1 @@
1
- {"version":3,"file":"vueSource.js","sourceRoot":"","sources":["../src/vueSource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vueSource.js","sourceRoot":"","sources":["../src/vueSource.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemonik/shared",
3
- "version": "7.152.1",
3
+ "version": "7.154.0",
4
4
  "description": "Shared constants and utilities for Mnemonik packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  }
46
46
  },
47
47
  "scripts": {
48
- "test": "tsx --test --test-concurrency=2 tests/repositoryFingerprint.test.ts tests/projectIdentity.test.ts tests/nearestProjectIdentity.test.ts tests/readiness.test.ts tests/scannerDisclosure.test.ts tests/hookRuntime.test.ts tests/grantHost.test.ts tests/hookTrace.test.ts",
48
+ "test": "tsx --test --test-concurrency=2 tests/repositoryFingerprint.test.ts tests/projectIdentity.test.ts tests/nearestProjectIdentity.test.ts tests/readiness.test.ts tests/scannerDisclosure.test.ts tests/hookRuntime.test.ts tests/grantHost.test.ts tests/hookTrace.test.ts tests/gateOutbox.test.ts",
49
49
  "build": "node ../../node_modules/@typescript/native/bin/tsc",
50
50
  "typecheck": "node ../../node_modules/@typescript/native/bin/tsc --noEmit -p tsconfig.test.json",
51
51
  "prepublishOnly": "npm run build"