@elench/testkit 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -30
- package/lib/app/doctor.mjs +43 -0
- package/lib/config/runtime.test.mjs +2 -2
- package/lib/config-api/index.d.ts +226 -78
- package/lib/config-api/index.mjs +137 -271
- package/lib/config-api/index.test.mjs +347 -155
- package/lib/config-api/profiles.mjs +640 -0
- package/lib/coverage/index.test.mjs +2 -2
- package/lib/shared/build-config.test.mjs +1 -1
- package/lib/shared/configured-steps.mjs +9 -7
- package/lib/shared/configured-steps.test.mjs +3 -3
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +5 -5
package/lib/config-api/index.mjs
CHANGED
|
@@ -3,79 +3,34 @@ import {
|
|
|
3
3
|
clearRuntimeContext,
|
|
4
4
|
getRepoConfig,
|
|
5
5
|
getRuntimeContext,
|
|
6
|
-
getRuntimeEnv,
|
|
7
6
|
registerRepoConfig,
|
|
8
7
|
registerRuntimeContext,
|
|
9
8
|
runtimeHttp,
|
|
10
9
|
runtimeJson,
|
|
11
10
|
} from "./runtime.mjs";
|
|
11
|
+
import {
|
|
12
|
+
customProfile,
|
|
13
|
+
localJsonProfile,
|
|
14
|
+
multiActorProfile,
|
|
15
|
+
rawProfile,
|
|
16
|
+
sessionProfile,
|
|
17
|
+
} from "./profiles.mjs";
|
|
12
18
|
|
|
13
19
|
export function defineConfig(config) {
|
|
14
20
|
return config || {};
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
export function defineHttpProfile(profile) {
|
|
18
|
-
return profile || {};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
23
|
export function defineFile(metadata) {
|
|
22
24
|
return metadata || {};
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
function postgresDatabase(options = {}) {
|
|
26
28
|
return {
|
|
27
29
|
provider: "local",
|
|
28
30
|
...options,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
export function commandStep(cmd, options = {}) {
|
|
33
|
-
return {
|
|
34
|
-
kind: "command",
|
|
35
|
-
cmd,
|
|
36
|
-
cwd: options.cwd,
|
|
37
|
-
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function sqlFileStep(filePath, options = {}) {
|
|
42
|
-
return {
|
|
43
|
-
kind: "sql-file",
|
|
44
|
-
path: filePath,
|
|
45
|
-
cwd: options.cwd,
|
|
46
|
-
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function moduleStep(specifier, options = {}) {
|
|
51
|
-
return {
|
|
52
|
-
kind: "module",
|
|
53
|
-
specifier,
|
|
54
|
-
cwd: options.cwd,
|
|
55
|
-
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function schemaSql(filePath, options = {}) {
|
|
60
|
-
return sqlFileStep(filePath, options);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function seedCommand(cmd, options = {}) {
|
|
64
|
-
return commandStep(cmd, options);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function seedModule(specifier, options = {}) {
|
|
68
|
-
return moduleStep(specifier, options);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function verifyCommand(cmd, options = {}) {
|
|
72
|
-
return commandStep(cmd, options);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function verifyModule(specifier, options = {}) {
|
|
76
|
-
return moduleStep(specifier, options);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
34
|
function buildDatabaseTemplateConfig(options = {}) {
|
|
80
35
|
const migrate = normalizeTemplateStepList(options.migrate);
|
|
81
36
|
const seed = normalizeTemplateStepList(options.seed);
|
|
@@ -90,60 +45,40 @@ function buildDatabaseTemplateConfig(options = {}) {
|
|
|
90
45
|
};
|
|
91
46
|
}
|
|
92
47
|
|
|
93
|
-
|
|
94
|
-
const {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
return postgresDatabase({
|
|
103
|
-
...databaseOptions,
|
|
104
|
-
template: buildDatabaseTemplateConfig(options.template || { inputs, schema, migrate, seed, verify }),
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function postgresFixture(options = {}) {
|
|
109
|
-
const { discovery, envFiles, ...databaseOptions } = options;
|
|
48
|
+
function postgresFixture(options = {}) {
|
|
49
|
+
const { discovery, envFiles, template, ...databaseOptions } = options;
|
|
50
|
+
for (const legacyKey of ["inputs", "schema", "migrate", "seed", "verify"]) {
|
|
51
|
+
if (Object.prototype.hasOwnProperty.call(options, legacyKey)) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`database.fixture(...) no longer accepts top-level "${legacyKey}". Move lifecycle config under database.fixture({ template: { ... } }).`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
110
57
|
return {
|
|
111
58
|
discovery: discovery || {
|
|
112
59
|
roots: [".testkit-fixture"],
|
|
113
60
|
},
|
|
114
61
|
envFiles,
|
|
115
62
|
local: false,
|
|
116
|
-
database: postgresDatabase(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
if (!serviceName || !String(serviceName).trim()) {
|
|
126
|
-
throw new Error("databaseServiceEnv serviceName must be a non-empty string");
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
[`${normalizedPrefix}_DATABASE_HOST`]: `{dbHost:${serviceName}}`,
|
|
131
|
-
[`${normalizedPrefix}_DATABASE_PORT`]: `{dbPort:${serviceName}}`,
|
|
132
|
-
[`${normalizedPrefix}_DATABASE_NAME`]: `{dbName:${serviceName}}`,
|
|
133
|
-
[`${normalizedPrefix}_DATABASE_USER`]: `{dbUser:${serviceName}}`,
|
|
134
|
-
[`${normalizedPrefix}_DATABASE_PASSWORD`]: `{dbPassword:${serviceName}}`,
|
|
135
|
-
[`${normalizedPrefix}_DATABASE_SSL`]: "0",
|
|
63
|
+
database: postgresDatabase(
|
|
64
|
+
template
|
|
65
|
+
? {
|
|
66
|
+
...databaseOptions,
|
|
67
|
+
template: buildDatabaseTemplateConfig(template),
|
|
68
|
+
}
|
|
69
|
+
: databaseOptions
|
|
70
|
+
),
|
|
136
71
|
};
|
|
137
72
|
}
|
|
138
73
|
|
|
139
|
-
|
|
74
|
+
function nodeToolchain(options = {}) {
|
|
140
75
|
return {
|
|
141
76
|
kind: "node",
|
|
142
77
|
...options,
|
|
143
78
|
};
|
|
144
79
|
}
|
|
145
80
|
|
|
146
|
-
|
|
81
|
+
function tscBuild(options = {}) {
|
|
147
82
|
return {
|
|
148
83
|
kind: "tsc",
|
|
149
84
|
cwd: options.cwd,
|
|
@@ -154,7 +89,7 @@ export function tscBuild(options = {}) {
|
|
|
154
89
|
};
|
|
155
90
|
}
|
|
156
91
|
|
|
157
|
-
|
|
92
|
+
function scriptBuild(script, options = {}) {
|
|
158
93
|
return {
|
|
159
94
|
kind: "script",
|
|
160
95
|
script,
|
|
@@ -163,7 +98,7 @@ export function scriptBuild(script, options = {}) {
|
|
|
163
98
|
};
|
|
164
99
|
}
|
|
165
100
|
|
|
166
|
-
|
|
101
|
+
function stepsBuild(options = {}) {
|
|
167
102
|
return {
|
|
168
103
|
kind: "steps",
|
|
169
104
|
inputs: Array.isArray(options.inputs) ? [...options.inputs] : undefined,
|
|
@@ -171,7 +106,7 @@ export function stepsBuild(options = {}) {
|
|
|
171
106
|
};
|
|
172
107
|
}
|
|
173
108
|
|
|
174
|
-
|
|
109
|
+
function nextBuild(options = {}) {
|
|
175
110
|
return {
|
|
176
111
|
kind: "next",
|
|
177
112
|
cwd: options.cwd,
|
|
@@ -181,14 +116,14 @@ export function nextBuild(options = {}) {
|
|
|
181
116
|
};
|
|
182
117
|
}
|
|
183
118
|
|
|
184
|
-
|
|
119
|
+
function nodeApp(options = {}) {
|
|
185
120
|
const {
|
|
186
121
|
baseUrl: explicitBaseUrl,
|
|
187
122
|
build: explicitBuild,
|
|
188
123
|
buildInputs,
|
|
189
124
|
cwd = ".",
|
|
190
125
|
entry = "src/index.ts",
|
|
191
|
-
env
|
|
126
|
+
env,
|
|
192
127
|
envFiles,
|
|
193
128
|
outDir = "dist",
|
|
194
129
|
port,
|
|
@@ -202,7 +137,8 @@ export function nodeApp(options = {}) {
|
|
|
202
137
|
...serviceConfig
|
|
203
138
|
} = options;
|
|
204
139
|
|
|
205
|
-
const normalizedPort = requiredNumber(port, "
|
|
140
|
+
const normalizedPort = requiredNumber(port, "app.node port");
|
|
141
|
+
const normalizedEnv = normalizePresetEnv(env);
|
|
206
142
|
const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
|
|
207
143
|
const build = explicitBuild === undefined ? tscBuild({
|
|
208
144
|
cwd,
|
|
@@ -228,12 +164,12 @@ export function nodeApp(options = {}) {
|
|
|
228
164
|
baseUrl,
|
|
229
165
|
readyUrl: explicitReadyUrl || `${baseUrl}${readyPath}`,
|
|
230
166
|
readyTimeoutMs,
|
|
231
|
-
env,
|
|
167
|
+
env: normalizedEnv,
|
|
232
168
|
},
|
|
233
169
|
};
|
|
234
170
|
}
|
|
235
171
|
|
|
236
|
-
|
|
172
|
+
function nextApp(options = {}) {
|
|
237
173
|
const {
|
|
238
174
|
baseUrl: explicitBaseUrl,
|
|
239
175
|
browser,
|
|
@@ -241,7 +177,7 @@ export function nextApp(options = {}) {
|
|
|
241
177
|
buildInputs,
|
|
242
178
|
cwd = ".",
|
|
243
179
|
dependsOn,
|
|
244
|
-
env
|
|
180
|
+
env,
|
|
245
181
|
envFiles,
|
|
246
182
|
mode = "dev",
|
|
247
183
|
port,
|
|
@@ -253,7 +189,8 @@ export function nextApp(options = {}) {
|
|
|
253
189
|
...serviceConfig
|
|
254
190
|
} = options;
|
|
255
191
|
|
|
256
|
-
const normalizedPort = requiredNumber(port, "
|
|
192
|
+
const normalizedPort = requiredNumber(port, "app.next port");
|
|
193
|
+
const normalizedEnv = normalizePresetEnv(env);
|
|
257
194
|
const baseUrl = explicitBaseUrl || "http://127.0.0.1:{port}";
|
|
258
195
|
const build =
|
|
259
196
|
explicitBuild === undefined
|
|
@@ -286,82 +223,54 @@ export function nextApp(options = {}) {
|
|
|
286
223
|
readyTimeoutMs,
|
|
287
224
|
env: mode === "start"
|
|
288
225
|
? {
|
|
289
|
-
NEXT_DIST_DIR:
|
|
290
|
-
NEXT_TSCONFIG_PATH:
|
|
291
|
-
|
|
226
|
+
NEXT_DIST_DIR: normalizedEnv.NEXT_DIST_DIR || ".next-testkit/{runtimeId}/dist",
|
|
227
|
+
NEXT_TSCONFIG_PATH:
|
|
228
|
+
normalizedEnv.NEXT_TSCONFIG_PATH || ".next-testkit/{runtimeId}/tsconfig.json",
|
|
229
|
+
...normalizedEnv,
|
|
292
230
|
}
|
|
293
|
-
:
|
|
231
|
+
: normalizedEnv,
|
|
294
232
|
},
|
|
295
233
|
};
|
|
296
234
|
}
|
|
297
235
|
|
|
298
|
-
export
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
return defineHttpProfile({
|
|
304
|
-
auth: {
|
|
305
|
-
setup() {
|
|
306
|
-
return resolveClerkSession({
|
|
307
|
-
apiBase,
|
|
308
|
-
secretKey: envValue(secretKeyEnv),
|
|
309
|
-
needsAuth,
|
|
310
|
-
});
|
|
311
|
-
},
|
|
312
|
-
headers(setupData) {
|
|
313
|
-
return getClerkAuthHeaders(setupData, { apiBase });
|
|
314
|
-
},
|
|
315
|
-
},
|
|
316
|
-
});
|
|
317
|
-
}
|
|
236
|
+
export const app = {
|
|
237
|
+
node: nodeApp,
|
|
238
|
+
next: nextApp,
|
|
239
|
+
};
|
|
318
240
|
|
|
319
|
-
export
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
cookie,
|
|
353
|
-
body: safeJson(res),
|
|
354
|
-
};
|
|
355
|
-
},
|
|
356
|
-
headers(session) {
|
|
357
|
-
if (!session?.cookie) return {};
|
|
358
|
-
return {
|
|
359
|
-
Cookie: `${cookieName}=${session.cookie}`,
|
|
360
|
-
};
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
}
|
|
241
|
+
export const database = {
|
|
242
|
+
postgres(options = {}) {
|
|
243
|
+
const { template, ...databaseOptions } = options;
|
|
244
|
+
for (const legacyKey of ["inputs", "schema", "migrate", "seed", "verify"]) {
|
|
245
|
+
if (Object.prototype.hasOwnProperty.call(options, legacyKey)) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
`database.postgres(...) no longer accepts top-level "${legacyKey}". Move lifecycle config under database.postgres({ template: { ... } }).`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return postgresDatabase(
|
|
252
|
+
template
|
|
253
|
+
? {
|
|
254
|
+
...databaseOptions,
|
|
255
|
+
template: buildDatabaseTemplateConfig(template),
|
|
256
|
+
}
|
|
257
|
+
: databaseOptions
|
|
258
|
+
);
|
|
259
|
+
},
|
|
260
|
+
fixture: postgresFixture,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
export const toolchain = {
|
|
264
|
+
node: nodeToolchain,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export const profiles = {
|
|
268
|
+
custom: customProfile,
|
|
269
|
+
localJson: localJsonProfile,
|
|
270
|
+
multiActor: multiActorProfile,
|
|
271
|
+
raw: rawProfile,
|
|
272
|
+
session: sessionProfile,
|
|
273
|
+
};
|
|
365
274
|
|
|
366
275
|
export {
|
|
367
276
|
clearRepoConfig,
|
|
@@ -381,6 +290,58 @@ function requiredNumber(value, label) {
|
|
|
381
290
|
return value;
|
|
382
291
|
}
|
|
383
292
|
|
|
293
|
+
function normalizePresetEnv(env) {
|
|
294
|
+
if (!env) return {};
|
|
295
|
+
if (typeof env !== "object" || Array.isArray(env)) {
|
|
296
|
+
throw new Error("Preset env must be an object");
|
|
297
|
+
}
|
|
298
|
+
const allowedKeys = new Set(["values", "databases"]);
|
|
299
|
+
const unexpectedKeys = Object.keys(env).filter((key) => !allowedKeys.has(key));
|
|
300
|
+
if (unexpectedKeys.length > 0) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`Preset env only supports "values" and "databases". Received unexpected key(s): ${unexpectedKeys.join(", ")}`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const values = env.values && typeof env.values === "object" && !Array.isArray(env.values) ? env.values : {};
|
|
307
|
+
const databases =
|
|
308
|
+
env.databases && typeof env.databases === "object" && !Array.isArray(env.databases) ? env.databases : {};
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
...expandDatabaseBindings(databases),
|
|
312
|
+
...values,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function expandDatabaseBindings(bindings) {
|
|
317
|
+
const env = {};
|
|
318
|
+
for (const [name, binding] of Object.entries(bindings || {})) {
|
|
319
|
+
if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
|
|
320
|
+
throw new Error(`env.databases.${name} must be an object`);
|
|
321
|
+
}
|
|
322
|
+
const prefix = normalizeDatabaseEnvToken(binding.prefix, `env.databases.${name}.prefix`);
|
|
323
|
+
const serviceName = normalizeDatabaseEnvToken(binding.service, `env.databases.${name}.service`, false);
|
|
324
|
+
env[`${prefix}_DATABASE_HOST`] = `{dbHost:${serviceName}}`;
|
|
325
|
+
env[`${prefix}_DATABASE_PORT`] = `{dbPort:${serviceName}}`;
|
|
326
|
+
env[`${prefix}_DATABASE_NAME`] = `{dbName:${serviceName}}`;
|
|
327
|
+
env[`${prefix}_DATABASE_USER`] = `{dbUser:${serviceName}}`;
|
|
328
|
+
env[`${prefix}_DATABASE_PASSWORD`] = `{dbPassword:${serviceName}}`;
|
|
329
|
+
env[`${prefix}_DATABASE_SSL`] = "0";
|
|
330
|
+
}
|
|
331
|
+
return env;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function normalizeDatabaseEnvToken(value, label, sanitize = true) {
|
|
335
|
+
const raw = String(value || "").trim();
|
|
336
|
+
const normalized = sanitize
|
|
337
|
+
? raw.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "")
|
|
338
|
+
: raw;
|
|
339
|
+
if (!normalized) {
|
|
340
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
341
|
+
}
|
|
342
|
+
return normalized;
|
|
343
|
+
}
|
|
344
|
+
|
|
384
345
|
function resolveNodeAppStart(build, entry) {
|
|
385
346
|
if (build?.kind === "tsc") {
|
|
386
347
|
const compiled = compiledEntryFromSource(entry || build.entry || "src/index.ts", build.outDir || "dist");
|
|
@@ -397,7 +358,10 @@ function normalizeTemplateStepList(value) {
|
|
|
397
358
|
function normalizeSchemaStep(value) {
|
|
398
359
|
if (value == null) return null;
|
|
399
360
|
if (typeof value === "string") {
|
|
400
|
-
return
|
|
361
|
+
return {
|
|
362
|
+
kind: "sql-file",
|
|
363
|
+
path: value,
|
|
364
|
+
};
|
|
401
365
|
}
|
|
402
366
|
return value;
|
|
403
367
|
}
|
|
@@ -408,101 +372,3 @@ function compiledEntryFromSource(entry, outDir) {
|
|
|
408
372
|
const relative = compiled.startsWith("src/") ? compiled.slice(4) : compiled;
|
|
409
373
|
return `${outDir}/${relative}`.replace(/\/+/g, "/");
|
|
410
374
|
}
|
|
411
|
-
|
|
412
|
-
function envValue(name) {
|
|
413
|
-
const env = getRuntimeEnv();
|
|
414
|
-
const value = env?.rawEnv?.[name] || env?.[name];
|
|
415
|
-
if (!value) {
|
|
416
|
-
throw new Error(`Missing required env var "${name}" for testkit config`);
|
|
417
|
-
}
|
|
418
|
-
return value;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function safeJson(response) {
|
|
422
|
-
try {
|
|
423
|
-
return runtimeJson(response);
|
|
424
|
-
} catch {
|
|
425
|
-
return null;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
function resolveClerkSession({ apiBase, secretKey, needsAuth }) {
|
|
430
|
-
if (!needsAuth) {
|
|
431
|
-
return { jwt: null };
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const headers = { Authorization: `Bearer ${secretKey}` };
|
|
435
|
-
const usersRes = runtimeHttp.get(`${apiBase}/users?limit=1&order_by=-created_at`, {
|
|
436
|
-
headers,
|
|
437
|
-
});
|
|
438
|
-
if (usersRes.status !== 200) {
|
|
439
|
-
throw new Error(`Clerk list users failed (${usersRes.status}): ${usersRes.body}`);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const users = runtimeJson(usersRes);
|
|
443
|
-
if (!users.length) {
|
|
444
|
-
throw new Error("No Clerk users found for testkit Clerk auth profile");
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
const userId = users[0].id;
|
|
448
|
-
const sessionsRes = runtimeHttp.get(
|
|
449
|
-
`${apiBase}/sessions?user_id=${userId}&status=active&limit=1`,
|
|
450
|
-
{ headers }
|
|
451
|
-
);
|
|
452
|
-
if (sessionsRes.status !== 200) {
|
|
453
|
-
throw new Error(`Clerk list sessions failed (${sessionsRes.status}): ${sessionsRes.body}`);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const sessions = runtimeJson(sessionsRes);
|
|
457
|
-
if (!sessions?.length) {
|
|
458
|
-
throw new Error("No active Clerk session found for testkit Clerk auth profile");
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const sessionId = sessions[0].id;
|
|
462
|
-
const tokenRes = runtimeHttp.post(`${apiBase}/sessions/${sessionId}/tokens`, null, {
|
|
463
|
-
headers: {
|
|
464
|
-
...headers,
|
|
465
|
-
"Content-Type": "application/json",
|
|
466
|
-
},
|
|
467
|
-
});
|
|
468
|
-
if (tokenRes.status !== 200) {
|
|
469
|
-
throw new Error(`Clerk create token failed (${tokenRes.status}): ${tokenRes.body}`);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return {
|
|
473
|
-
jwt: runtimeJson(tokenRes).jwt,
|
|
474
|
-
sessionId,
|
|
475
|
-
secretKey,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function getClerkAuthHeaders(setupData, { apiBase }) {
|
|
480
|
-
if (!setupData?.jwt) return {};
|
|
481
|
-
|
|
482
|
-
if (!setupData.sessionId || !setupData.secretKey) {
|
|
483
|
-
return {
|
|
484
|
-
Authorization: `Bearer ${setupData.jwt}`,
|
|
485
|
-
"Content-Type": "application/json",
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const tokenRes = runtimeHttp.post(`${apiBase}/sessions/${setupData.sessionId}/tokens`, null, {
|
|
490
|
-
headers: {
|
|
491
|
-
Authorization: `Bearer ${setupData.secretKey}`,
|
|
492
|
-
"Content-Type": "application/json",
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
if (tokenRes.status !== 200) {
|
|
496
|
-
return {
|
|
497
|
-
Authorization: `Bearer ${setupData.jwt}`,
|
|
498
|
-
"Content-Type": "application/json",
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
const nextJwt = runtimeJson(tokenRes).jwt;
|
|
503
|
-
setupData.jwt = nextJwt;
|
|
504
|
-
return {
|
|
505
|
-
Authorization: `Bearer ${nextJwt}`,
|
|
506
|
-
"Content-Type": "application/json",
|
|
507
|
-
};
|
|
508
|
-
}
|