@theaiplatform/miniapp-sdk 0.3.2 → 0.3.3
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 +27 -0
- package/dist/index.d.ts +26 -0
- package/dist/rspack/index.js +23 -1
- package/dist/sdk.d.ts +26 -0
- package/dist/testing/rstest.d.ts +1 -0
- package/dist/testing/rstest.js +161 -86
- package/dist/ui/styles.css +504 -6
- package/dist/ui/wasm.js +9229 -509
- package/dist/ui/wasm.js.LICENSE.txt +12 -0
- package/dist/ui.js +9491 -539
- package/dist/ui.js.LICENSE.txt +12 -0
- package/dist/vscode-webview.d.ts +133 -0
- package/dist/vscode-webview.js +594 -0
- package/dist/web.d.ts +26 -0
- package/package.json +14 -10
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ Start with the [Miniapp SDK documentation](https://docs.theaiplatform.app/miniap
|
|
|
25
25
|
- `@theaiplatform/miniapp-sdk/ui/tailwind.css`
|
|
26
26
|
- `@theaiplatform/miniapp-sdk/ui-components.json`
|
|
27
27
|
- `@theaiplatform/miniapp-sdk/surface`
|
|
28
|
+
- `@theaiplatform/miniapp-sdk/vscode-webview`
|
|
28
29
|
- `@theaiplatform/miniapp-sdk/config`
|
|
29
30
|
- `@theaiplatform/miniapp-sdk/rspack`
|
|
30
31
|
- `@theaiplatform/miniapp-sdk/testing/rstest`
|
|
@@ -60,6 +61,32 @@ requests through host consent instead of browser `fetch`, and
|
|
|
60
61
|
secrets remain in the host vault and are injected only by the native request
|
|
61
62
|
authority.
|
|
62
63
|
|
|
64
|
+
## Converted VS Code webviews in 0.3.3
|
|
65
|
+
|
|
66
|
+
The `/vscode-webview` entry point mounts a converted, static VS Code webview in
|
|
67
|
+
a sandboxed iframe while keeping platform authority in the outer federated
|
|
68
|
+
surface. Declarative message bindings persist document data through
|
|
69
|
+
`sdk.storage`; the synchronous `localStorage` compatibility facade is backed by
|
|
70
|
+
`sdk.session`, so standalone and channel surfaces share sign-in only for the
|
|
71
|
+
same account, workspace, installation, and package; and exact HTTPS origins are
|
|
72
|
+
mediated through `sdk.http`. The bridge does not expose the host transport, and
|
|
73
|
+
undeclared origins fail closed.
|
|
74
|
+
|
|
75
|
+
Conversion tools should emit `tapVsCodeWebviewRuntimeSource` beside the imported
|
|
76
|
+
assets and call `mountVsCodeWebview` from the generated surface. The SDK owns
|
|
77
|
+
this compatibility boundary so conversion recipes describe mappings rather
|
|
78
|
+
than introducing a second miniapp data plane. TAP's package CSP permits only
|
|
79
|
+
same-origin external scripts and forbids `<base>`, so converters must
|
|
80
|
+
externalize executable inline scripts. The bridge resolves document resource
|
|
81
|
+
URLs against the original entry before mounting and exposes the immutable
|
|
82
|
+
`window.__TAP_VSCODE_WEBVIEW_ASSET_BASE_URL__` value for reviewed replacements
|
|
83
|
+
of extension-specific asset-root placeholders.
|
|
84
|
+
|
|
85
|
+
In Surface Test Lab runs, `sdk.http` uses the run's exact-origin policy and the
|
|
86
|
+
same bounded native transport, while stored credentials remain unavailable.
|
|
87
|
+
That origin list governs host-mediated SDK requests; it is not a browser-wide
|
|
88
|
+
network sandbox for trusted Playwright test code.
|
|
89
|
+
|
|
63
90
|
`sdk.printing` is an optional desktop-only receipt printer API. It discovers
|
|
64
91
|
bounded machine-local printer metadata and host-supported 58 mm and 80 mm paper
|
|
65
92
|
profiles, then accepts only bounded semantic version-1 receipt rows with
|
package/dist/index.d.ts
CHANGED
|
@@ -348,6 +348,7 @@ export declare type MiniAppPlatformApi = {
|
|
|
348
348
|
};
|
|
349
349
|
chat: MiniAppChatApi;
|
|
350
350
|
storage: MiniAppStorageApi;
|
|
351
|
+
session: MiniAppSessionApi;
|
|
351
352
|
presence: MiniAppPresenceApi;
|
|
352
353
|
/** Desktop host capability; feature-detect before use on portable targets. */
|
|
353
354
|
http?: MiniAppHttpApi;
|
|
@@ -507,6 +508,31 @@ export declare type MiniAppReceiptTextAlignment = 'left' | 'center' | 'right';
|
|
|
507
508
|
|
|
508
509
|
export declare type MiniAppReceiptTextWeight = 'normal' | 'bold';
|
|
509
510
|
|
|
511
|
+
/**
|
|
512
|
+
* Secure session storage backed by the operating system credential store.
|
|
513
|
+
*
|
|
514
|
+
* The host derives the signed-in TAP account, active workspace, installation,
|
|
515
|
+
* and package from the authenticated frame. Channel, surface, document, and
|
|
516
|
+
* release are deliberately excluded, so every surface of one installed
|
|
517
|
+
* miniapp shares the same session only within a workspace and package updates
|
|
518
|
+
* retain it. Unlike host-managed HTTP credentials, values returned here enter
|
|
519
|
+
* miniapp JavaScript.
|
|
520
|
+
*/
|
|
521
|
+
export declare type MiniAppSessionApi = {
|
|
522
|
+
get(): MiniAppMaybePromise<MiniAppSessionEntry>;
|
|
523
|
+
set(value: MiniAppSessionValue): MiniAppMaybePromise<void>;
|
|
524
|
+
clear(): MiniAppMaybePromise<void>;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
export declare type MiniAppSessionEntry = {
|
|
528
|
+
/** Null means that no session value currently exists for this installation. */
|
|
529
|
+
value: MiniAppSessionValue | null;
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
export declare type MiniAppSessionValue = {
|
|
533
|
+
[key: string]: MiniAppJsonValue;
|
|
534
|
+
};
|
|
535
|
+
|
|
510
536
|
export declare type MiniAppSpecialistApi = {
|
|
511
537
|
joinToChannel(channelId: string, specialistId: string): MiniAppMaybePromise<string>;
|
|
512
538
|
listWorkspace(workspaceId: string): MiniAppMaybePromise<MiniAppSpecialistSummary[]>;
|
package/dist/rspack/index.js
CHANGED
|
@@ -320,7 +320,7 @@ const TAP_FEDERATED_SURFACE_HTML = `<!doctype html>
|
|
|
320
320
|
<head>
|
|
321
321
|
<meta charset="utf-8">
|
|
322
322
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
323
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'self'; worker-src 'self' blob:; object-src 'none'; base-uri 'none'; form-action 'none'">
|
|
323
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'self'; worker-src 'self' blob:; object-src 'none'; base-uri 'none'; form-action 'none'">
|
|
324
324
|
<title>TAP mini app</title>
|
|
325
325
|
<style>html,body,#tap-root{height:100%;width:100%;margin:0}body{overflow:hidden;background:transparent}#tap-error{box-sizing:border-box;display:none;min-height:100%;padding:24px;font:14px/1.5 system-ui,sans-serif;color:#b42318;background:#fff}</style>
|
|
326
326
|
</head>
|
|
@@ -452,6 +452,7 @@ const MAX_CHECKPOINT_JSON_BYTES = 32 * 1024;
|
|
|
452
452
|
const MAX_STORAGE_NAMESPACE_CHARS = 128;
|
|
453
453
|
const MAX_STORAGE_KEY_CHARS = 512;
|
|
454
454
|
const MAX_STORAGE_JSON_BYTES = 5 * 1024 * 1024;
|
|
455
|
+
const MAX_SESSION_JSON_BYTES = 1_800;
|
|
455
456
|
const MAX_PRESENCE_ROOM_CHARS = 256;
|
|
456
457
|
const MAX_PRESENCE_JSON_BYTES = 16 * 1024;
|
|
457
458
|
const MAX_HTTP_REQUEST_JSON_BYTES = 11 * 1024 * 1024;
|
|
@@ -736,6 +737,26 @@ const storage = Object.freeze({
|
|
|
736
737
|
return invokeSdkHostAction('tap.platform.storage.delete', options, 'app.storage.delete');
|
|
737
738
|
},
|
|
738
739
|
});
|
|
740
|
+
const session = Object.freeze({
|
|
741
|
+
get() {
|
|
742
|
+
return invokeSdkHostAction('tap.platform.session.get', {}, 'app.session.get');
|
|
743
|
+
},
|
|
744
|
+
set(value) {
|
|
745
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
746
|
+
throw new Error('app.session.set requires a JSON object.');
|
|
747
|
+
}
|
|
748
|
+
checkedPlatformJson(value, MAX_SESSION_JSON_BYTES, 'app.session.set value');
|
|
749
|
+
return invokeSdkHostAction(
|
|
750
|
+
'tap.platform.session.set',
|
|
751
|
+
{ value },
|
|
752
|
+
'app.session.set',
|
|
753
|
+
12000,
|
|
754
|
+
);
|
|
755
|
+
},
|
|
756
|
+
clear() {
|
|
757
|
+
return invokeSdkHostAction('tap.platform.session.clear', {}, 'app.session.clear');
|
|
758
|
+
},
|
|
759
|
+
});
|
|
739
760
|
const checkedPresenceAddress = (options, label) => {
|
|
740
761
|
requireOptionsObject(options, label);
|
|
741
762
|
if (!validPlatformPartition(options.namespace, MAX_STORAGE_NAMESPACE_CHARS)) {
|
|
@@ -1692,6 +1713,7 @@ const miniappSdk = Object.freeze({
|
|
|
1692
1713
|
navigation,
|
|
1693
1714
|
chat: miniappChat,
|
|
1694
1715
|
storage,
|
|
1716
|
+
session,
|
|
1695
1717
|
presence,
|
|
1696
1718
|
http,
|
|
1697
1719
|
credentials,
|
package/dist/sdk.d.ts
CHANGED
|
@@ -319,6 +319,7 @@ export declare type MiniAppPlatformApi = {
|
|
|
319
319
|
};
|
|
320
320
|
chat: MiniAppChatApi;
|
|
321
321
|
storage: MiniAppStorageApi;
|
|
322
|
+
session: MiniAppSessionApi;
|
|
322
323
|
presence: MiniAppPresenceApi;
|
|
323
324
|
/** Desktop host capability; feature-detect before use on portable targets. */
|
|
324
325
|
http?: MiniAppHttpApi;
|
|
@@ -478,6 +479,31 @@ export declare type MiniAppReceiptTextAlignment = 'left' | 'center' | 'right';
|
|
|
478
479
|
|
|
479
480
|
export declare type MiniAppReceiptTextWeight = 'normal' | 'bold';
|
|
480
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Secure session storage backed by the operating system credential store.
|
|
484
|
+
*
|
|
485
|
+
* The host derives the signed-in TAP account, active workspace, installation,
|
|
486
|
+
* and package from the authenticated frame. Channel, surface, document, and
|
|
487
|
+
* release are deliberately excluded, so every surface of one installed
|
|
488
|
+
* miniapp shares the same session only within a workspace and package updates
|
|
489
|
+
* retain it. Unlike host-managed HTTP credentials, values returned here enter
|
|
490
|
+
* miniapp JavaScript.
|
|
491
|
+
*/
|
|
492
|
+
export declare type MiniAppSessionApi = {
|
|
493
|
+
get(): MiniAppMaybePromise<MiniAppSessionEntry>;
|
|
494
|
+
set(value: MiniAppSessionValue): MiniAppMaybePromise<void>;
|
|
495
|
+
clear(): MiniAppMaybePromise<void>;
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
export declare type MiniAppSessionEntry = {
|
|
499
|
+
/** Null means that no session value currently exists for this installation. */
|
|
500
|
+
value: MiniAppSessionValue | null;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
export declare type MiniAppSessionValue = {
|
|
504
|
+
[key: string]: MiniAppJsonValue;
|
|
505
|
+
};
|
|
506
|
+
|
|
481
507
|
export declare type MiniAppSpecialistApi = {
|
|
482
508
|
joinToChannel(channelId: string, specialistId: string): MiniAppMaybePromise<string>;
|
|
483
509
|
listWorkspace(workspaceId: string): MiniAppMaybePromise<MiniAppSpecialistSummary[]>;
|
package/dist/testing/rstest.d.ts
CHANGED
|
@@ -80,6 +80,7 @@ export declare type TapMiniappTestControl = {
|
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
export declare type TapMiniappTestFixture = Readonly<Pick<TapMiniappTestSession, 'channelId' | 'dataScope' | 'installationId' | 'localGeneration' | 'mode' | 'packageId' | 'permissionScenario' | 'releaseDigest' | 'runId' | 'sourceDigest' | 'surfaceId' | 'surfaceAssetOrigin' | 'testBundleDigest' | 'workspaceId'> & {
|
|
83
|
+
/** Origins authorized for host-mediated SDK HTTP, not browser-wide egress. */
|
|
83
84
|
readonly allowedNetworkOrigins: readonly string[];
|
|
84
85
|
readonly credentialAliases: readonly string[];
|
|
85
86
|
control: TapMiniappTestControl;
|
package/dist/testing/rstest.js
CHANGED
|
@@ -114,6 +114,97 @@ function fixtureMetadata(session, page) {
|
|
|
114
114
|
function safeArtifactSegment(value) {
|
|
115
115
|
return value.replaceAll(/[^a-zA-Z0-9._-]/g, '-').slice(0, 160);
|
|
116
116
|
}
|
|
117
|
+
const HTTP_PROTOCOLS = new Set([
|
|
118
|
+
'http:',
|
|
119
|
+
'https:'
|
|
120
|
+
]);
|
|
121
|
+
const SAFE_INTERNAL_PROTOCOLS = new Set([
|
|
122
|
+
'about:',
|
|
123
|
+
'blob:',
|
|
124
|
+
'data:'
|
|
125
|
+
]);
|
|
126
|
+
function explicitHttpOrigin(value, label) {
|
|
127
|
+
const url = new URL(value);
|
|
128
|
+
if (!HTTP_PROTOCOLS.has(url.protocol)) throw new Error(`${label} must use HTTP or HTTPS.`);
|
|
129
|
+
return url.origin;
|
|
130
|
+
}
|
|
131
|
+
function allowedHttpOrigins(session) {
|
|
132
|
+
return new Set([
|
|
133
|
+
explicitHttpOrigin(session.pageUrlPrefix, 'TAP host page URL prefix'),
|
|
134
|
+
explicitHttpOrigin(session.surfaceAssetOrigin, 'Surface asset origin'),
|
|
135
|
+
...session.allowedNetworkOrigins.map((value)=>explicitHttpOrigin(value, 'Allowed network origin'))
|
|
136
|
+
]);
|
|
137
|
+
}
|
|
138
|
+
function classifyRequestUrl(value, allowedOrigins) {
|
|
139
|
+
let url;
|
|
140
|
+
try {
|
|
141
|
+
url = new URL(value);
|
|
142
|
+
} catch {
|
|
143
|
+
return {
|
|
144
|
+
action: 'abort',
|
|
145
|
+
reason: 'malformed-url'
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (SAFE_INTERNAL_PROTOCOLS.has(url.protocol)) return {
|
|
149
|
+
action: 'continue',
|
|
150
|
+
reason: 'safe-internal'
|
|
151
|
+
};
|
|
152
|
+
if ('file:' === url.protocol) return {
|
|
153
|
+
action: 'abort',
|
|
154
|
+
reason: 'file-scheme',
|
|
155
|
+
target: 'file:'
|
|
156
|
+
};
|
|
157
|
+
if (!HTTP_PROTOCOLS.has(url.protocol)) return {
|
|
158
|
+
action: 'abort',
|
|
159
|
+
reason: 'unsupported-scheme',
|
|
160
|
+
target: url.protocol.slice(0, 32)
|
|
161
|
+
};
|
|
162
|
+
if (!allowedOrigins.has(url.origin)) return {
|
|
163
|
+
action: 'abort',
|
|
164
|
+
reason: 'origin-not-allowed',
|
|
165
|
+
target: url.origin.slice(0, 256)
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
action: 'continue',
|
|
169
|
+
reason: 'explicit-http-origin'
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function classifyWebSocketUrl(value, allowedOrigins) {
|
|
173
|
+
let url;
|
|
174
|
+
try {
|
|
175
|
+
url = new URL(value);
|
|
176
|
+
} catch {
|
|
177
|
+
return {
|
|
178
|
+
action: 'abort',
|
|
179
|
+
reason: 'malformed-url'
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if ('ws:' !== url.protocol && 'wss:' !== url.protocol) return {
|
|
183
|
+
action: 'abort',
|
|
184
|
+
reason: 'file:' === url.protocol ? 'file-scheme' : 'unsupported-scheme',
|
|
185
|
+
target: url.protocol.slice(0, 32)
|
|
186
|
+
};
|
|
187
|
+
const diagnosticOrigin = url.origin.slice(0, 256);
|
|
188
|
+
url.protocol = 'ws:' === url.protocol ? 'http:' : 'https:';
|
|
189
|
+
if (!allowedOrigins.has(url.origin)) return {
|
|
190
|
+
action: 'abort',
|
|
191
|
+
reason: 'origin-not-allowed',
|
|
192
|
+
target: diagnosticOrigin
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
action: 'continue',
|
|
196
|
+
reason: 'explicit-http-origin'
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function reportUnexpectedWebSocket(webSocket, allowedOrigins) {
|
|
200
|
+
const decision = classifyWebSocketUrl(webSocket.url(), allowedOrigins);
|
|
201
|
+
if ('continue' === decision.action) return;
|
|
202
|
+
const target = decision.target ? ` (${decision.target})` : '';
|
|
203
|
+
process.emitWarning(`TAP Test Lab observed a WebSocket outside the run's SDK HTTP origin set: ${decision.reason}${target}. This check is diagnostic only; TAP does not yet provide native browser-wide egress enforcement.`, {
|
|
204
|
+
code: 'TAP_MINIAPP_TEST_NETWORK_DIAGNOSTIC',
|
|
205
|
+
type: 'Warning'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
117
208
|
const test = __rspack_external__rstest_playwright_5734ff29.test.extend({
|
|
118
209
|
browser: async (_context, use)=>{
|
|
119
210
|
const session = await loadSession();
|
|
@@ -132,78 +223,80 @@ const test = __rspack_external__rstest_playwright_5734ff29.test.extend({
|
|
|
132
223
|
const context = contexts[0];
|
|
133
224
|
if (!context) throw new Error('TAP Browser Driver context selection failed');
|
|
134
225
|
const hostPage = selectPage(context, session);
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
...session.allowedNetworkOrigins.map((value)=>new URL(value).origin)
|
|
140
|
-
]);
|
|
141
|
-
const enforceNetworkPolicy = async (route)=>{
|
|
142
|
-
const url = route.request().url();
|
|
143
|
-
const origin = originOf(url);
|
|
144
|
-
if (void 0 === origin || allowedOrigins.has(origin)) return void await route.continue();
|
|
226
|
+
const allowedOrigins = allowedHttpOrigins(session);
|
|
227
|
+
const enforceDiagnosticNetworkPolicy = async (route)=>{
|
|
228
|
+
const decision = classifyRequestUrl(route.request().url(), allowedOrigins);
|
|
229
|
+
if ('continue' === decision.action) return void await route.continue();
|
|
145
230
|
await route.abort('blockedbyclient');
|
|
146
231
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
recursive: true
|
|
151
|
-
});
|
|
152
|
-
await context.tracing.start({
|
|
153
|
-
screenshots: true,
|
|
154
|
-
snapshots: true,
|
|
155
|
-
sources: true
|
|
156
|
-
});
|
|
232
|
+
const diagnoseWebSocket = (webSocket)=>reportUnexpectedWebSocket(webSocket, allowedOrigins);
|
|
233
|
+
await context.route('**/*', enforceDiagnosticNetworkPolicy);
|
|
234
|
+
hostPage.on('websocket', diagnoseWebSocket);
|
|
157
235
|
try {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
path: (0, __rspack_external_node_path_806ed179.join)(traceDirectory, 'trace.zip')
|
|
236
|
+
const traceDirectory = (0, __rspack_external_node_path_806ed179.join)(session.artifactDirectory, 'traces', safeArtifactSegment(task.id));
|
|
237
|
+
await (0, __rspack_external_node_fs_promises_3b710708.mkdir)(traceDirectory, {
|
|
238
|
+
recursive: true
|
|
162
239
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
'',
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
240
|
+
await context.tracing.start({
|
|
241
|
+
screenshots: true,
|
|
242
|
+
snapshots: true,
|
|
243
|
+
sources: true
|
|
244
|
+
});
|
|
245
|
+
try {
|
|
246
|
+
await use(context);
|
|
247
|
+
} finally{
|
|
248
|
+
await context.tracing.stop({
|
|
249
|
+
path: (0, __rspack_external_node_path_806ed179.join)(traceDirectory, 'trace.zip')
|
|
250
|
+
});
|
|
251
|
+
const traceSummary = {
|
|
252
|
+
schemaVersion: 2,
|
|
253
|
+
runId: session.runId,
|
|
254
|
+
taskId: task.id,
|
|
255
|
+
mode: session.mode,
|
|
256
|
+
dataScope: session.dataScope,
|
|
257
|
+
packageId: session.packageId,
|
|
258
|
+
surfaceId: session.surfaceId,
|
|
259
|
+
sourceDigest: session.sourceDigest,
|
|
260
|
+
testBundleDigest: session.testBundleDigest,
|
|
261
|
+
networkPolicyRole: 'diagnostic-only',
|
|
262
|
+
tracePath: 'trace.zip',
|
|
263
|
+
traceRedacted: false,
|
|
264
|
+
traceSensitivity: 'raw-sensitive',
|
|
265
|
+
traceAccessScope: 'channel-only',
|
|
266
|
+
traceMayContain: [
|
|
267
|
+
'authorization headers',
|
|
268
|
+
'cookies',
|
|
269
|
+
'credential values',
|
|
270
|
+
'network request and response bodies',
|
|
271
|
+
'DOM snapshots',
|
|
272
|
+
'screenshots',
|
|
273
|
+
'test sources'
|
|
274
|
+
]
|
|
275
|
+
};
|
|
276
|
+
await Promise.all([
|
|
277
|
+
(0, __rspack_external_node_fs_promises_3b710708.writeFile)((0, __rspack_external_node_path_806ed179.join)(traceDirectory, 'trace-summary.json'), `${JSON.stringify(traceSummary, void 0, 2)}\n`, 'utf8'),
|
|
278
|
+
(0, __rspack_external_node_fs_promises_3b710708.writeFile)((0, __rspack_external_node_path_806ed179.join)(traceDirectory, 'debug.md'), [
|
|
279
|
+
'# Miniapp test trace',
|
|
280
|
+
'',
|
|
281
|
+
`- Run: \`${session.runId}\``,
|
|
282
|
+
`- Rstest task: \`${task.id}\``,
|
|
283
|
+
`- Mode: \`${session.mode}\``,
|
|
284
|
+
`- Data scope: \`${session.dataScope}\``,
|
|
285
|
+
`- Surface: \`${session.surfaceId}\``,
|
|
286
|
+
`- Source digest: \`${session.sourceDigest}\``,
|
|
287
|
+
`- Test bundle digest: \`${session.testBundleDigest}\``,
|
|
288
|
+
'- Browser network routing: diagnostic-only; not native egress enforcement',
|
|
289
|
+
'',
|
|
290
|
+
'`trace.zip` is raw, sensitive, channel-only evidence. It is not redacted and may contain authorization headers, cookies, credential values, network bodies, DOM snapshots, screenshots, and test source.',
|
|
291
|
+
'',
|
|
292
|
+
'Open the trace from The AI Platform Test Lab for debugging. Do not publish it or attach it to specialist context. The final assertion outcome is authoritative in `report.json` and `report.md`.',
|
|
293
|
+
''
|
|
294
|
+
].join('\n'), 'utf8')
|
|
295
|
+
]);
|
|
296
|
+
}
|
|
297
|
+
} finally{
|
|
298
|
+
hostPage.removeListener('websocket', diagnoseWebSocket);
|
|
299
|
+
await context.unroute('**/*', enforceDiagnosticNetworkPolicy);
|
|
207
300
|
}
|
|
208
301
|
},
|
|
209
302
|
page: async ({ context }, use)=>{
|
|
@@ -224,24 +317,6 @@ const test = __rspack_external__rstest_playwright_5734ff29.test.extend({
|
|
|
224
317
|
});
|
|
225
318
|
const afterEach = __rspack_external__rstest_playwright_5734ff29.afterEach;
|
|
226
319
|
const beforeEach = __rspack_external__rstest_playwright_5734ff29.beforeEach;
|
|
227
|
-
function originOf(value) {
|
|
228
|
-
try {
|
|
229
|
-
const url = new URL(value);
|
|
230
|
-
if (matchesNonNetworkScheme(url.protocol)) return;
|
|
231
|
-
return url.origin;
|
|
232
|
-
} catch {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function matchesNonNetworkScheme(protocol) {
|
|
237
|
-
return NON_NETWORK_PROTOCOLS.has(protocol);
|
|
238
|
-
}
|
|
239
|
-
const NON_NETWORK_PROTOCOLS = new Set([
|
|
240
|
-
'about:',
|
|
241
|
-
'blob:',
|
|
242
|
-
'data:',
|
|
243
|
-
'file:'
|
|
244
|
-
]);
|
|
245
320
|
var afterAll = __rspack_external__rstest_playwright_5734ff29.afterAll;
|
|
246
321
|
var beforeAll = __rspack_external__rstest_playwright_5734ff29.beforeAll;
|
|
247
322
|
var describe = __rspack_external__rstest_playwright_5734ff29.describe;
|