@glubean/sdk 0.2.1 → 0.2.2
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/dist/configure/http.d.ts +25 -0
- package/dist/configure/http.d.ts.map +1 -0
- package/dist/configure/http.js +88 -0
- package/dist/configure/http.js.map +1 -0
- package/dist/configure/index.d.ts +78 -0
- package/dist/configure/index.d.ts.map +1 -0
- package/dist/configure/index.js +78 -0
- package/dist/configure/index.js.map +1 -0
- package/dist/configure/plugin.d.ts +23 -0
- package/dist/configure/plugin.d.ts.map +1 -0
- package/dist/configure/plugin.js +81 -0
- package/dist/configure/plugin.js.map +1 -0
- package/dist/configure/runtime.d.ts +24 -0
- package/dist/configure/runtime.d.ts.map +1 -0
- package/dist/configure/runtime.js +45 -0
- package/dist/configure/runtime.js.map +1 -0
- package/dist/configure/template.d.ts +22 -0
- package/dist/configure/template.d.ts.map +1 -0
- package/dist/configure/template.js +34 -0
- package/dist/configure/template.js.map +1 -0
- package/dist/configure/vars.d.ts +20 -0
- package/dist/configure/vars.d.ts.map +1 -0
- package/dist/configure/vars.js +48 -0
- package/dist/configure/vars.js.map +1 -0
- package/dist/configure.d.ts +2 -133
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +2 -436
- package/dist/configure.js.map +1 -1
- package/dist/contract-artifacts.d.ts +268 -0
- package/dist/contract-artifacts.d.ts.map +1 -0
- package/dist/contract-artifacts.js +402 -0
- package/dist/contract-artifacts.js.map +1 -0
- package/dist/contract-core.d.ts +30 -0
- package/dist/contract-core.d.ts.map +1 -1
- package/dist/contract-core.js +47 -0
- package/dist/contract-core.js.map +1 -1
- package/dist/contract-http/adapter.d.ts.map +1 -1
- package/dist/contract-http/adapter.js +22 -7
- package/dist/contract-http/adapter.js.map +1 -1
- package/dist/contract-http/factory.d.ts.map +1 -1
- package/dist/contract-http/factory.js +13 -14
- package/dist/contract-http/factory.js.map +1 -1
- package/dist/contract-http/openapi.d.ts +56 -7
- package/dist/contract-http/openapi.d.ts.map +1 -1
- package/dist/contract-http/openapi.js +371 -21
- package/dist/contract-http/openapi.js.map +1 -1
- package/dist/contract-http/types.d.ts +2 -13
- package/dist/contract-http/types.d.ts.map +1 -1
- package/dist/contract-types.d.ts +59 -10
- package/dist/contract-types.d.ts.map +1 -1
- package/dist/expect.d.ts +13 -0
- package/dist/expect.d.ts.map +1 -1
- package/dist/expect.js +18 -0
- package/dist/expect.js.map +1 -1
- package/dist/index.d.ts +55 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -8
- package/dist/index.js.map +1 -1
- package/dist/install-plugin.d.ts +94 -0
- package/dist/install-plugin.d.ts.map +1 -0
- package/dist/install-plugin.js +222 -0
- package/dist/install-plugin.js.map +1 -0
- package/dist/internal.d.ts +1 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -0
- package/dist/internal.js.map +1 -1
- package/dist/plugin.d.ts +45 -34
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +47 -34
- package/dist/plugin.js.map +1 -1
- package/dist/{test-builder.d.ts → test/builder.d.ts} +2 -2
- package/dist/test/builder.d.ts.map +1 -0
- package/dist/{test-builder.js → test/builder.js} +3 -3
- package/dist/{test-builder.js.map → test/builder.js.map} +1 -1
- package/dist/{each-builder.d.ts → test/each-builder.d.ts} +1 -1
- package/dist/test/each-builder.d.ts.map +1 -0
- package/dist/{each-builder.js → test/each-builder.js} +3 -3
- package/dist/test/each-builder.js.map +1 -0
- package/dist/{test-extend.d.ts → test/extend.d.ts} +3 -3
- package/dist/test/extend.d.ts.map +1 -0
- package/dist/{test-extend.js → test/extend.js} +5 -5
- package/dist/test/extend.js.map +1 -0
- package/dist/{test-utils.d.ts → test/utils.d.ts} +2 -2
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/{test-utils.js → test/utils.js} +1 -1
- package/dist/test/utils.js.map +1 -0
- package/dist/types.d.ts +78 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/contract-http/markdown.d.ts +0 -10
- package/dist/contract-http/markdown.d.ts.map +0 -1
- package/dist/contract-http/markdown.js +0 -21
- package/dist/contract-http/markdown.js.map +0 -1
- package/dist/each-builder.d.ts.map +0 -1
- package/dist/each-builder.js.map +0 -1
- package/dist/test-builder.d.ts.map +0 -1
- package/dist/test-extend.d.ts.map +0 -1
- package/dist/test-extend.js.map +0 -1
- package/dist/test-utils.d.ts.map +0 -1
- package/dist/test-utils.js.map +0 -1
package/dist/configure.d.ts
CHANGED
|
@@ -1,134 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* `configure()` lets you declare shared dependencies (vars, secrets, HTTP config)
|
|
5
|
-
* once at the top of a test file (or in a shared `configure.ts`), eliminating
|
|
6
|
-
* repetitive `ctx.vars.require()` / `ctx.secrets.require()` calls in every test.
|
|
7
|
-
*
|
|
8
|
-
* All returned values are **lazy** — they are not resolved until a test function
|
|
9
|
-
* actually accesses them at runtime. This means:
|
|
10
|
-
* - Safe to call at module top-level (scanner won't trigger resolution)
|
|
11
|
-
* - Safe to share across files via re-exports
|
|
12
|
-
* - Each test execution gets the correct runtime values
|
|
13
|
-
*
|
|
14
|
-
* @example Single file usage
|
|
15
|
-
* ```ts
|
|
16
|
-
* import { test, configure } from "@glubean/sdk";
|
|
17
|
-
*
|
|
18
|
-
* const { vars, secrets, http } = configure({
|
|
19
|
-
* vars: { baseUrl: "BASE_URL" },
|
|
20
|
-
* secrets: { apiKey: "API_KEY" },
|
|
21
|
-
* http: {
|
|
22
|
-
* prefixUrl: "BASE_URL",
|
|
23
|
-
* headers: { Authorization: "Bearer {{API_KEY}}" },
|
|
24
|
-
* },
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
28
|
-
* const res = await http.get("users").json();
|
|
29
|
-
* ctx.assert(res.length > 0, "has users");
|
|
30
|
-
* });
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* @example Shared across files (tests/configure.ts)
|
|
34
|
-
* ```ts
|
|
35
|
-
* // tests/configure.ts
|
|
36
|
-
* import { configure } from "@glubean/sdk";
|
|
37
|
-
* export const { vars, secrets, http } = configure({
|
|
38
|
-
* vars: { baseUrl: "BASE_URL" },
|
|
39
|
-
* http: { prefixUrl: "BASE_URL" },
|
|
40
|
-
* });
|
|
41
|
-
*
|
|
42
|
-
* // tests/users.test.ts
|
|
43
|
-
* import { test } from "@glubean/sdk";
|
|
44
|
-
* import { http } from "./configure.js";
|
|
45
|
-
*
|
|
46
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
47
|
-
* const res = await http.get("users").json();
|
|
48
|
-
* });
|
|
49
|
-
* ```
|
|
50
|
-
*
|
|
51
|
-
* @module configure
|
|
52
|
-
*/
|
|
53
|
-
import type { ConfigureOptions, ConfigureResult, PluginFactory, ReservedConfigureKeys, ResolvePlugins } from "./types.js";
|
|
54
|
-
import { type InternalRuntime } from "./runtime-carrier.js";
|
|
55
|
-
export type { InternalRuntime };
|
|
56
|
-
/**
|
|
57
|
-
* Resolve `{{key}}` template placeholders in a string.
|
|
58
|
-
*
|
|
59
|
-
* Resolution priority (first non-empty wins):
|
|
60
|
-
* 1. Session — dynamic values set during session setup (e.g., auth tokens)
|
|
61
|
-
* 2. Secrets — from `.env.secrets`
|
|
62
|
-
* 3. Vars — from `.env`
|
|
63
|
-
*
|
|
64
|
-
* Session values must be strings to resolve in templates. Non-string session
|
|
65
|
-
* values are silently skipped (they're still accessible via `ctx.session.get()`).
|
|
66
|
-
*
|
|
67
|
-
* This is used internally by `buildLazyHttp()` and exposed to plugin authors
|
|
68
|
-
* via `GlubeanRuntime.resolveTemplate()`.
|
|
69
|
-
*/
|
|
70
|
-
export declare function resolveTemplate(template: string, vars: Record<string, string>, secrets: Record<string, string>, session?: Record<string, unknown>): string;
|
|
71
|
-
/**
|
|
72
|
-
* Declare file-level dependencies on vars, secrets, and HTTP configuration.
|
|
73
|
-
*
|
|
74
|
-
* Returns lazy accessors that resolve at test runtime, not at import time.
|
|
75
|
-
* All declared vars and secrets are **required** — missing values cause the test
|
|
76
|
-
* to fail immediately with a clear error message.
|
|
77
|
-
*
|
|
78
|
-
* The returned objects can be shared across files via re-exports.
|
|
79
|
-
*
|
|
80
|
-
* @param options Configuration declaring vars, secrets, and HTTP defaults
|
|
81
|
-
* @returns Lazy accessors for vars, secrets, and a pre-configured HTTP client
|
|
82
|
-
*
|
|
83
|
-
* @example Basic usage
|
|
84
|
-
* ```ts
|
|
85
|
-
* import { test, configure } from "@glubean/sdk";
|
|
86
|
-
*
|
|
87
|
-
* const { vars, http } = configure({
|
|
88
|
-
* vars: { baseUrl: "base_url" },
|
|
89
|
-
* http: { prefixUrl: "base_url" },
|
|
90
|
-
* });
|
|
91
|
-
*
|
|
92
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
93
|
-
* const res = await http.get("users").json();
|
|
94
|
-
* ctx.log(`Base URL: ${vars.baseUrl}`);
|
|
95
|
-
* });
|
|
96
|
-
* ```
|
|
97
|
-
*
|
|
98
|
-
* @example Full configuration with secrets
|
|
99
|
-
* ```ts
|
|
100
|
-
* const { vars, secrets, http } = configure({
|
|
101
|
-
* vars: { baseUrl: "base_url", orgId: "org_id" },
|
|
102
|
-
* secrets: { apiKey: "api_key" },
|
|
103
|
-
* http: {
|
|
104
|
-
* prefixUrl: "base_url",
|
|
105
|
-
* headers: { Authorization: "Bearer {{api_key}}" },
|
|
106
|
-
* },
|
|
107
|
-
* });
|
|
108
|
-
* ```
|
|
109
|
-
*
|
|
110
|
-
* @example Shared across test files
|
|
111
|
-
* ```ts
|
|
112
|
-
* // tests/configure.ts
|
|
113
|
-
* export const { vars, secrets, http } = configure({ ... });
|
|
114
|
-
*
|
|
115
|
-
* // tests/users.test.ts
|
|
116
|
-
* import { http, vars } from "./configure.js";
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
export declare function configure<V extends Record<string, string> = Record<string, string>, S extends Record<string, string> = Record<string, string>, P extends Record<string, PluginFactory<any>> = Record<string, never>>(options: ConfigureOptions & {
|
|
120
|
-
vars?: {
|
|
121
|
-
[K in keyof V]: string;
|
|
122
|
-
};
|
|
123
|
-
secrets?: {
|
|
124
|
-
[K in keyof S]: string;
|
|
125
|
-
};
|
|
126
|
-
plugins?: P & {
|
|
127
|
-
[K in ReservedConfigureKeys]?: never;
|
|
128
|
-
};
|
|
129
|
-
}): ConfigureResult<{
|
|
130
|
-
[K in keyof V]: string;
|
|
131
|
-
}, {
|
|
132
|
-
[K in keyof S]: string;
|
|
133
|
-
}> & ResolvePlugins<P>;
|
|
1
|
+
export { configure, resolveTemplate } from "./configure/index.js";
|
|
2
|
+
export type { InternalRuntime } from "./configure/index.js";
|
|
134
3
|
//# sourceMappingURL=configure.d.ts.map
|
package/dist/configure.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/configure.js
CHANGED
|
@@ -1,437 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* `configure()` lets you declare shared dependencies (vars, secrets, HTTP config)
|
|
5
|
-
* once at the top of a test file (or in a shared `configure.ts`), eliminating
|
|
6
|
-
* repetitive `ctx.vars.require()` / `ctx.secrets.require()` calls in every test.
|
|
7
|
-
*
|
|
8
|
-
* All returned values are **lazy** — they are not resolved until a test function
|
|
9
|
-
* actually accesses them at runtime. This means:
|
|
10
|
-
* - Safe to call at module top-level (scanner won't trigger resolution)
|
|
11
|
-
* - Safe to share across files via re-exports
|
|
12
|
-
* - Each test execution gets the correct runtime values
|
|
13
|
-
*
|
|
14
|
-
* @example Single file usage
|
|
15
|
-
* ```ts
|
|
16
|
-
* import { test, configure } from "@glubean/sdk";
|
|
17
|
-
*
|
|
18
|
-
* const { vars, secrets, http } = configure({
|
|
19
|
-
* vars: { baseUrl: "BASE_URL" },
|
|
20
|
-
* secrets: { apiKey: "API_KEY" },
|
|
21
|
-
* http: {
|
|
22
|
-
* prefixUrl: "BASE_URL",
|
|
23
|
-
* headers: { Authorization: "Bearer {{API_KEY}}" },
|
|
24
|
-
* },
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
28
|
-
* const res = await http.get("users").json();
|
|
29
|
-
* ctx.assert(res.length > 0, "has users");
|
|
30
|
-
* });
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* @example Shared across files (tests/configure.ts)
|
|
34
|
-
* ```ts
|
|
35
|
-
* // tests/configure.ts
|
|
36
|
-
* import { configure } from "@glubean/sdk";
|
|
37
|
-
* export const { vars, secrets, http } = configure({
|
|
38
|
-
* vars: { baseUrl: "BASE_URL" },
|
|
39
|
-
* http: { prefixUrl: "BASE_URL" },
|
|
40
|
-
* });
|
|
41
|
-
*
|
|
42
|
-
* // tests/users.test.ts
|
|
43
|
-
* import { test } from "@glubean/sdk";
|
|
44
|
-
* import { http } from "./configure.js";
|
|
45
|
-
*
|
|
46
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
47
|
-
* const res = await http.get("users").json();
|
|
48
|
-
* });
|
|
49
|
-
* ```
|
|
50
|
-
*
|
|
51
|
-
* @module configure
|
|
52
|
-
*/
|
|
53
|
-
import { getRuntime as getCarrierRuntime, } from "./runtime-carrier.js";
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// Runtime accessor
|
|
56
|
-
// =============================================================================
|
|
57
|
-
/**
|
|
58
|
-
* Get the current runtime context, throwing if accessed outside test execution.
|
|
59
|
-
* Thin wrapper over the carrier's optional `getRuntime()` that preserves the
|
|
60
|
-
* legacy throw-on-missing contract.
|
|
61
|
-
*
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
|
-
function getRuntime() {
|
|
65
|
-
const runtime = getCarrierRuntime();
|
|
66
|
-
if (!runtime) {
|
|
67
|
-
throw new Error("configure() values can only be accessed during test execution. " +
|
|
68
|
-
"Did you try to read a var or secret at module load time? " +
|
|
69
|
-
"Move the access inside a test function.");
|
|
70
|
-
}
|
|
71
|
-
return runtime;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Require a var from the runtime context.
|
|
75
|
-
* Throws if the var is missing or empty.
|
|
76
|
-
*
|
|
77
|
-
* @internal
|
|
78
|
-
*/
|
|
79
|
-
function requireVar(key) {
|
|
80
|
-
const runtime = getRuntime();
|
|
81
|
-
const value = runtime.vars[key];
|
|
82
|
-
if (value === undefined || value === null || value === "") {
|
|
83
|
-
throw new Error(`Missing required var: ${key}`);
|
|
84
|
-
}
|
|
85
|
-
return value;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Require a secret from the runtime context.
|
|
89
|
-
* Throws if the secret is missing or empty.
|
|
90
|
-
*
|
|
91
|
-
* @internal
|
|
92
|
-
*/
|
|
93
|
-
function requireSecret(key) {
|
|
94
|
-
const runtime = getRuntime();
|
|
95
|
-
const value = runtime.secrets[key];
|
|
96
|
-
if (value === undefined || value === null || value === "") {
|
|
97
|
-
throw new Error(`Missing required secret: ${key}`);
|
|
98
|
-
}
|
|
99
|
-
return value;
|
|
100
|
-
}
|
|
101
|
-
// =============================================================================
|
|
102
|
-
// Lazy proxy builders
|
|
103
|
-
// =============================================================================
|
|
104
|
-
/**
|
|
105
|
-
* Regex for `{{key}}` template placeholders in header values.
|
|
106
|
-
*/
|
|
107
|
-
const TEMPLATE_RE = /\{\{([\w-]+)\}\}/g;
|
|
108
|
-
/**
|
|
109
|
-
* Build a lazy vars accessor object.
|
|
110
|
-
* Each property is a getter that calls `requireVar()` on access.
|
|
111
|
-
*
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
114
|
-
function buildLazyVars(mapping) {
|
|
115
|
-
const obj = {};
|
|
116
|
-
for (const [prop, value] of Object.entries(mapping)) {
|
|
117
|
-
Object.defineProperty(obj, prop, {
|
|
118
|
-
get() {
|
|
119
|
-
const runtime = getRuntime();
|
|
120
|
-
return resolveTemplate(value, runtime.vars, runtime.secrets, runtime.session);
|
|
121
|
-
},
|
|
122
|
-
enumerable: true,
|
|
123
|
-
configurable: false,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return obj;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Build a lazy secrets accessor object.
|
|
130
|
-
* Each property is a getter that calls `requireSecret()` on access.
|
|
131
|
-
*
|
|
132
|
-
* @internal
|
|
133
|
-
*/
|
|
134
|
-
function buildLazySecrets(mapping) {
|
|
135
|
-
const obj = {};
|
|
136
|
-
for (const [prop, value] of Object.entries(mapping)) {
|
|
137
|
-
Object.defineProperty(obj, prop, {
|
|
138
|
-
get() {
|
|
139
|
-
const runtime = getRuntime();
|
|
140
|
-
return resolveTemplate(value, runtime.vars, runtime.secrets, runtime.session);
|
|
141
|
-
},
|
|
142
|
-
enumerable: true,
|
|
143
|
-
configurable: false,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
return obj;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Resolve `{{key}}` template placeholders in a string.
|
|
150
|
-
*
|
|
151
|
-
* Resolution priority (first non-empty wins):
|
|
152
|
-
* 1. Session — dynamic values set during session setup (e.g., auth tokens)
|
|
153
|
-
* 2. Secrets — from `.env.secrets`
|
|
154
|
-
* 3. Vars — from `.env`
|
|
155
|
-
*
|
|
156
|
-
* Session values must be strings to resolve in templates. Non-string session
|
|
157
|
-
* values are silently skipped (they're still accessible via `ctx.session.get()`).
|
|
158
|
-
*
|
|
159
|
-
* This is used internally by `buildLazyHttp()` and exposed to plugin authors
|
|
160
|
-
* via `GlubeanRuntime.resolveTemplate()`.
|
|
161
|
-
*/
|
|
162
|
-
export function resolveTemplate(template, vars, secrets, session) {
|
|
163
|
-
return template.replace(TEMPLATE_RE, (_match, key) => {
|
|
164
|
-
// Session first (dynamic, from setup hooks), then secrets, then vars
|
|
165
|
-
const sessionValue = session?.[key];
|
|
166
|
-
const value = (typeof sessionValue === "string" ? sessionValue : undefined) ??
|
|
167
|
-
secrets[key] ??
|
|
168
|
-
vars[key];
|
|
169
|
-
if (value === undefined || value === null || value === "") {
|
|
170
|
-
throw new Error(`Missing value for template placeholder "{{${key}}}" in configure() http headers. ` +
|
|
171
|
-
`Ensure "${key}" is available in session, as a secret, or as a var.`);
|
|
172
|
-
}
|
|
173
|
-
return value;
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Build a lazy HTTP client proxy.
|
|
178
|
-
* On first method call, resolves the config and creates an extended client.
|
|
179
|
-
*
|
|
180
|
-
* @internal
|
|
181
|
-
*/
|
|
182
|
-
function buildLazyHttp(httpOptions) {
|
|
183
|
-
// Cache the resolved client per runtime identity to avoid re-extending on every call.
|
|
184
|
-
// Since each test runs in its own subprocess, a WeakMap keyed on runtime object
|
|
185
|
-
// ensures we get one extended client per test execution.
|
|
186
|
-
const cache = new WeakMap();
|
|
187
|
-
function getClient() {
|
|
188
|
-
const runtime = getRuntime();
|
|
189
|
-
let client = cache.get(runtime);
|
|
190
|
-
if (client)
|
|
191
|
-
return client;
|
|
192
|
-
// Build ky-compatible options from the configure http config
|
|
193
|
-
const extendOptions = {};
|
|
194
|
-
if (httpOptions.prefixUrl) {
|
|
195
|
-
extendOptions.prefixUrl = resolveTemplate(httpOptions.prefixUrl, runtime.vars, runtime.secrets, runtime.session);
|
|
196
|
-
}
|
|
197
|
-
if (httpOptions.headers) {
|
|
198
|
-
const resolvedHeaders = {};
|
|
199
|
-
for (const [name, template] of Object.entries(httpOptions.headers)) {
|
|
200
|
-
resolvedHeaders[name] = resolveTemplate(template, runtime.vars, runtime.secrets, runtime.session);
|
|
201
|
-
}
|
|
202
|
-
extendOptions.headers = resolvedHeaders;
|
|
203
|
-
}
|
|
204
|
-
if (httpOptions.searchParams) {
|
|
205
|
-
const resolvedParams = {};
|
|
206
|
-
for (const [name, template] of Object.entries(httpOptions.searchParams)) {
|
|
207
|
-
resolvedParams[name] = resolveTemplate(template, runtime.vars, runtime.secrets, runtime.session);
|
|
208
|
-
}
|
|
209
|
-
extendOptions.searchParams = resolvedParams;
|
|
210
|
-
}
|
|
211
|
-
if (httpOptions.timeout !== undefined) {
|
|
212
|
-
extendOptions.timeout = httpOptions.timeout;
|
|
213
|
-
}
|
|
214
|
-
if (httpOptions.retry !== undefined) {
|
|
215
|
-
extendOptions.retry = httpOptions.retry;
|
|
216
|
-
}
|
|
217
|
-
if (httpOptions.throwHttpErrors !== undefined) {
|
|
218
|
-
extendOptions.throwHttpErrors = httpOptions.throwHttpErrors;
|
|
219
|
-
}
|
|
220
|
-
if (httpOptions.hooks) {
|
|
221
|
-
extendOptions.hooks = httpOptions.hooks;
|
|
222
|
-
}
|
|
223
|
-
if (httpOptions.redirect !== undefined) {
|
|
224
|
-
extendOptions.redirect = httpOptions.redirect;
|
|
225
|
-
}
|
|
226
|
-
if (typeof process !== "undefined" && process.env?.["GLUBEAN_DEBUG"]) {
|
|
227
|
-
process.stderr.write(`[glubean:debug] configure.getClient extendOptions=${JSON.stringify({ ...extendOptions, headers: "..." })}\n`);
|
|
228
|
-
}
|
|
229
|
-
client = runtime.http.extend(extendOptions);
|
|
230
|
-
cache.set(runtime, client);
|
|
231
|
-
return client;
|
|
232
|
-
}
|
|
233
|
-
// Create a callable proxy that delegates all method calls to the lazily-resolved client.
|
|
234
|
-
const HTTP_METHODS = [
|
|
235
|
-
"get",
|
|
236
|
-
"post",
|
|
237
|
-
"put",
|
|
238
|
-
"patch",
|
|
239
|
-
"delete",
|
|
240
|
-
"head",
|
|
241
|
-
];
|
|
242
|
-
// The callable function (for `http(url, options)` shorthand)
|
|
243
|
-
const proxy = function (url, options) {
|
|
244
|
-
return getClient()(url, options);
|
|
245
|
-
};
|
|
246
|
-
// Method shortcuts
|
|
247
|
-
for (const method of HTTP_METHODS) {
|
|
248
|
-
proxy[method] = (url, options) => getClient()[method](url, options);
|
|
249
|
-
}
|
|
250
|
-
// extend() — returns a new HttpClient that merges options with the resolved base
|
|
251
|
-
proxy.extend = (options) => getClient().extend(options);
|
|
252
|
-
// Expose configured timeout for error reporting (e.g. contract timeout errors)
|
|
253
|
-
proxy._configuredTimeout = httpOptions.timeout;
|
|
254
|
-
return proxy;
|
|
255
|
-
}
|
|
256
|
-
// =============================================================================
|
|
257
|
-
// Lazy plugin builder
|
|
258
|
-
// =============================================================================
|
|
259
|
-
/**
|
|
260
|
-
* Build lazy property descriptors for plugin factories.
|
|
261
|
-
* Each plugin is instantiated on first property access with a WeakMap cache
|
|
262
|
-
* keyed by the internal runtime identity.
|
|
263
|
-
*
|
|
264
|
-
* Returns PropertyDescriptorMap (not a ready object) so the caller can use
|
|
265
|
-
* Object.defineProperties() without triggering getters via spread.
|
|
266
|
-
*
|
|
267
|
-
* @internal
|
|
268
|
-
*/
|
|
269
|
-
/** Reserved keys that plugins cannot shadow. */
|
|
270
|
-
const RESERVED_KEYS = new Set(["vars", "secrets", "http"]);
|
|
271
|
-
/**
|
|
272
|
-
* Resolve (or retrieve cached) the real plugin instance for the current runtime.
|
|
273
|
-
*
|
|
274
|
-
* @internal
|
|
275
|
-
*/
|
|
276
|
-
function resolvePlugin(factory, cache) {
|
|
277
|
-
const runtime = getRuntime();
|
|
278
|
-
if (cache.has(runtime))
|
|
279
|
-
return cache.get(runtime);
|
|
280
|
-
// Build the augmented runtime that plugins see
|
|
281
|
-
const noop = () => { };
|
|
282
|
-
const augmented = {
|
|
283
|
-
vars: runtime.vars,
|
|
284
|
-
secrets: runtime.secrets,
|
|
285
|
-
http: runtime.http,
|
|
286
|
-
test: runtime.test,
|
|
287
|
-
requireVar,
|
|
288
|
-
requireSecret,
|
|
289
|
-
resolveTemplate: (template) => resolveTemplate(template, runtime.vars, runtime.secrets, runtime.session),
|
|
290
|
-
trace: runtime.trace?.bind(runtime) ?? noop,
|
|
291
|
-
action: runtime.action?.bind(runtime) ?? noop,
|
|
292
|
-
event: runtime.event?.bind(runtime) ?? noop,
|
|
293
|
-
log: runtime.log?.bind(runtime) ?? noop,
|
|
294
|
-
};
|
|
295
|
-
const instance = factory.create(augmented);
|
|
296
|
-
cache.set(runtime, instance);
|
|
297
|
-
return instance;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Build a Proxy that defers plugin creation until the plugin is actually used.
|
|
301
|
-
*
|
|
302
|
-
* This allows `const { chrome } = configure(...)` to work at module top-level —
|
|
303
|
-
* the destructured value is a transparent Proxy, not the real plugin instance.
|
|
304
|
-
* The real instance is created lazily on first property access / method call
|
|
305
|
-
* during test execution.
|
|
306
|
-
*
|
|
307
|
-
* @internal
|
|
308
|
-
*/
|
|
309
|
-
function buildLazyPlugin(factory) {
|
|
310
|
-
const cache = new WeakMap();
|
|
311
|
-
return new Proxy(Object.create(null), {
|
|
312
|
-
get(_target, prop, receiver) {
|
|
313
|
-
const instance = resolvePlugin(factory, cache);
|
|
314
|
-
const value = Reflect.get(instance, prop, receiver);
|
|
315
|
-
return typeof value === "function"
|
|
316
|
-
? value.bind(instance)
|
|
317
|
-
: value;
|
|
318
|
-
},
|
|
319
|
-
set(_target, prop, value) {
|
|
320
|
-
const instance = resolvePlugin(factory, cache);
|
|
321
|
-
return Reflect.set(instance, prop, value);
|
|
322
|
-
},
|
|
323
|
-
has(_target, prop) {
|
|
324
|
-
const instance = resolvePlugin(factory, cache);
|
|
325
|
-
return Reflect.has(instance, prop);
|
|
326
|
-
},
|
|
327
|
-
ownKeys() {
|
|
328
|
-
const instance = resolvePlugin(factory, cache);
|
|
329
|
-
return Reflect.ownKeys(instance);
|
|
330
|
-
},
|
|
331
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
332
|
-
const instance = resolvePlugin(factory, cache);
|
|
333
|
-
return Object.getOwnPropertyDescriptor(instance, prop);
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function buildLazyPlugins(plugins) {
|
|
338
|
-
const result = {};
|
|
339
|
-
for (const [name, factory] of Object.entries(plugins)) {
|
|
340
|
-
if (RESERVED_KEYS.has(name)) {
|
|
341
|
-
throw new Error(`Plugin name "${name}" conflicts with a reserved configure() field. ` +
|
|
342
|
-
`Choose a different key (reserved: ${[...RESERVED_KEYS].join(", ")}).`);
|
|
343
|
-
}
|
|
344
|
-
result[name] = buildLazyPlugin(factory);
|
|
345
|
-
}
|
|
346
|
-
return result;
|
|
347
|
-
}
|
|
348
|
-
// =============================================================================
|
|
349
|
-
// Public API
|
|
350
|
-
// =============================================================================
|
|
351
|
-
/**
|
|
352
|
-
* Declare file-level dependencies on vars, secrets, and HTTP configuration.
|
|
353
|
-
*
|
|
354
|
-
* Returns lazy accessors that resolve at test runtime, not at import time.
|
|
355
|
-
* All declared vars and secrets are **required** — missing values cause the test
|
|
356
|
-
* to fail immediately with a clear error message.
|
|
357
|
-
*
|
|
358
|
-
* The returned objects can be shared across files via re-exports.
|
|
359
|
-
*
|
|
360
|
-
* @param options Configuration declaring vars, secrets, and HTTP defaults
|
|
361
|
-
* @returns Lazy accessors for vars, secrets, and a pre-configured HTTP client
|
|
362
|
-
*
|
|
363
|
-
* @example Basic usage
|
|
364
|
-
* ```ts
|
|
365
|
-
* import { test, configure } from "@glubean/sdk";
|
|
366
|
-
*
|
|
367
|
-
* const { vars, http } = configure({
|
|
368
|
-
* vars: { baseUrl: "base_url" },
|
|
369
|
-
* http: { prefixUrl: "base_url" },
|
|
370
|
-
* });
|
|
371
|
-
*
|
|
372
|
-
* export const listUsers = test("list-users", async (ctx) => {
|
|
373
|
-
* const res = await http.get("users").json();
|
|
374
|
-
* ctx.log(`Base URL: ${vars.baseUrl}`);
|
|
375
|
-
* });
|
|
376
|
-
* ```
|
|
377
|
-
*
|
|
378
|
-
* @example Full configuration with secrets
|
|
379
|
-
* ```ts
|
|
380
|
-
* const { vars, secrets, http } = configure({
|
|
381
|
-
* vars: { baseUrl: "base_url", orgId: "org_id" },
|
|
382
|
-
* secrets: { apiKey: "api_key" },
|
|
383
|
-
* http: {
|
|
384
|
-
* prefixUrl: "base_url",
|
|
385
|
-
* headers: { Authorization: "Bearer {{api_key}}" },
|
|
386
|
-
* },
|
|
387
|
-
* });
|
|
388
|
-
* ```
|
|
389
|
-
*
|
|
390
|
-
* @example Shared across test files
|
|
391
|
-
* ```ts
|
|
392
|
-
* // tests/configure.ts
|
|
393
|
-
* export const { vars, secrets, http } = configure({ ... });
|
|
394
|
-
*
|
|
395
|
-
* // tests/users.test.ts
|
|
396
|
-
* import { http, vars } from "./configure.js";
|
|
397
|
-
* ```
|
|
398
|
-
*/
|
|
399
|
-
export function configure(options) {
|
|
400
|
-
const vars = options.vars
|
|
401
|
-
? buildLazyVars(options.vars)
|
|
402
|
-
: {};
|
|
403
|
-
const secrets = options.secrets
|
|
404
|
-
? buildLazySecrets(options.secrets)
|
|
405
|
-
: {};
|
|
406
|
-
const http = options.http ? buildLazyHttp(options.http) : buildPassthroughHttp();
|
|
407
|
-
const base = { vars, secrets, http };
|
|
408
|
-
if (options.plugins) {
|
|
409
|
-
Object.assign(base, buildLazyPlugins(options.plugins));
|
|
410
|
-
}
|
|
411
|
-
return base;
|
|
412
|
-
}
|
|
413
|
-
/**
|
|
414
|
-
* Build a passthrough HTTP client that simply delegates to ctx.http.
|
|
415
|
-
* Used when `configure()` is called without `http` options.
|
|
416
|
-
*
|
|
417
|
-
* @internal
|
|
418
|
-
*/
|
|
419
|
-
function buildPassthroughHttp() {
|
|
420
|
-
const HTTP_METHODS = [
|
|
421
|
-
"get",
|
|
422
|
-
"post",
|
|
423
|
-
"put",
|
|
424
|
-
"patch",
|
|
425
|
-
"delete",
|
|
426
|
-
"head",
|
|
427
|
-
];
|
|
428
|
-
const proxy = function (url, options) {
|
|
429
|
-
return getRuntime().http(url, options);
|
|
430
|
-
};
|
|
431
|
-
for (const method of HTTP_METHODS) {
|
|
432
|
-
proxy[method] = (url, options) => getRuntime().http[method](url, options);
|
|
433
|
-
}
|
|
434
|
-
proxy.extend = (options) => getRuntime().http.extend(options);
|
|
435
|
-
return proxy;
|
|
436
|
-
}
|
|
1
|
+
// Back-compat re-export. Implementation has moved to ./configure/index.ts
|
|
2
|
+
export { configure, resolveTemplate } from "./configure/index.js";
|
|
437
3
|
//# sourceMappingURL=configure.js.map
|
package/dist/configure.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|