@ultimat3/query 30.3.0 → 30.4.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.
Files changed (2) hide show
  1. package/package.json +8 -8
  2. package/src/exercise.ts +29 -25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/query",
3
- "version": "30.3.0",
3
+ "version": "30.4.0",
4
4
  "description": "The query primitive: a policy-checked read, optionally live, with cursor pagination and an incremental matcher",
5
5
  "keywords": [
6
6
  "ultimate",
@@ -47,12 +47,12 @@
47
47
  "test": "bun test"
48
48
  },
49
49
  "dependencies": {
50
- "@ultimat3/cache": "30.3.0",
51
- "@ultimat3/core": "30.3.0",
52
- "@ultimat3/db": "30.3.0",
53
- "@ultimat3/entity": "30.3.0",
54
- "@ultimat3/http": "30.3.0",
55
- "@ultimat3/policy": "30.3.0",
56
- "@ultimat3/schema": "30.3.0"
50
+ "@ultimat3/cache": "30.4.0",
51
+ "@ultimat3/core": "30.4.0",
52
+ "@ultimat3/db": "30.4.0",
53
+ "@ultimat3/entity": "30.4.0",
54
+ "@ultimat3/http": "30.4.0",
55
+ "@ultimat3/policy": "30.4.0",
56
+ "@ultimat3/schema": "30.4.0"
57
57
  }
58
58
  }
package/src/exercise.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  tryUseContext,
16
16
  UltimateError,
17
17
  } from '@ultimat3/core';
18
- import { statusFor } from '@ultimat3/http';
18
+ import { statusFor, withScratchRateLimitStore } from '@ultimat3/http';
19
19
  import type { StandardSchemaV1 } from '@ultimat3/schema';
20
20
  import { validateAsync } from '@ultimat3/schema';
21
21
  import { arbitrary } from '@ultimat3/schema/sample';
@@ -62,8 +62,9 @@ const accepts = async (schema: StandardSchemaV1, input: unknown): Promise<boolea
62
62
  * policy, the declared limit, the parse — is the front half every surface shares.
63
63
  *
64
64
  * A test-time call: refused in `staging`/`production` (`X_CONTRACT_EXERCISE_ENVIRONMENT`). Nothing
65
- * is rolled back, because a read writes nothing; what it touches anyway (a rate-limit counter, an
66
- * audit record, an outbound fetch — sealed under the test preload) is kept.
65
+ * is rolled back, because a read writes nothing; what it touches anyway (an audit record, an
66
+ * outbound fetch — sealed under the test preload) is kept. Rate-limit counters are spent in a
67
+ * scratch store of the exercise's own, so the installed one is left as it was.
67
68
  */
68
69
  export async function exerciseQuery(
69
70
  target: AnyQuery,
@@ -72,28 +73,31 @@ export async function exerciseQuery(
72
73
  ): Promise<QueryExerciseReport> {
73
74
  const name = queryName(target);
74
75
  const base = ctx ?? tryUseContext() ?? ctxOf({});
75
- const verdict = await runExercise({
76
- name,
77
- runs: options.runs,
78
- stoppedLabel: 'stopped before sql()',
79
- draw: (seed, run) => arbitrary(target.input, { seed, run }),
80
- bind: bindDrawn(options.input),
81
- accepts: (input) => accepts(target.input, input),
82
- attempt: async (input) => {
83
- try {
84
- const source = await sourceFor(target, input, {
85
- ctx: base,
86
- actor: options.actor,
87
- surface: 'http',
88
- });
89
- await source.execute();
90
- return { ok: true, reached: true };
91
- } catch (error) {
92
- return { ok: false, reached: !beforeSql(error), error };
93
- }
94
- },
95
- statusOf: statusFor,
96
- });
76
+ // Counted in a scratch store: a spent bucket would make the file's next real call a 429.
77
+ const verdict = await withScratchRateLimitStore(() =>
78
+ runExercise({
79
+ name,
80
+ runs: options.runs,
81
+ stoppedLabel: 'stopped before sql()',
82
+ draw: (seed, run) => arbitrary(target.input, { seed, run }),
83
+ bind: bindDrawn(options.input),
84
+ accepts: (input) => accepts(target.input, input),
85
+ attempt: async (input) => {
86
+ try {
87
+ const source = await sourceFor(target, input, {
88
+ ctx: base,
89
+ actor: options.actor,
90
+ surface: 'http',
91
+ });
92
+ await source.execute();
93
+ return { ok: true, reached: true };
94
+ } catch (error) {
95
+ return { ok: false, reached: !beforeSql(error), error };
96
+ }
97
+ },
98
+ statusOf: statusFor,
99
+ }),
100
+ );
97
101
  switch (verdict.kind) {
98
102
  case 'pass':
99
103
  return verdict.report;