@open-mercato/core 0.6.8-develop.7046.1.153faed87a → 0.6.8-develop.7047.1.32ab5fcb07
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.
|
@@ -91,7 +91,9 @@ async function postForm(request, path, data, options) {
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
async function withCredentialIsolatedRequest(use) {
|
|
94
|
-
const context = await playwrightRequest.newContext(
|
|
94
|
+
const context = await playwrightRequest.newContext({
|
|
95
|
+
baseURL: BASE_URL ?? "http://localhost:3000"
|
|
96
|
+
});
|
|
95
97
|
try {
|
|
96
98
|
return await use(context);
|
|
97
99
|
} finally {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/helpers/integration/api.ts"],
|
|
4
|
-
"sourcesContent": ["import { request as playwrightRequest, type APIRequestContext } from '@playwright/test';\nimport { DEFAULT_CREDENTIALS, type Role } from './auth';\n\nconst BASE_URL = process.env.BASE_URL?.trim() || null;\n\nfunction resolveUrl(path: string): string {\n return BASE_URL ? `${BASE_URL}${path}` : path;\n}\n\n// Cached tokens per credential to dodge the login rate limit\n// (5 attempts/60s per email). Tokens are reused across tests in the same\n// Playwright worker; each worker still mints its own.\nconst tokenCache = new Map<string, { token: string; mintedAt: number }>();\nconst TOKEN_TTL_MS = 45 * 60 * 1000; // 45 min; well under the default 2h session TTL.\n\n/**\n * Drops cached tokens so the next getAuthToken() mints a fresh session.\n *\n * A cached token points at a `sessions` row. Anything that deletes those rows \u2014\n * deactivating the user, a password change, an explicit session purge \u2014 leaves the\n * cached token resolving to 401 for the rest of the TTL, and `apiRequest` neither\n * retries nor re-mints. A spec that revokes sessions for an account other specs also\n * use MUST call this afterwards.\n */\nexport function clearAuthTokenCache(): void {\n tokenCache.clear();\n}\n\nexport async function getAuthToken(\n request: APIRequestContext,\n roleOrEmail: Role | string = 'admin',\n password?: string,\n): Promise<string> {\n const role = roleOrEmail in DEFAULT_CREDENTIALS ? (roleOrEmail as Role) : null;\n const credentialAttempts: Array<{ email: string; password: string }> = [];\n\n if (role) {\n const configured = DEFAULT_CREDENTIALS[role];\n credentialAttempts.push({ email: configured.email, password: password ?? configured.password });\n if (!password) {\n credentialAttempts.push({ email: `${role}@acme.com`, password: 'secret' });\n }\n } else {\n credentialAttempts.push({ email: roleOrEmail, password: password ?? 'secret' });\n }\n\n const cacheKey = credentialAttempts\n .map((entry) => `${entry.email}:${entry.password}`)\n .join('|');\n const cached = tokenCache.get(cacheKey);\n if (cached && Date.now() - cached.mintedAt < TOKEN_TTL_MS) {\n return cached.token;\n }\n\n let lastStatus = 0;\n\n for (const attempt of credentialAttempts) {\n const form = new URLSearchParams();\n form.set('email', attempt.email);\n form.set('password', attempt.password);\n\n // Retry on 429 (auth rate limit kicks in after ~25-30 rapid attempts from\n // the same test run). Capped exponential backoff: 1s, 2s, 4s; 3 retries.\n for (let retry = 0; retry < 4; retry += 1) {\n const response = await request.post(resolveUrl('/api/auth/login'), {\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n },\n data: form.toString(),\n });\n\n const raw = await response.text();\n let body: Record<string, unknown> | null = null;\n try {\n body = raw ? (JSON.parse(raw) as Record<string, unknown>) : null;\n } catch {\n body = null;\n }\n\n lastStatus = response.status();\n if (response.ok() && body && typeof body.token === 'string' && body.token) {\n tokenCache.set(cacheKey, { token: body.token, mintedAt: Date.now() });\n return body.token;\n }\n if (response.status() !== 429) break;\n const backoffMs = 1000 * 2 ** retry;\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n }\n\n throw new Error(`Failed to obtain auth token (status ${lastStatus})`);\n}\n\nexport async function apiRequest(\n request: APIRequestContext,\n method: string,\n path: string,\n options: {\n token: string;\n data?: unknown;\n timeout?: number;\n retryTransport?: boolean;\n headers?: Record<string, string>;\n },\n) {\n const headers = {\n Authorization: `Bearer ${options.token}`,\n 'Content-Type': 'application/json',\n ...(options.headers ?? {}),\n };\n const timeout = options.timeout ?? 30_000;\n let lastError: unknown = null;\n const maxAttempts = options.retryTransport === false ? 1 : 2;\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n return await request.fetch(resolveUrl(path), { method, headers, data: options.data, timeout });\n } catch (error) {\n lastError = error;\n const message = error instanceof Error ? error.message : '';\n const retryable = /timeout|idle-session|socket|ECONNRESET|Target page, context or browser has been closed/i.test(message);\n if (!retryable || attempt === maxAttempts - 1) throw error;\n await new Promise((resolve) => setTimeout(resolve, 250));\n }\n }\n throw lastError;\n}\n\nexport async function postForm(\n request: APIRequestContext,\n path: string,\n data: Record<string, string>,\n options?: { headers?: Record<string, string> },\n) {\n const form = new URLSearchParams();\n for (const [key, value] of Object.entries(data)) form.set(key, value);\n return request.post(resolveUrl(path), {\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n ...(options?.headers ?? {}),\n },\n data: form.toString(),\n });\n}\n\n/**\n * Runs `use` against a request context that shares no cookies with the caller's.\n *\n * The `request` fixture keeps a cookie jar, and `/api/auth/login` sets `auth_token`\n * on it. Every later call through that fixture therefore carries the LAST logged-in\n * user's session, even one that deliberately sends no Authorization header or an\n * `ApiKey` one
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { request as playwrightRequest, type APIRequestContext } from '@playwright/test';\nimport { DEFAULT_CREDENTIALS, type Role } from './auth';\n\nconst BASE_URL = process.env.BASE_URL?.trim() || null;\n\nfunction resolveUrl(path: string): string {\n return BASE_URL ? `${BASE_URL}${path}` : path;\n}\n\n// Cached tokens per credential to dodge the login rate limit\n// (5 attempts/60s per email). Tokens are reused across tests in the same\n// Playwright worker; each worker still mints its own.\nconst tokenCache = new Map<string, { token: string; mintedAt: number }>();\nconst TOKEN_TTL_MS = 45 * 60 * 1000; // 45 min; well under the default 2h session TTL.\n\n/**\n * Drops cached tokens so the next getAuthToken() mints a fresh session.\n *\n * A cached token points at a `sessions` row. Anything that deletes those rows \u2014\n * deactivating the user, a password change, an explicit session purge \u2014 leaves the\n * cached token resolving to 401 for the rest of the TTL, and `apiRequest` neither\n * retries nor re-mints. A spec that revokes sessions for an account other specs also\n * use MUST call this afterwards.\n */\nexport function clearAuthTokenCache(): void {\n tokenCache.clear();\n}\n\nexport async function getAuthToken(\n request: APIRequestContext,\n roleOrEmail: Role | string = 'admin',\n password?: string,\n): Promise<string> {\n const role = roleOrEmail in DEFAULT_CREDENTIALS ? (roleOrEmail as Role) : null;\n const credentialAttempts: Array<{ email: string; password: string }> = [];\n\n if (role) {\n const configured = DEFAULT_CREDENTIALS[role];\n credentialAttempts.push({ email: configured.email, password: password ?? configured.password });\n if (!password) {\n credentialAttempts.push({ email: `${role}@acme.com`, password: 'secret' });\n }\n } else {\n credentialAttempts.push({ email: roleOrEmail, password: password ?? 'secret' });\n }\n\n const cacheKey = credentialAttempts\n .map((entry) => `${entry.email}:${entry.password}`)\n .join('|');\n const cached = tokenCache.get(cacheKey);\n if (cached && Date.now() - cached.mintedAt < TOKEN_TTL_MS) {\n return cached.token;\n }\n\n let lastStatus = 0;\n\n for (const attempt of credentialAttempts) {\n const form = new URLSearchParams();\n form.set('email', attempt.email);\n form.set('password', attempt.password);\n\n // Retry on 429 (auth rate limit kicks in after ~25-30 rapid attempts from\n // the same test run). Capped exponential backoff: 1s, 2s, 4s; 3 retries.\n for (let retry = 0; retry < 4; retry += 1) {\n const response = await request.post(resolveUrl('/api/auth/login'), {\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n },\n data: form.toString(),\n });\n\n const raw = await response.text();\n let body: Record<string, unknown> | null = null;\n try {\n body = raw ? (JSON.parse(raw) as Record<string, unknown>) : null;\n } catch {\n body = null;\n }\n\n lastStatus = response.status();\n if (response.ok() && body && typeof body.token === 'string' && body.token) {\n tokenCache.set(cacheKey, { token: body.token, mintedAt: Date.now() });\n return body.token;\n }\n if (response.status() !== 429) break;\n const backoffMs = 1000 * 2 ** retry;\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n }\n\n throw new Error(`Failed to obtain auth token (status ${lastStatus})`);\n}\n\nexport async function apiRequest(\n request: APIRequestContext,\n method: string,\n path: string,\n options: {\n token: string;\n data?: unknown;\n timeout?: number;\n retryTransport?: boolean;\n headers?: Record<string, string>;\n },\n) {\n const headers = {\n Authorization: `Bearer ${options.token}`,\n 'Content-Type': 'application/json',\n ...(options.headers ?? {}),\n };\n const timeout = options.timeout ?? 30_000;\n let lastError: unknown = null;\n const maxAttempts = options.retryTransport === false ? 1 : 2;\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n return await request.fetch(resolveUrl(path), { method, headers, data: options.data, timeout });\n } catch (error) {\n lastError = error;\n const message = error instanceof Error ? error.message : '';\n const retryable = /timeout|idle-session|socket|ECONNRESET|Target page, context or browser has been closed/i.test(message);\n if (!retryable || attempt === maxAttempts - 1) throw error;\n await new Promise((resolve) => setTimeout(resolve, 250));\n }\n }\n throw lastError;\n}\n\nexport async function postForm(\n request: APIRequestContext,\n path: string,\n data: Record<string, string>,\n options?: { headers?: Record<string, string> },\n) {\n const form = new URLSearchParams();\n for (const [key, value] of Object.entries(data)) form.set(key, value);\n return request.post(resolveUrl(path), {\n headers: {\n 'content-type': 'application/x-www-form-urlencoded',\n ...(options?.headers ?? {}),\n },\n data: form.toString(),\n });\n}\n\n/**\n * Runs `use` against a request context that shares no cookies with the caller's.\n *\n * The `request` fixture keeps a cookie jar, and `/api/auth/login` sets `auth_token`\n * on it. Every later call through that fixture therefore carries the LAST logged-in\n * user's session, even one that deliberately sends no Authorization header or an\n * `ApiKey` one.\n *\n * A spec asserting \"no credentials are rejected\" or \"this API key alone decides\n * access\" must therefore issue the request from a jar that never saw a login,\n * rather than assuming the fixture's jar is empty. TC-DOCUMENTS-009 and\n * TC-DOCUMENTS-018 both observably failed in the standalone lane \u2014 with the\n * replayed cookie visible in the trace \u2014 while passing in the ephemeral one, and\n * routing them through this helper fixed both.\n */\nexport async function withCredentialIsolatedRequest<T>(\n use: (request: APIRequestContext) => Promise<T>,\n): Promise<T> {\n // A hand-built context does not inherit the project's `use.baseURL` the way the\n // `request` fixture does, so it has to repeat the config's own resolution \u2014 otherwise\n // a relative path throws here on any run that leaves BASE_URL unset, while the same\n // path works through the fixture.\n const context = await playwrightRequest.newContext({\n baseURL: BASE_URL ?? 'http://localhost:3000',\n });\n try {\n return await use(context);\n } finally {\n await context.dispose();\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAW,yBAAiD;AACrE,SAAS,2BAAsC;AAE/C,MAAM,WAAW,QAAQ,IAAI,UAAU,KAAK,KAAK;AAEjD,SAAS,WAAW,MAAsB;AACxC,SAAO,WAAW,GAAG,QAAQ,GAAG,IAAI,KAAK;AAC3C;AAKA,MAAM,aAAa,oBAAI,IAAiD;AACxE,MAAM,eAAe,KAAK,KAAK;AAWxB,SAAS,sBAA4B;AAC1C,aAAW,MAAM;AACnB;AAEA,eAAsB,aACpB,SACA,cAA6B,SAC7B,UACiB;AACjB,QAAM,OAAO,eAAe,sBAAuB,cAAuB;AAC1E,QAAM,qBAAiE,CAAC;AAExE,MAAI,MAAM;AACR,UAAM,aAAa,oBAAoB,IAAI;AAC3C,uBAAmB,KAAK,EAAE,OAAO,WAAW,OAAO,UAAU,YAAY,WAAW,SAAS,CAAC;AAC9F,QAAI,CAAC,UAAU;AACb,yBAAmB,KAAK,EAAE,OAAO,GAAG,IAAI,aAAa,UAAU,SAAS,CAAC;AAAA,IAC3E;AAAA,EACF,OAAO;AACL,uBAAmB,KAAK,EAAE,OAAO,aAAa,UAAU,YAAY,SAAS,CAAC;AAAA,EAChF;AAEA,QAAM,WAAW,mBACd,IAAI,CAAC,UAAU,GAAG,MAAM,KAAK,IAAI,MAAM,QAAQ,EAAE,EACjD,KAAK,GAAG;AACX,QAAM,SAAS,WAAW,IAAI,QAAQ;AACtC,MAAI,UAAU,KAAK,IAAI,IAAI,OAAO,WAAW,cAAc;AACzD,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,aAAa;AAEjB,aAAW,WAAW,oBAAoB;AACxC,UAAM,OAAO,IAAI,gBAAgB;AACjC,SAAK,IAAI,SAAS,QAAQ,KAAK;AAC/B,SAAK,IAAI,YAAY,QAAQ,QAAQ;AAIrC,aAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG;AACzC,YAAM,WAAW,MAAM,QAAQ,KAAK,WAAW,iBAAiB,GAAG;AAAA,QACjE,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,SAAS;AAAA,MACtB,CAAC;AAED,YAAM,MAAM,MAAM,SAAS,KAAK;AAChC,UAAI,OAAuC;AAC3C,UAAI;AACF,eAAO,MAAO,KAAK,MAAM,GAAG,IAAgC;AAAA,MAC9D,QAAQ;AACN,eAAO;AAAA,MACT;AAEA,mBAAa,SAAS,OAAO;AAC7B,UAAI,SAAS,GAAG,KAAK,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,OAAO;AACzE,mBAAW,IAAI,UAAU,EAAE,OAAO,KAAK,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;AACpE,eAAO,KAAK;AAAA,MACd;AACA,UAAI,SAAS,OAAO,MAAM,IAAK;AAC/B,YAAM,YAAY,MAAO,KAAK;AAC9B,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,SAAS,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,uCAAuC,UAAU,GAAG;AACtE;AAEA,eAAsB,WACpB,SACA,QACA,MACA,SAOA;AACA,QAAM,UAAU;AAAA,IACd,eAAe,UAAU,QAAQ,KAAK;AAAA,IACtC,gBAAgB;AAAA,IAChB,GAAI,QAAQ,WAAW,CAAC;AAAA,EAC1B;AACA,QAAM,UAAU,QAAQ,WAAW;AACnC,MAAI,YAAqB;AACzB,QAAM,cAAc,QAAQ,mBAAmB,QAAQ,IAAI;AAC3D,WAAS,UAAU,GAAG,UAAU,aAAa,WAAW,GAAG;AACzD,QAAI;AACF,aAAO,MAAM,QAAQ,MAAM,WAAW,IAAI,GAAG,EAAE,QAAQ,SAAS,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,IAC/F,SAAS,OAAO;AACd,kBAAY;AACZ,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,YAAM,YAAY,0FAA0F,KAAK,OAAO;AACxH,UAAI,CAAC,aAAa,YAAY,cAAc,EAAG,OAAM;AACrD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,IACzD;AAAA,EACF;AACA,QAAM;AACR;AAEA,eAAsB,SACpB,SACA,MACA,MACA,SACA;AACA,QAAM,OAAO,IAAI,gBAAgB;AACjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,EAAG,MAAK,IAAI,KAAK,KAAK;AACpE,SAAO,QAAQ,KAAK,WAAW,IAAI,GAAG;AAAA,IACpC,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,GAAI,SAAS,WAAW,CAAC;AAAA,IAC3B;AAAA,IACA,MAAM,KAAK,SAAS;AAAA,EACtB,CAAC;AACH;AAiBA,eAAsB,8BACpB,KACY;AAKZ,QAAM,UAAU,MAAM,kBAAkB,WAAW;AAAA,IACjD,SAAS,YAAY;AAAA,EACvB,CAAC;AACD,MAAI;AACF,WAAO,MAAM,IAAI,OAAO;AAAA,EAC1B,UAAE;AACA,UAAM,QAAQ,QAAQ;AAAA,EACxB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
256
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
257
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
256
|
+
"@open-mercato/shared": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
257
|
+
"@open-mercato/ui": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
263
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
264
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
263
|
+
"@open-mercato/shared": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
264
|
+
"@open-mercato/ui": "0.6.8-develop.7047.1.32ab5fcb07",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -148,21 +148,25 @@ export async function postForm(
|
|
|
148
148
|
* The `request` fixture keeps a cookie jar, and `/api/auth/login` sets `auth_token`
|
|
149
149
|
* on it. Every later call through that fixture therefore carries the LAST logged-in
|
|
150
150
|
* user's session, even one that deliberately sends no Authorization header or an
|
|
151
|
-
* `ApiKey` one.
|
|
152
|
-
* the login route marks it `secure` only when `NODE_ENV === 'production'`, so a lane
|
|
153
|
-
* that serves the app with any other NODE_ENV over http keeps it while a production
|
|
154
|
-
* lane silently drops it.
|
|
151
|
+
* `ApiKey` one.
|
|
155
152
|
*
|
|
156
153
|
* A spec asserting "no credentials are rejected" or "this API key alone decides
|
|
157
|
-
* access" must
|
|
158
|
-
*
|
|
159
|
-
* both failed in the standalone lane
|
|
160
|
-
* ephemeral one
|
|
154
|
+
* access" must therefore issue the request from a jar that never saw a login,
|
|
155
|
+
* rather than assuming the fixture's jar is empty. TC-DOCUMENTS-009 and
|
|
156
|
+
* TC-DOCUMENTS-018 both observably failed in the standalone lane — with the
|
|
157
|
+
* replayed cookie visible in the trace — while passing in the ephemeral one, and
|
|
158
|
+
* routing them through this helper fixed both.
|
|
161
159
|
*/
|
|
162
160
|
export async function withCredentialIsolatedRequest<T>(
|
|
163
161
|
use: (request: APIRequestContext) => Promise<T>,
|
|
164
162
|
): Promise<T> {
|
|
165
|
-
|
|
163
|
+
// A hand-built context does not inherit the project's `use.baseURL` the way the
|
|
164
|
+
// `request` fixture does, so it has to repeat the config's own resolution — otherwise
|
|
165
|
+
// a relative path throws here on any run that leaves BASE_URL unset, while the same
|
|
166
|
+
// path works through the fixture.
|
|
167
|
+
const context = await playwrightRequest.newContext({
|
|
168
|
+
baseURL: BASE_URL ?? 'http://localhost:3000',
|
|
169
|
+
});
|
|
166
170
|
try {
|
|
167
171
|
return await use(context);
|
|
168
172
|
} finally {
|