callman-core 1.7.1 → 1.8.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.
Files changed (114) hide show
  1. package/dist/scenario-runner/runScenario.d.ts.map +1 -1
  2. package/dist/scenario-runner/runScenario.js +8 -0
  3. package/dist/scenario-runner/runScenario.js.map +1 -1
  4. package/dist/scenario-runner/templateResolver.d.ts.map +1 -1
  5. package/dist/scenario-runner/templateResolver.js +18 -0
  6. package/dist/scenario-runner/templateResolver.js.map +1 -1
  7. package/dist/scenario-runner/types.d.ts +1 -1
  8. package/dist/scenario-runner/types.d.ts.map +1 -1
  9. package/dist/script/executor.d.ts.map +1 -1
  10. package/dist/script/executor.js +75 -9
  11. package/dist/script/executor.js.map +1 -1
  12. package/dist/script/features/collectionVariables.d.ts +16 -0
  13. package/dist/script/features/collectionVariables.d.ts.map +1 -0
  14. package/dist/script/features/collectionVariables.js +83 -0
  15. package/dist/script/features/collectionVariables.js.map +1 -0
  16. package/dist/script/features/cryptojs.d.ts +8 -12
  17. package/dist/script/features/cryptojs.d.ts.map +1 -1
  18. package/dist/script/features/cryptojs.js +15 -99
  19. package/dist/script/features/cryptojs.js.map +1 -1
  20. package/dist/script/features/environment.d.ts +8 -1
  21. package/dist/script/features/environment.d.ts.map +1 -1
  22. package/dist/script/features/environment.js +25 -1
  23. package/dist/script/features/environment.js.map +1 -1
  24. package/dist/script/features/execution.d.ts +17 -0
  25. package/dist/script/features/execution.d.ts.map +1 -0
  26. package/dist/script/features/execution.js +60 -0
  27. package/dist/script/features/execution.js.map +1 -0
  28. package/dist/script/features/headerList.d.ts +44 -0
  29. package/dist/script/features/headerList.d.ts.map +1 -0
  30. package/dist/script/features/headerList.js +284 -0
  31. package/dist/script/features/headerList.js.map +1 -0
  32. package/dist/script/features/info.d.ts +10 -0
  33. package/dist/script/features/info.d.ts.map +1 -0
  34. package/dist/script/features/info.js +32 -0
  35. package/dist/script/features/info.js.map +1 -0
  36. package/dist/script/features/request.d.ts +3 -2
  37. package/dist/script/features/request.d.ts.map +1 -1
  38. package/dist/script/features/request.js +38 -29
  39. package/dist/script/features/request.js.map +1 -1
  40. package/dist/script/features/response.d.ts +7 -5
  41. package/dist/script/features/response.d.ts.map +1 -1
  42. package/dist/script/features/response.js +16 -8
  43. package/dist/script/features/response.js.map +1 -1
  44. package/dist/script/features/responseAssertions.d.ts +50 -0
  45. package/dist/script/features/responseAssertions.d.ts.map +1 -0
  46. package/dist/script/features/responseAssertions.js +293 -0
  47. package/dist/script/features/responseAssertions.js.map +1 -0
  48. package/dist/script/features/timers.d.ts +17 -0
  49. package/dist/script/features/timers.d.ts.map +1 -0
  50. package/dist/script/features/timers.js +152 -0
  51. package/dist/script/features/timers.js.map +1 -0
  52. package/dist/script/features/variables.d.ts +8 -1
  53. package/dist/script/features/variables.d.ts.map +1 -1
  54. package/dist/script/features/variables.js +57 -11
  55. package/dist/script/features/variables.js.map +1 -1
  56. package/dist/script/scope.d.ts +10 -0
  57. package/dist/script/scope.d.ts.map +1 -1
  58. package/dist/script/scope.js +13 -4
  59. package/dist/script/scope.js.map +1 -1
  60. package/dist/script/types.d.ts +51 -1
  61. package/dist/script/types.d.ts.map +1 -1
  62. package/dist/templating/generator-metadata.d.ts +1 -0
  63. package/dist/templating/generator-metadata.d.ts.map +1 -1
  64. package/dist/templating/generator-metadata.js +76 -0
  65. package/dist/templating/generator-metadata.js.map +1 -1
  66. package/dist/templating/postman-generators.d.ts +12 -0
  67. package/dist/templating/postman-generators.d.ts.map +1 -0
  68. package/dist/templating/postman-generators.js +577 -0
  69. package/dist/templating/postman-generators.js.map +1 -0
  70. package/dist/templating/template-engine.d.ts.map +1 -1
  71. package/dist/templating/template-engine.js +16 -0
  72. package/dist/templating/template-engine.js.map +1 -1
  73. package/dist/variables/resolver.d.ts.map +1 -1
  74. package/dist/variables/resolver.js +15 -0
  75. package/dist/variables/resolver.js.map +1 -1
  76. package/dist-cjs/scenario-runner/runScenario.js +8 -0
  77. package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
  78. package/dist-cjs/scenario-runner/templateResolver.js +18 -0
  79. package/dist-cjs/scenario-runner/templateResolver.js.map +1 -1
  80. package/dist-cjs/script/executor.js +78 -9
  81. package/dist-cjs/script/executor.js.map +1 -1
  82. package/dist-cjs/script/features/collectionVariables.js +87 -0
  83. package/dist-cjs/script/features/collectionVariables.js.map +1 -0
  84. package/dist-cjs/script/features/cryptojs.js +18 -99
  85. package/dist-cjs/script/features/cryptojs.js.map +1 -1
  86. package/dist-cjs/script/features/environment.js +25 -1
  87. package/dist-cjs/script/features/environment.js.map +1 -1
  88. package/dist-cjs/script/features/execution.js +64 -0
  89. package/dist-cjs/script/features/execution.js.map +1 -0
  90. package/dist-cjs/script/features/headerList.js +289 -0
  91. package/dist-cjs/script/features/headerList.js.map +1 -0
  92. package/dist-cjs/script/features/info.js +36 -0
  93. package/dist-cjs/script/features/info.js.map +1 -0
  94. package/dist-cjs/script/features/request.js +38 -29
  95. package/dist-cjs/script/features/request.js.map +1 -1
  96. package/dist-cjs/script/features/response.js +16 -8
  97. package/dist-cjs/script/features/response.js.map +1 -1
  98. package/dist-cjs/script/features/responseAssertions.js +297 -0
  99. package/dist-cjs/script/features/responseAssertions.js.map +1 -0
  100. package/dist-cjs/script/features/timers.js +156 -0
  101. package/dist-cjs/script/features/timers.js.map +1 -0
  102. package/dist-cjs/script/features/variables.js +57 -11
  103. package/dist-cjs/script/features/variables.js.map +1 -1
  104. package/dist-cjs/script/scope.js +13 -4
  105. package/dist-cjs/script/scope.js.map +1 -1
  106. package/dist-cjs/templating/generator-metadata.js +77 -1
  107. package/dist-cjs/templating/generator-metadata.js.map +1 -1
  108. package/dist-cjs/templating/postman-generators.js +581 -0
  109. package/dist-cjs/templating/postman-generators.js.map +1 -0
  110. package/dist-cjs/templating/template-engine.js +16 -0
  111. package/dist-cjs/templating/template-engine.js.map +1 -1
  112. package/dist-cjs/variables/resolver.js +15 -0
  113. package/dist-cjs/variables/resolver.js.map +1 -1
  114. package/package.json +6 -2
@@ -0,0 +1,17 @@
1
+ import type { ScriptExecutionCapability, ScriptExecutionControl } from "../types.js";
2
+ export interface ExecutionLocation extends Array<string> {
3
+ /** The last segment in the location array (the current request). */
4
+ current: string;
5
+ }
6
+ export interface ExecutionApi {
7
+ setNextRequest: (name: string | null | undefined) => void;
8
+ skipRequest: () => void;
9
+ location: ExecutionLocation;
10
+ }
11
+ export interface ExecutionFeature {
12
+ api: ExecutionApi;
13
+ /** Snapshot of any control flags the script set. */
14
+ getControl: () => ScriptExecutionControl;
15
+ }
16
+ export declare const buildExecutionFeature: (capability: ScriptExecutionCapability | undefined) => ExecutionFeature;
17
+ //# sourceMappingURL=execution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../../src/script/features/execution.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,MAAM,CAAC;IACtD,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;IAC1D,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,YAAY,CAAC;IAClB,oDAAoD;IACpD,UAAU,EAAE,MAAM,sBAAsB,CAAC;CAC1C;AAkBD,eAAO,MAAM,qBAAqB,GAChC,YAAY,yBAAyB,GAAG,SAAS,KAChD,gBA2BF,CAAC"}
@@ -0,0 +1,60 @@
1
+ // pm.execution — Postman's collection-runner control surface.
2
+ //
3
+ // pm.execution.setNextRequest(name | null)
4
+ // Tell the runner to jump to a named request after this one (or
5
+ // `null` to stop the branch). Has no effect outside a runner — the
6
+ // host is free to ignore the flag for ad-hoc Send.
7
+ //
8
+ // pm.execution.skipRequest()
9
+ // Only meaningful in a pre-request script. Sets a flag that causes
10
+ // the runner to skip the HTTP call entirely. The Tests script then
11
+ // does NOT run either.
12
+ //
13
+ // pm.execution.location / .location.current
14
+ // A path-like array of segment strings (e.g. ["Smoke",
15
+ // "Authentication", "Login"]) and the last segment as `.current`,
16
+ // so users can pivot behaviour by location.
17
+ //
18
+ // Why this lives separately from `pm.node`:
19
+ // pm.node was a Callman-specific scenario-flow accessor. pm.execution
20
+ // is the Postman-named surface. We expose both — pm.node stays for
21
+ // back-compat, pm.execution is preferred going forward.
22
+ const buildLocation = (segments) => {
23
+ const arr = Array.isArray(segments) ? [...segments] : [];
24
+ const current = arr.length > 0 ? arr[arr.length - 1] : "";
25
+ // Augment the array with a `.current` getter. Using
26
+ // Object.defineProperty keeps it non-enumerable so JSON.stringify
27
+ // still produces a plain array.
28
+ Object.defineProperty(arr, "current", {
29
+ configurable: true,
30
+ enumerable: false,
31
+ get: () => current,
32
+ });
33
+ return arr;
34
+ };
35
+ export const buildExecutionFeature = (capability) => {
36
+ const state = {
37
+ nextRequest: undefined,
38
+ skipRequested: false,
39
+ };
40
+ const location = buildLocation(capability?.location);
41
+ const api = {
42
+ setNextRequest: (name) => {
43
+ if (name === null || name === undefined) {
44
+ state.nextRequest = null;
45
+ return;
46
+ }
47
+ const trimmed = String(name).trim();
48
+ state.nextRequest = trimmed.length > 0 ? trimmed : null;
49
+ },
50
+ skipRequest: () => {
51
+ state.skipRequested = true;
52
+ },
53
+ location,
54
+ };
55
+ return {
56
+ api,
57
+ getControl: () => ({ ...state }),
58
+ };
59
+ };
60
+ //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.js","sourceRoot":"","sources":["../../../src/script/features/execution.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,6CAA6C;AAC7C,oEAAoE;AACpE,uEAAuE;AACvE,uDAAuD;AACvD,EAAE;AACF,+BAA+B;AAC/B,uEAAuE;AACvE,uEAAuE;AACvE,2BAA2B;AAC3B,EAAE;AACF,8CAA8C;AAC9C,2DAA2D;AAC3D,sEAAsE;AACtE,gDAAgD;AAChD,EAAE;AACF,4CAA4C;AAC5C,wEAAwE;AACxE,qEAAqE;AACrE,0DAA0D;AAwB1D,MAAM,aAAa,GAAG,CACpB,QAA8B,EACX,EAAE;IACrB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,oDAAoD;IACpD,kEAAkE;IAClE,gCAAgC;IAChC,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE;QACpC,YAAY,EAAE,IAAI;QAClB,UAAU,EAAE,KAAK;QACjB,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO;KACnB,CAAC,CAAC;IACH,OAAO,GAAwB,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,UAAiD,EAC/B,EAAE;IACpB,MAAM,KAAK,GAA2B;QACpC,WAAW,EAAE,SAAS;QACtB,aAAa,EAAE,KAAK;KACrB,CAAC;IAEF,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAErD,MAAM,GAAG,GAAiB;QACxB,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE;YACvB,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACxC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;gBACzB,OAAO;YACT,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACpC,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,CAAC;QACD,WAAW,EAAE,GAAG,EAAE;YAChB,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,QAAQ;KACT,CAAC;IAEF,OAAO;QACL,GAAG;QACH,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;KACjC,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ export interface HeaderEntry {
2
+ key: string;
3
+ value: string;
4
+ description?: string;
5
+ }
6
+ export interface HeaderListMethods {
7
+ /** Case-insensitive value lookup. Returns the first matching value, or
8
+ * `undefined` if no header with that name exists. */
9
+ get(name: string): string | undefined;
10
+ /** Case-insensitive presence check. */
11
+ has(name: string): boolean;
12
+ /** Entry at numeric index, or undefined if out of range. */
13
+ idx(index: number): HeaderEntry | undefined;
14
+ /** Append an entry (allows duplicate names — same as Postman). */
15
+ add(spec: HeaderEntry | Record<string, unknown>): void;
16
+ /** Replace entries with the same name (case-insensitive), or append if
17
+ * absent. Always leaves at most one entry with that name. */
18
+ upsert(spec: HeaderEntry | Record<string, unknown>): void;
19
+ /** Remove every entry whose name matches (case-insensitive). */
20
+ remove(name: string): void;
21
+ /** Snapshot of all entries as a fresh array. */
22
+ all(): HeaderEntry[];
23
+ /** Postman-compat alias for `all()`. */
24
+ toJSON(): HeaderEntry[];
25
+ /** Iterator over entries (Postman HeaderList is iterable). */
26
+ [Symbol.iterator](): IterableIterator<HeaderEntry>;
27
+ }
28
+ export type HeaderList = HeaderListMethods & Record<string, string>;
29
+ /**
30
+ * Build a Proxy-wrapped HeaderList. Bracket access reads / writes as if the
31
+ * value were a plain `Record<string, string>` (case-sensitive, exact key
32
+ * match). The HeaderList methods (`get`, `has`, `add`, ...) are exposed
33
+ * directly on the wrapper.
34
+ */
35
+ export declare const createHeaderList: (initial?: HeaderEntry[] | Record<string, string>, options?: {
36
+ readOnly?: boolean;
37
+ }) => HeaderList;
38
+ /**
39
+ * Best-effort extraction of the underlying entry list, used by the
40
+ * request-state serialiser. Falls back to `Object.entries` for back-compat
41
+ * with any external callers that still pass a plain record.
42
+ */
43
+ export declare const headerListEntries: (value: HeaderList | Record<string, string>) => HeaderEntry[];
44
+ //# sourceMappingURL=headerList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headerList.d.ts","sourceRoot":"","sources":["../../../src/script/features/headerList.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC;yDACqD;IACrD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,uCAAuC;IACvC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,4DAA4D;IAC5D,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IAC5C,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACvD;iEAC6D;IAC7D,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1D,gEAAgE;IAChE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gDAAgD;IAChD,GAAG,IAAI,WAAW,EAAE,CAAC;IACrB,wCAAwC;IACxC,MAAM,IAAI,WAAW,EAAE,CAAC;IACxB,8DAA8D;IAC9D,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACpD;AAED,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AA8KpE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,UAAS,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACpD,UAAS;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,KACnC,UAwFF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACzC,WAAW,EAab,CAAC"}
@@ -0,0 +1,284 @@
1
+ // HeaderList — Postman-compatible header / query parameter wrapper.
2
+ //
3
+ // Background. Older callman-core releases exposed `pm.request.headers` and
4
+ // `pm.response.headers` as plain `Record<string, string>` objects. Many real
5
+ // Postman scripts assume a richer `HeaderList` shape:
6
+ //
7
+ // pm.request.headers.add({ key, value, description? })
8
+ // pm.request.headers.upsert({ key, value, description? })
9
+ // pm.request.headers.remove(name)
10
+ // pm.request.headers.has(name) // case-insensitive
11
+ // pm.request.headers.get(name) // case-insensitive
12
+ // pm.request.headers.idx(i) // entry at index
13
+ // pm.request.headers.all() // [{ key, value, description }]
14
+ // for (const h of pm.request.headers) ... // iterable
15
+ //
16
+ // The class below provides both shapes through a Proxy: existing scripts that
17
+ // rely on bracket access (`headers["X-Custom"]`, `Object.keys(headers)`,
18
+ // `Object.entries(headers)`) keep working bit-for-bit, while new scripts can
19
+ // call the Postman methods on the same object.
20
+ //
21
+ // Mutability:
22
+ // - Request headers are writable. `setHeader` / `add` / `upsert` mutate the
23
+ // internal list and the changes are observed by `toRequestState()` when
24
+ // the script completes.
25
+ // - Response headers are constructed read-only — `add` / `upsert` / `remove`
26
+ // throw to preserve the immutability of an already-received response.
27
+ //
28
+ // Case sensitivity rules:
29
+ // - Lookups via `.get()`, `.has()`, `.remove()`, `.upsert()` are
30
+ // case-INSENSITIVE. This matches Postman and is the HTTP semantic.
31
+ // - Bracket access (`headers["X-Custom"]`) is case-SENSITIVE for
32
+ // back-compat with older Callman scripts that depended on exact-case
33
+ // keys derived from the previous Record<string, string> shape.
34
+ const METHOD_KEYS = new Set([
35
+ "get",
36
+ "has",
37
+ "idx",
38
+ "add",
39
+ "upsert",
40
+ "remove",
41
+ "all",
42
+ "toJSON",
43
+ "isReadOnly",
44
+ ]);
45
+ const normaliseSpec = (spec) => {
46
+ if (spec === null || typeof spec !== "object") {
47
+ throw new TypeError("HeaderList: expected { key, value, description? } object");
48
+ }
49
+ const key = String(spec.key ?? "").trim();
50
+ if (!key) {
51
+ throw new TypeError("HeaderList: header key must be a non-empty string");
52
+ }
53
+ const value = spec.value;
54
+ const description = spec.description;
55
+ return {
56
+ key,
57
+ value: value === undefined || value === null ? "" : String(value),
58
+ description: typeof description === "string" ? description : undefined,
59
+ };
60
+ };
61
+ const stringifyValue = (value) => value === undefined || value === null ? "" : String(value);
62
+ class HeaderListImpl {
63
+ entries = [];
64
+ readOnly;
65
+ constructor(initial, readOnly = false) {
66
+ for (const entry of initial) {
67
+ this.entries.push({ ...entry });
68
+ }
69
+ this.readOnly = readOnly;
70
+ }
71
+ guardWritable() {
72
+ if (this.readOnly) {
73
+ throw new Error("Cannot mutate response headers — they are read-only after the response is captured.");
74
+ }
75
+ }
76
+ get(name) {
77
+ const target = String(name ?? "")
78
+ .trim()
79
+ .toLowerCase();
80
+ if (!target)
81
+ return undefined;
82
+ for (const entry of this.entries) {
83
+ if (entry.key.toLowerCase() === target) {
84
+ return entry.value;
85
+ }
86
+ }
87
+ return undefined;
88
+ }
89
+ has(name) {
90
+ return this.get(name) !== undefined;
91
+ }
92
+ idx(index) {
93
+ if (!Number.isInteger(index) || index < 0 || index >= this.entries.length) {
94
+ return undefined;
95
+ }
96
+ return { ...this.entries[index] };
97
+ }
98
+ add(spec) {
99
+ this.guardWritable();
100
+ this.entries.push(normaliseSpec(spec));
101
+ }
102
+ upsert(spec) {
103
+ this.guardWritable();
104
+ const next = normaliseSpec(spec);
105
+ const target = next.key.toLowerCase();
106
+ const replaceIndex = this.entries.findIndex((entry) => entry.key.toLowerCase() === target);
107
+ if (replaceIndex >= 0) {
108
+ this.entries[replaceIndex] = next;
109
+ // Drop any further duplicates so upsert leaves a single entry.
110
+ for (let i = this.entries.length - 1; i > replaceIndex; i -= 1) {
111
+ if (this.entries[i].key.toLowerCase() === target) {
112
+ this.entries.splice(i, 1);
113
+ }
114
+ }
115
+ return;
116
+ }
117
+ this.entries.push(next);
118
+ }
119
+ remove(name) {
120
+ this.guardWritable();
121
+ const target = String(name ?? "")
122
+ .trim()
123
+ .toLowerCase();
124
+ if (!target)
125
+ return;
126
+ for (let i = this.entries.length - 1; i >= 0; i -= 1) {
127
+ if (this.entries[i].key.toLowerCase() === target) {
128
+ this.entries.splice(i, 1);
129
+ }
130
+ }
131
+ }
132
+ all() {
133
+ return this.entries.map((entry) => ({ ...entry }));
134
+ }
135
+ toJSON() {
136
+ return this.all();
137
+ }
138
+ *[Symbol.iterator]() {
139
+ for (const entry of this.entries) {
140
+ yield { ...entry };
141
+ }
142
+ }
143
+ // ── Internal hooks used by the Proxy wrapper ──────────────────────────
144
+ __rawEntries() {
145
+ return this.entries;
146
+ }
147
+ __setRaw(key, value) {
148
+ this.guardWritable();
149
+ const normalisedKey = String(key ?? "").trim();
150
+ if (!normalisedKey)
151
+ return;
152
+ // Bracket-assignment is treated as upsert with EXACT case so that
153
+ // Object.keys(headers) and headers[k] readbacks see the user's chosen
154
+ // case — matches the legacy Record<string, string> behaviour.
155
+ const stringValue = stringifyValue(value);
156
+ const existing = this.entries.findIndex((entry) => entry.key === normalisedKey);
157
+ if (existing >= 0) {
158
+ this.entries[existing].value = stringValue;
159
+ return;
160
+ }
161
+ this.entries.push({ key: normalisedKey, value: stringValue });
162
+ }
163
+ __deleteRaw(key) {
164
+ this.guardWritable();
165
+ const normalisedKey = String(key ?? "").trim();
166
+ if (!normalisedKey)
167
+ return false;
168
+ const idx = this.entries.findIndex((entry) => entry.key === normalisedKey);
169
+ if (idx >= 0) {
170
+ this.entries.splice(idx, 1);
171
+ return true;
172
+ }
173
+ return false;
174
+ }
175
+ }
176
+ /**
177
+ * Build a Proxy-wrapped HeaderList. Bracket access reads / writes as if the
178
+ * value were a plain `Record<string, string>` (case-sensitive, exact key
179
+ * match). The HeaderList methods (`get`, `has`, `add`, ...) are exposed
180
+ * directly on the wrapper.
181
+ */
182
+ export const createHeaderList = (initial = [], options = {}) => {
183
+ const entries = Array.isArray(initial)
184
+ ? initial.map((entry) => ({ ...entry }))
185
+ : Object.entries(initial).map(([key, value]) => ({
186
+ key,
187
+ value: stringifyValue(value),
188
+ }));
189
+ const impl = new HeaderListImpl(entries, options.readOnly ?? false);
190
+ return new Proxy(impl, {
191
+ get(target, prop, receiver) {
192
+ // Hand back methods / iterator unchanged.
193
+ if (typeof prop === "symbol") {
194
+ return Reflect.get(target, prop, receiver);
195
+ }
196
+ if (METHOD_KEYS.has(prop) || prop in target) {
197
+ const value = Reflect.get(target, prop, receiver);
198
+ if (typeof value === "function") {
199
+ return value.bind(target);
200
+ }
201
+ return value;
202
+ }
203
+ // String prop → look up as a header name (case-sensitive bracket
204
+ // access for back-compat with the previous Record shape).
205
+ const raw = target.__rawEntries();
206
+ for (const entry of raw) {
207
+ if (entry.key === prop) {
208
+ return entry.value;
209
+ }
210
+ }
211
+ return undefined;
212
+ },
213
+ set(target, prop, value, receiver) {
214
+ if (typeof prop === "symbol" || METHOD_KEYS.has(prop)) {
215
+ return Reflect.set(target, prop, value, receiver);
216
+ }
217
+ target.__setRaw(prop, value);
218
+ return true;
219
+ },
220
+ has(target, prop) {
221
+ if (typeof prop === "symbol" || METHOD_KEYS.has(prop) || prop in target) {
222
+ return Reflect.has(target, prop);
223
+ }
224
+ const raw = target.__rawEntries();
225
+ return raw.some((entry) => entry.key === prop);
226
+ },
227
+ deleteProperty(target, prop) {
228
+ if (typeof prop === "symbol" || METHOD_KEYS.has(prop)) {
229
+ return Reflect.deleteProperty(target, prop);
230
+ }
231
+ return target.__deleteRaw(String(prop));
232
+ },
233
+ ownKeys(target) {
234
+ // Object.keys / Object.entries / for-in see only the header names.
235
+ // The HeaderList methods stay non-enumerable so they don't pollute
236
+ // serialisation.
237
+ const raw = target.__rawEntries();
238
+ const seen = new Set();
239
+ const keys = [];
240
+ for (const entry of raw) {
241
+ if (!seen.has(entry.key)) {
242
+ seen.add(entry.key);
243
+ keys.push(entry.key);
244
+ }
245
+ }
246
+ return keys;
247
+ },
248
+ getOwnPropertyDescriptor(target, prop) {
249
+ if (typeof prop === "symbol") {
250
+ return Reflect.getOwnPropertyDescriptor(target, prop);
251
+ }
252
+ if (METHOD_KEYS.has(prop)) {
253
+ return undefined;
254
+ }
255
+ const raw = target.__rawEntries();
256
+ const found = raw.find((entry) => entry.key === prop);
257
+ if (found) {
258
+ return {
259
+ configurable: true,
260
+ enumerable: true,
261
+ writable: true,
262
+ value: found.value,
263
+ };
264
+ }
265
+ return undefined;
266
+ },
267
+ });
268
+ };
269
+ /**
270
+ * Best-effort extraction of the underlying entry list, used by the
271
+ * request-state serialiser. Falls back to `Object.entries` for back-compat
272
+ * with any external callers that still pass a plain record.
273
+ */
274
+ export const headerListEntries = (value) => {
275
+ if (value &&
276
+ typeof value.all === "function") {
277
+ return value.all();
278
+ }
279
+ return Object.entries(value).map(([key, raw]) => ({
280
+ key,
281
+ value: stringifyValue(raw),
282
+ }));
283
+ };
284
+ //# sourceMappingURL=headerList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headerList.js","sourceRoot":"","sources":["../../../src/script/features/headerList.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ScriptInfoCapability, ScriptStage } from "../types.js";
2
+ export interface InfoApi {
3
+ eventName: string;
4
+ iteration: number;
5
+ iterationCount: number;
6
+ requestName: string;
7
+ requestId: string;
8
+ }
9
+ export declare const buildInfoApi: (capability: ScriptInfoCapability | undefined, stage: ScriptStage) => InfoApi;
10
+ //# sourceMappingURL=info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../../src/script/features/info.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAiBD,eAAO,MAAM,YAAY,GACvB,YAAY,oBAAoB,GAAG,SAAS,EAC5C,OAAO,WAAW,KACjB,OAeF,CAAC"}
@@ -0,0 +1,32 @@
1
+ // pm.info — Postman's read-only snapshot of "where am I" in a run.
2
+ //
3
+ // Every field is host-supplied via capabilities.info. Defaults are
4
+ // chosen so a single Send (no iteration) still produces sensible
5
+ // values: iteration=1, iterationCount=1, eventName based on stage.
6
+ const stageToEventName = (stage) => {
7
+ switch (stage) {
8
+ case "pre-request":
9
+ return "prerequest";
10
+ case "tests":
11
+ return "test";
12
+ case "post-response":
13
+ return "post-response";
14
+ case "script":
15
+ return "scenario-script";
16
+ default:
17
+ return String(stage);
18
+ }
19
+ };
20
+ export const buildInfoApi = (capability, stage) => {
21
+ const fallbackEvent = stageToEventName(stage);
22
+ return {
23
+ eventName: capability?.eventName ?? fallbackEvent,
24
+ iteration: typeof capability?.iteration === "number" ? capability.iteration : 1,
25
+ iterationCount: typeof capability?.iterationCount === "number"
26
+ ? capability.iterationCount
27
+ : 1,
28
+ requestName: typeof capability?.requestName === "string" ? capability.requestName : "",
29
+ requestId: typeof capability?.requestId === "string" ? capability.requestId : "",
30
+ };
31
+ };
32
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../../src/script/features/info.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,mEAAmE;AACnE,iEAAiE;AACjE,mEAAmE;AAYnE,MAAM,gBAAgB,GAAG,CAAC,KAAkB,EAAU,EAAE;IACtD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,YAAY,CAAC;QACtB,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,eAAe;YAClB,OAAO,eAAe,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,iBAAiB,CAAC;QAC3B;YACE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,UAA4C,EAC5C,KAAkB,EACT,EAAE;IACX,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO;QACL,SAAS,EAAE,UAAU,EAAE,SAAS,IAAI,aAAa;QACjD,SAAS,EACP,OAAO,UAAU,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACtE,cAAc,EACZ,OAAO,UAAU,EAAE,cAAc,KAAK,QAAQ;YAC5C,CAAC,CAAC,UAAU,CAAC,cAAc;YAC3B,CAAC,CAAC,CAAC;QACP,WAAW,EACT,OAAO,UAAU,EAAE,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE;QAC3E,SAAS,EACP,OAAO,UAAU,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;KACxE,CAAC;AACJ,CAAC,CAAC"}
@@ -1,9 +1,10 @@
1
+ import { type HeaderList } from "./headerList.js";
1
2
  import type { ScriptRequestBodyState, ScriptRequestState } from "../types.js";
2
3
  export interface RequestApi {
3
4
  method: string;
4
5
  url: string;
5
- headers: Record<string, string>;
6
- query: Record<string, string>;
6
+ headers: HeaderList;
7
+ query: HeaderList;
7
8
  body: ScriptRequestBodyState;
8
9
  getHeader: (key: string) => string | undefined;
9
10
  setHeader: (key: string, value: unknown) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/script/features/request.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAEV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnD,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAqCD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,UAAU,CAAC;IAChB,cAAc,EAAE,MAAM,kBAAkB,CAAC;CAC1C;AAED,eAAO,MAAM,eAAe,GAAI,SAAS,kBAAkB,KAAG,gBAqE7D,CAAC"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/script/features/request.ts"],"names":[],"mappings":"AAaA,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAEV,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/C,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnD,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AAwBD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,UAAU,CAAC;IAChB,cAAc,EAAE,MAAM,kBAAkB,CAAC;CAC1C;AAED,eAAO,MAAM,eAAe,GAAI,SAAS,kBAAkB,KAAG,gBAmF7D,CAAC"}
@@ -4,39 +4,34 @@
4
4
  // getQueryParam/setQueryParam/unsetQueryParam, setMethod/setUrl/setRawBody.
5
5
  // Mutations are applied to a working copy; callers retrieve the final
6
6
  // state via `toRequestState()` after the script completes.
7
+ //
8
+ // `headers` and `query` are exposed as HeaderList wrappers (see
9
+ // `./headerList.ts`). Existing scripts that use bracket access
10
+ // (`pm.request.headers["X-Custom"]`) continue to work bit-for-bit; new
11
+ // scripts can call `headers.get`, `headers.upsert`, `headers.add`,
12
+ // `headers.has`, `headers.remove`, etc.
13
+ import { createHeaderList, headerListEntries, } from "./headerList.js";
7
14
  const cloneBody = (body) => ({
8
15
  mode: body.mode,
9
16
  raw: body.raw,
10
17
  formEntries: body.formEntries.map((entry) => ({ ...entry })),
11
18
  });
12
- const toRecord = (entries) => {
13
- const record = {};
14
- for (const entry of entries) {
15
- if (entry.enabled === false) {
16
- continue;
17
- }
18
- const key = entry.key.trim();
19
- if (!key) {
20
- continue;
21
- }
22
- record[key] = entry.value;
23
- }
24
- return record;
25
- };
26
- const toEntries = (record) => Object.entries(record).map(([key, value]) => ({
27
- key,
28
- value,
29
- enabled: true,
30
- }));
31
19
  const stringifyHeaderValue = (value) => {
32
20
  if (value === undefined || value === null) {
33
21
  return "";
34
22
  }
35
23
  return String(value);
36
24
  };
25
+ const enabledEntries = (entries) => entries
26
+ .filter((entry) => entry.enabled !== false)
27
+ .map((entry) => ({
28
+ key: entry.key.trim(),
29
+ value: entry.value,
30
+ }))
31
+ .filter((entry) => entry.key.length > 0);
37
32
  export const buildRequestApi = (request) => {
38
- const headers = toRecord(request.headers);
39
- const query = toRecord(request.query);
33
+ const headers = createHeaderList(enabledEntries(request.headers));
34
+ const query = createHeaderList(enabledEntries(request.query));
40
35
  const body = cloneBody(request.body);
41
36
  const api = {
42
37
  method: request.method,
@@ -44,35 +39,43 @@ export const buildRequestApi = (request) => {
44
39
  headers,
45
40
  query,
46
41
  body,
47
- getHeader: (key) => headers[String(key ?? "").trim()],
42
+ getHeader: (key) => headers.get(String(key ?? "").trim()),
48
43
  setHeader: (key, value) => {
49
44
  const normalizedKey = String(key ?? "").trim();
50
45
  if (!normalizedKey) {
51
46
  return;
52
47
  }
53
- headers[normalizedKey] = stringifyHeaderValue(value);
48
+ // upsert keeps duplicates collapsed and is case-insensitive — matches
49
+ // both Postman semantics and the legacy `headers[k] = v` behaviour.
50
+ headers.upsert({
51
+ key: normalizedKey,
52
+ value: stringifyHeaderValue(value),
53
+ });
54
54
  },
55
55
  unsetHeader: (key) => {
56
56
  const normalizedKey = String(key ?? "").trim();
57
57
  if (!normalizedKey) {
58
58
  return;
59
59
  }
60
- delete headers[normalizedKey];
60
+ headers.remove(normalizedKey);
61
61
  },
62
- getQueryParam: (key) => query[String(key ?? "").trim()],
62
+ getQueryParam: (key) => query.get(String(key ?? "").trim()),
63
63
  setQueryParam: (key, value) => {
64
64
  const normalizedKey = String(key ?? "").trim();
65
65
  if (!normalizedKey) {
66
66
  return;
67
67
  }
68
- query[normalizedKey] = stringifyHeaderValue(value);
68
+ query.upsert({
69
+ key: normalizedKey,
70
+ value: stringifyHeaderValue(value),
71
+ });
69
72
  },
70
73
  unsetQueryParam: (key) => {
71
74
  const normalizedKey = String(key ?? "").trim();
72
75
  if (!normalizedKey) {
73
76
  return;
74
77
  }
75
- delete query[normalizedKey];
78
+ query.remove(normalizedKey);
76
79
  },
77
80
  setMethod(nextMethod) {
78
81
  const normalizedValue = String(nextMethod ?? "")
@@ -96,8 +99,14 @@ export const buildRequestApi = (request) => {
96
99
  toRequestState: () => ({
97
100
  method: api.method,
98
101
  url: api.url,
99
- headers: toEntries(api.headers),
100
- query: toEntries(api.query),
102
+ headers: headerListEntries(api.headers).map((entry) => ({
103
+ ...entry,
104
+ enabled: true,
105
+ })),
106
+ query: headerListEntries(api.query).map((entry) => ({
107
+ ...entry,
108
+ enabled: true,
109
+ })),
101
110
  body: cloneBody(api.body),
102
111
  }),
103
112
  };