@volter/twin-standard 1.0.156 → 1.0.158
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/client-sdks/import.mjs +2 -0
- package/client-sdks/package.json +3 -0
- package/client-sdks/pnpm-lock.yaml +399 -0
- package/dist/client-sdks/import.mjs +2 -0
- package/dist/client-sdks/package.json +3 -0
- package/dist/client-sdks/pnpm-lock.yaml +399 -0
- package/dist/src/cli.js +11 -11
- package/dist/src/clients/tinybird.js +15 -6
- package/dist/src/clients/vercel.d.ts +2 -0
- package/dist/src/clients/vercel.js +73 -0
- package/dist/src/conformance.js +2 -2
- package/dist/src/walk/serve-pack.d.ts +1 -0
- package/package.json +2 -1
- package/src/cli.ts +11 -11
- package/src/clients/tinybird.ts +8 -6
- package/src/clients/vercel.ts +67 -0
- package/src/conformance.ts +2 -2
- package/src/walk/serve-pack.ts +1 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
// Vercel's unchanged REST SDK and Dub's Edge Config client, using the enclosing World's routing.
|
|
10
|
+
import { standardPackageFile } from "../package-file.js";
|
|
11
|
+
const { importSdk } = await import(__rewriteRelativeImportExtension(new URL('import.mjs', standardPackageFile('client-sdks/')).href));
|
|
12
|
+
const { Vercel } = await importSdk('@vercel/sdk');
|
|
13
|
+
const { VercelError } = await importSdk('@vercel/sdk/models/vercelerror.js');
|
|
14
|
+
const { createClient } = await importSdk('@vercel/edge-config');
|
|
15
|
+
const PROJECTS = 'https://unpkg.com/@vercel/sdk@1.28.38/esm/sdk/projects.js';
|
|
16
|
+
const EDGE = 'https://unpkg.com/@vercel/edge-config@0.4.1/dist/index.d.ts';
|
|
17
|
+
export const cases = [
|
|
18
|
+
{
|
|
19
|
+
id: 'project-domain-add-and-read',
|
|
20
|
+
asks: 'the issued project token adds a domain, and an independent SDK read preserves its name, project and verification state',
|
|
21
|
+
source: `${PROJECTS} "Add a domain to the project by passing its domain name"; ${PROJECTS} "Get project domain by project id/name and domain name."`,
|
|
22
|
+
async run(c) {
|
|
23
|
+
const vercel = new Vercel({ bearerToken: c.env.VERCEL_API_KEY });
|
|
24
|
+
const project = c.env.VERCEL_PROJECT_ID;
|
|
25
|
+
const name = 'sdk-client.example.test';
|
|
26
|
+
const added = await vercel.projects.addProjectDomain({ idOrName: project, requestBody: { name } });
|
|
27
|
+
const got = await vercel.projects.getProjectDomain({ idOrName: project, domain: name });
|
|
28
|
+
const wanted = { name, apexName: 'example.test', projectId: project, verified: true };
|
|
29
|
+
return Object.entries(wanted).flatMap(([field, value]) => added[field] === value && got[field] === value ? [] : [`project domain ${field} did not survive SDK create/read`]);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'invalid-project-token',
|
|
34
|
+
asks: 'an invalid token cannot read the project domain and the SDK preserves the HTTP refusal status',
|
|
35
|
+
source: `${PROJECTS} "Get project domain by project id/name and domain name."; https://unpkg.com/@vercel/sdk@1.28.38/esm/models/vercelerror.js "HTTP status code"`,
|
|
36
|
+
async run(c) {
|
|
37
|
+
const vercel = new Vercel({ bearerToken: 'throwaway-invalid-token' });
|
|
38
|
+
try {
|
|
39
|
+
await vercel.projects.getProjectDomain({ idOrName: c.env.VERCEL_PROJECT_ID, domain: 'sdk-client.example.test' });
|
|
40
|
+
return ['an invalid token read the project domain'];
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return error instanceof Error && error instanceof VercelError && 'statusCode' in error && error.statusCode === 403
|
|
44
|
+
? [] : [`invalid token refusal differs: ${String(error)}`];
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'edge-config-get-and-selected-get-all',
|
|
50
|
+
asks: 'the issued Edge Config connection string reads a stored value and only the selected keys through the unchanged SDK',
|
|
51
|
+
source: `${EDGE} "Read a single value."; ${EDGE} "Returns all entries when called with no arguments or only entries matching the given keys otherwise."`,
|
|
52
|
+
async run(c) {
|
|
53
|
+
const domains = ['phish-bank.example.test'];
|
|
54
|
+
const terms = ['gift-card'];
|
|
55
|
+
const written = await c.fetch(`https://api.vercel.com/v1/edge-config/${c.env.EDGE_CONFIG_ID}/items`, {
|
|
56
|
+
method: 'PATCH', headers: { authorization: `Bearer ${c.env.VERCEL_API_KEY}`, 'content-type': 'application/json' },
|
|
57
|
+
body: JSON.stringify({ items: [
|
|
58
|
+
{ operation: 'upsert', key: 'sdk_domains', value: domains },
|
|
59
|
+
{ operation: 'upsert', key: 'sdk_terms', value: terms },
|
|
60
|
+
{ operation: 'upsert', key: 'sdk_unselected', value: true },
|
|
61
|
+
] }),
|
|
62
|
+
});
|
|
63
|
+
if (!written.ok || (await written.json()).status !== 'ok')
|
|
64
|
+
return ['the Edge Config items were not written through the vendor API'];
|
|
65
|
+
const edge = createClient(c.env.EDGE_CONFIG);
|
|
66
|
+
const value = await edge.get('sdk_domains');
|
|
67
|
+
const selected = await edge.getAll(['sdk_domains', 'sdk_terms']);
|
|
68
|
+
return JSON.stringify(value) === JSON.stringify(domains) && JSON.stringify(selected.sdk_domains) === JSON.stringify(domains)
|
|
69
|
+
&& JSON.stringify(selected.sdk_terms) === JSON.stringify(terms) && Object.keys(selected).length === 2
|
|
70
|
+
? [] : ['Edge Config get/getAll did not preserve the stored values and selected keys'];
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
];
|
package/dist/src/conformance.js
CHANGED
|
@@ -611,8 +611,8 @@ async function lifeServed(pack) {
|
|
|
611
611
|
}, server.managedDatabaseUrl ? { managedDatabaseUrl: server.managedDatabaseUrl } : {}),
|
|
612
612
|
// a socket opened as an application opens it: a WebSocket to the served port, the vendor's host in its Host header
|
|
613
613
|
socket: (url, headers) => new WebSocket(`ws://127.0.0.1:${port}${url}`, { headers }),
|
|
614
|
-
//
|
|
615
|
-
stream: lineConnection(server.port),
|
|
614
|
+
// TCP to the native wire: a separate listener beside HTTP, or the primary protocol port.
|
|
615
|
+
stream: lineConnection(server.wirePort ?? server.port),
|
|
616
616
|
// bounded: Bun's server.stop(true) never settles once a WebSocket peer has closed under it (discord's life, Bun
|
|
617
617
|
// 1.3.11: the walk ended and the stop spun at full CPU for 45 minutes), so the check waits 5 s and goes on
|
|
618
618
|
stop: async () => { await within(5000, Promise.resolve(server.stop())); },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/twin-standard",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.158",
|
|
4
4
|
"description": "The Protocol 3 standard for Volter twin packs: the criteria a pack is graded by, the grader, the gate a pack repository and the twin catalog run on every change and submission, and the spec derivation the grade checks against. Pin a version: every place a pack is judged judges by that standard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"README.md",
|
|
21
21
|
"LICENSE",
|
|
22
22
|
"client-sdks/package.json",
|
|
23
|
+
"client-sdks/import.mjs",
|
|
23
24
|
"client-sdks/pnpm-lock.yaml",
|
|
24
25
|
"!**/*.test.ts",
|
|
25
26
|
"client-sdks/pnpm-workspace.yaml",
|
package/src/cli.ts
CHANGED
|
@@ -78,7 +78,7 @@ if (command === '--version') {
|
|
|
78
78
|
});
|
|
79
79
|
} else if (command === 'create') {
|
|
80
80
|
if (args.includes('--init') && !args.includes('--package')) throw new Error('Name your scoped package with --package');
|
|
81
|
-
await (await import('./create-pack.
|
|
81
|
+
await (await import('./create-pack.js')).createPack(args);
|
|
82
82
|
} else if (command === 'prepare-consumer') {
|
|
83
83
|
if (!args[0]) usage();
|
|
84
84
|
const value = (name: string) => { const at = args.indexOf(name); if (at < 0 || !args[at + 1]) usage(); return args[at + 1]!; };
|
|
@@ -88,7 +88,7 @@ if (command === '--version') {
|
|
|
88
88
|
if (!/^sha512-[A-Za-z0-9+/]{86}==$/.test(artifactIntegrity)) throw new Error('Consumer preparation requires candidate SHA-512 integrity');
|
|
89
89
|
const out = resolve(value('--out'));
|
|
90
90
|
if (existsSync(out)) throw new Error('Prepared consumer output already exists');
|
|
91
|
-
const { prepareConsumerApp } = await import('./consumer.
|
|
91
|
+
const { prepareConsumerApp } = await import('./consumer.js');
|
|
92
92
|
const candidateAt = args.indexOf('--candidate');
|
|
93
93
|
const artifact = candidateAt >= 0 ? resolve(value('--candidate')) : undefined;
|
|
94
94
|
const fixture = prepareConsumerApp(resolve(args[0]!), appDir, { cli, artifact });
|
|
@@ -102,7 +102,7 @@ if (command === '--version') {
|
|
|
102
102
|
const outputAt = args.indexOf('--out');
|
|
103
103
|
if (outputAt >= 0 && !args[outputAt + 1]) usage();
|
|
104
104
|
const consumer = JSON.parse(readFileSync(resolve(args[at + 1]!), 'utf8'));
|
|
105
|
-
const { runConsumerWorkflow } = await import('./consumer.
|
|
105
|
+
const { runConsumerWorkflow } = await import('./consumer.js');
|
|
106
106
|
const report = await runConsumerWorkflow(resolve(args[0]!), consumer);
|
|
107
107
|
const text = `${JSON.stringify(report, null, 2)}\n`;
|
|
108
108
|
if (outputAt >= 0) {
|
|
@@ -112,7 +112,7 @@ if (command === '--version') {
|
|
|
112
112
|
process.exit(report.passed ? 0 : 1);
|
|
113
113
|
} else if (command === 'assess') {
|
|
114
114
|
if (!args[0]) usage();
|
|
115
|
-
const { assessPack } = await import('./assessment.
|
|
115
|
+
const { assessPack } = await import('./assessment.js');
|
|
116
116
|
const consumerAt = args.indexOf('--prepared-consumer');
|
|
117
117
|
if (consumerAt >= 0 && !args[consumerAt + 1]) usage();
|
|
118
118
|
const consumer = consumerAt >= 0 ? JSON.parse(readFileSync(resolve(args[consumerAt + 1]!), 'utf8')) : undefined;
|
|
@@ -126,7 +126,7 @@ if (command === '--version') {
|
|
|
126
126
|
process.exit(report.ready ? 0 : 1);
|
|
127
127
|
} else if (command === 'facts') {
|
|
128
128
|
if (!args[0]) usage();
|
|
129
|
-
const { compilePackFacts, renderPackFacts } = await import('./pack-facts.
|
|
129
|
+
const { compilePackFacts, renderPackFacts } = await import('./pack-facts.js');
|
|
130
130
|
const { mkdirSync, writeFileSync } = await import('node:fs');
|
|
131
131
|
const { join, dirname } = await import('node:path');
|
|
132
132
|
const dir = resolve(args[0]!);
|
|
@@ -145,19 +145,19 @@ if (command === '--version') {
|
|
|
145
145
|
if (!args[0] || args[0].startsWith('-')) usage();
|
|
146
146
|
const tool = { walk: 'score-pack', examples: 'vendor-examples', coverage: 'life-coverage', 'judge-brief': 'judge-brief' }[command];
|
|
147
147
|
process.argv = [process.argv[0]!, process.argv[1]!, ...args];
|
|
148
|
-
await import((await import('./tools/packs-root.
|
|
148
|
+
await import((await import('./tools/packs-root.js')).toolPath(tool));
|
|
149
149
|
} else if (command === 'derive') {
|
|
150
150
|
if (!args[0]) usage();
|
|
151
151
|
// the derivation is a script over process.argv: it reads the unit from its first argument
|
|
152
152
|
process.argv = [process.argv[0]!, process.argv[1]!, ...args];
|
|
153
|
-
await import('./derive.
|
|
153
|
+
await import('./derive.js');
|
|
154
154
|
} else if (command === 'check-sources') {
|
|
155
155
|
if (!args[0]) usage();
|
|
156
|
-
await (await import('./check-sources.
|
|
156
|
+
await (await import('./check-sources.js')).checkSources(args);
|
|
157
157
|
} else if (command === 'read-page') {
|
|
158
158
|
// a documentation page's text, read as the citation check reads it: where an author finds the vendor's examples and words
|
|
159
159
|
if (!args[0]) usage();
|
|
160
|
-
const { status, readable, raw, error } = await (await import('./check-sources.
|
|
160
|
+
const { status, readable, raw, error } = await (await import('./check-sources.js')).readPage(args[0]);
|
|
161
161
|
if (status !== 200) { console.error(`read-page: ${args[0]} answered ${status || 'nothing'}${error ? `: ${error}` : ''}`); process.exit(1); }
|
|
162
162
|
// --raw: the page's own bytes, as fetched (a spec writer reads its tables, which the readable text drops)
|
|
163
163
|
if (args.includes('--raw')) process.stdout.write(raw); else console.log(readable);
|
|
@@ -169,8 +169,8 @@ if (command === '--version') {
|
|
|
169
169
|
// `.tgz` the tarball `npm pack` makes of one, the bytes a publish would send
|
|
170
170
|
const published = target.endsWith('.tgz') || (!existsSync(target) && /^@?[^@]+@[^@]+$/.test(target));
|
|
171
171
|
const results = published
|
|
172
|
-
? await (await import('./published.
|
|
173
|
-
: await (await import('./conformance.
|
|
172
|
+
? await (await import('./published.js')).conformPublished(target, at >= 0 ? { registry: args[at + 1]! } : {})
|
|
173
|
+
: await (await import('./conformance.js')).conformance(target, { onCheck: (id) => console.error(` … ${id} (${new Date().toISOString().slice(11, 19)})`) });
|
|
174
174
|
for (const r of results) {
|
|
175
175
|
console.log(`${r.failures.length ? '✗' : '✓'} ${r.id.padEnd(15)} ${r.asks}${r.note ? ` (${r.note})` : ''}`);
|
|
176
176
|
for (const f of r.failures) console.log(` ${f}`);
|
package/src/clients/tinybird.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// Tinybird's official API wrapper, unmodified, with the World credential and routed fetch.
|
|
2
2
|
// The pinned package names Forward; its decoupled API wrapper uses the Classic /v0 APIs.
|
|
3
3
|
import type { ClientCase, ClientContext } from './harness.ts';
|
|
4
|
+
import { standardPackageFile } from '../package-file.ts';
|
|
5
|
+
|
|
6
|
+
const { importSdk } = await import(new URL('import.mjs', standardPackageFile('client-sdks/')).href);
|
|
7
|
+
const { createTinybirdApi, TinybirdApiError }: typeof import('@tinybirdco/sdk/api') = await importSdk('@tinybirdco/sdk/api');
|
|
4
8
|
|
|
5
9
|
const SDK = 'https://unpkg.com/@tinybirdco/sdk@0.0.84/src/api/api.ts';
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
const { createTinybirdApi } = await import('@tinybirdco/sdk/api');
|
|
11
|
+
function client(c: ClientContext, fetch: typeof globalThis.fetch = c.fetch) {
|
|
9
12
|
return createTinybirdApi({ baseUrl: `https://${c.host}`, token: c.env.TINYBIRD_API_KEY ?? c.env.TINYBIRD_TOKEN ?? '', fetch });
|
|
10
13
|
}
|
|
11
14
|
|
|
@@ -15,8 +18,7 @@ export const cases: ClientCase[] = [
|
|
|
15
18
|
asks: 'a request token override is used instead of the Workspace token, and its refusal retains the status and JSON error in TinybirdApiError',
|
|
16
19
|
source: `${SDK} "Error thrown by TinybirdApi when a response is not OK"`,
|
|
17
20
|
async run(c) {
|
|
18
|
-
const
|
|
19
|
-
const api = await client(c);
|
|
21
|
+
const api = client(c);
|
|
20
22
|
try {
|
|
21
23
|
await api.ingest('client_case_events', { label: 'refused' }, { token: 'throwaway-invalid-token' });
|
|
22
24
|
return ['the invalid request token was accepted'];
|
|
@@ -37,7 +39,7 @@ export const cases: ClientCase[] = [
|
|
|
37
39
|
async run(c) {
|
|
38
40
|
let calls = 0;
|
|
39
41
|
const routed = ((input: RequestInfo | URL, init?: RequestInit) => { calls++; return c.fetch(input, init); }) as typeof fetch;
|
|
40
|
-
const api =
|
|
42
|
+
const api = client(c, routed);
|
|
41
43
|
try {
|
|
42
44
|
await api.ingest('client_case_events', { timestamp: new Date('2024-01-15T10:30:00Z') });
|
|
43
45
|
return ['a Date object was accepted for ingestion'];
|
|
@@ -58,7 +60,7 @@ export const cases: ClientCase[] = [
|
|
|
58
60
|
asks: 'an object query parameter becomes JSON and the Endpoint uses its value rather than the object string representation',
|
|
59
61
|
source: `${SDK} "Plain objects (e.g. p.json() params) become JSON strings; Dates are rejected;"`,
|
|
60
62
|
async run(c) {
|
|
61
|
-
const api =
|
|
63
|
+
const api = client(c);
|
|
62
64
|
await api.requestJson('/v0/datasources', { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ name: 'client_json_rows', schema: 'name String' }).toString() });
|
|
63
65
|
await api.ingestBatch('client_json_rows', [{ name: 'selected' }, { name: 'excluded' }], { wait: true });
|
|
64
66
|
await api.requestJson('/v0/pipes', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ name: 'client_json_filter', nodes: [{ name: 'endpoint', type: 'endpoint', sql: "%\nSELECT name FROM client_json_rows WHERE name = {{JSON(filters, '{\"name\":\"selected\"}').get('name')}}" }] }) });
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Vercel's unchanged REST SDK and Dub's Edge Config client, using the enclosing World's routing.
|
|
2
|
+
import { standardPackageFile } from '../package-file.ts';
|
|
3
|
+
import type { ClientCase } from './harness.ts';
|
|
4
|
+
|
|
5
|
+
const { importSdk } = await import(new URL('import.mjs', standardPackageFile('client-sdks/')).href);
|
|
6
|
+
const { Vercel } = await importSdk('@vercel/sdk');
|
|
7
|
+
const { VercelError } = await importSdk('@vercel/sdk/models/vercelerror.js');
|
|
8
|
+
const { createClient } = await importSdk('@vercel/edge-config');
|
|
9
|
+
const PROJECTS = 'https://unpkg.com/@vercel/sdk@1.28.38/esm/sdk/projects.js';
|
|
10
|
+
const EDGE = 'https://unpkg.com/@vercel/edge-config@0.4.1/dist/index.d.ts';
|
|
11
|
+
|
|
12
|
+
export const cases: ClientCase[] = [
|
|
13
|
+
{
|
|
14
|
+
id: 'project-domain-add-and-read',
|
|
15
|
+
asks: 'the issued project token adds a domain, and an independent SDK read preserves its name, project and verification state',
|
|
16
|
+
source: `${PROJECTS} "Add a domain to the project by passing its domain name"; ${PROJECTS} "Get project domain by project id/name and domain name."`,
|
|
17
|
+
async run(c) {
|
|
18
|
+
const vercel = new Vercel({ bearerToken: c.env.VERCEL_API_KEY });
|
|
19
|
+
const project = c.env.VERCEL_PROJECT_ID;
|
|
20
|
+
const name = 'sdk-client.example.test';
|
|
21
|
+
const added = await vercel.projects.addProjectDomain({ idOrName: project, requestBody: { name } });
|
|
22
|
+
const got = await vercel.projects.getProjectDomain({ idOrName: project, domain: name });
|
|
23
|
+
const wanted = { name, apexName: 'example.test', projectId: project, verified: true };
|
|
24
|
+
return Object.entries(wanted).flatMap(([field, value]) =>
|
|
25
|
+
added[field] === value && got[field] === value ? [] : [`project domain ${field} did not survive SDK create/read`]);
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'invalid-project-token',
|
|
30
|
+
asks: 'an invalid token cannot read the project domain and the SDK preserves the HTTP refusal status',
|
|
31
|
+
source: `${PROJECTS} "Get project domain by project id/name and domain name."; https://unpkg.com/@vercel/sdk@1.28.38/esm/models/vercelerror.js "HTTP status code"`,
|
|
32
|
+
async run(c) {
|
|
33
|
+
const vercel = new Vercel({ bearerToken: 'throwaway-invalid-token' });
|
|
34
|
+
try {
|
|
35
|
+
await vercel.projects.getProjectDomain({ idOrName: c.env.VERCEL_PROJECT_ID, domain: 'sdk-client.example.test' });
|
|
36
|
+
return ['an invalid token read the project domain'];
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return error instanceof Error && error instanceof VercelError && 'statusCode' in error && error.statusCode === 403
|
|
39
|
+
? [] : [`invalid token refusal differs: ${String(error)}`];
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'edge-config-get-and-selected-get-all',
|
|
45
|
+
asks: 'the issued Edge Config connection string reads a stored value and only the selected keys through the unchanged SDK',
|
|
46
|
+
source: `${EDGE} "Read a single value."; ${EDGE} "Returns all entries when called with no arguments or only entries matching the given keys otherwise."`,
|
|
47
|
+
async run(c) {
|
|
48
|
+
const domains = ['phish-bank.example.test'];
|
|
49
|
+
const terms = ['gift-card'];
|
|
50
|
+
const written = await c.fetch(`https://api.vercel.com/v1/edge-config/${c.env.EDGE_CONFIG_ID}/items`, {
|
|
51
|
+
method: 'PATCH', headers: { authorization: `Bearer ${c.env.VERCEL_API_KEY}`, 'content-type': 'application/json' },
|
|
52
|
+
body: JSON.stringify({ items: [
|
|
53
|
+
{ operation: 'upsert', key: 'sdk_domains', value: domains },
|
|
54
|
+
{ operation: 'upsert', key: 'sdk_terms', value: terms },
|
|
55
|
+
{ operation: 'upsert', key: 'sdk_unselected', value: true },
|
|
56
|
+
] }),
|
|
57
|
+
});
|
|
58
|
+
if (!written.ok || (await written.json() as { status?: string }).status !== 'ok') return ['the Edge Config items were not written through the vendor API'];
|
|
59
|
+
const edge = createClient(c.env.EDGE_CONFIG);
|
|
60
|
+
const value = await edge.get('sdk_domains');
|
|
61
|
+
const selected = await edge.getAll(['sdk_domains', 'sdk_terms']);
|
|
62
|
+
return JSON.stringify(value) === JSON.stringify(domains) && JSON.stringify(selected.sdk_domains) === JSON.stringify(domains)
|
|
63
|
+
&& JSON.stringify(selected.sdk_terms) === JSON.stringify(terms) && Object.keys(selected).length === 2
|
|
64
|
+
? [] : ['Edge Config get/getAll did not preserve the stored values and selected keys'];
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
package/src/conformance.ts
CHANGED
|
@@ -499,8 +499,8 @@ async function lifeServed(pack: string): Promise<string[]> {
|
|
|
499
499
|
}, server.managedDatabaseUrl ? { managedDatabaseUrl: server.managedDatabaseUrl } : {}),
|
|
500
500
|
// a socket opened as an application opens it: a WebSocket to the served port, the vendor's host in its Host header
|
|
501
501
|
socket: (url: string, headers: Record<string, string>) => new WebSocket(`ws://127.0.0.1:${port}${url}`, { headers } as unknown as string[]),
|
|
502
|
-
//
|
|
503
|
-
stream: lineConnection(server.port),
|
|
502
|
+
// TCP to the native wire: a separate listener beside HTTP, or the primary protocol port.
|
|
503
|
+
stream: lineConnection(server.wirePort ?? server.port),
|
|
504
504
|
// bounded: Bun's server.stop(true) never settles once a WebSocket peer has closed under it (discord's life, Bun
|
|
505
505
|
// 1.3.11: the walk ended and the stop spun at full CPU for 45 minutes), so the check waits 5 s and goes on
|
|
506
506
|
stop: async () => { await within(5000, Promise.resolve(server.stop())); },
|
package/src/walk/serve-pack.ts
CHANGED