wikimemory 0.2.3 → 0.2.4
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.
|
@@ -79,6 +79,10 @@ export function compareSemanticVersions(left, right) {
|
|
|
79
79
|
}
|
|
80
80
|
return 0;
|
|
81
81
|
}
|
|
82
|
+
export function deploymentIsCurrent(currentVersion, manifest, pendingMigrations) {
|
|
83
|
+
return (compareSemanticVersions(currentVersion, manifest.version) === 0 &&
|
|
84
|
+
pendingMigrations.length === 0);
|
|
85
|
+
}
|
|
82
86
|
export function productionUpgradeConfig(record, packageRoot) {
|
|
83
87
|
return `${JSON.stringify({
|
|
84
88
|
$schema: join(packageRoot, "node_modules", "wrangler", "config-schema.json"),
|
|
@@ -166,34 +170,64 @@ async function confirmUpgrade(summary, automatic) {
|
|
|
166
170
|
if (answer !== "y" && answer !== "yes")
|
|
167
171
|
throw new Error("Cancelled");
|
|
168
172
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
.object({ status: z.literal("ok"), service: z.literal("wikimemory"), version: z.string() })
|
|
173
|
-
.parse(await health.json());
|
|
174
|
-
if (!health.ok || healthBody.version !== manifest.version)
|
|
175
|
-
throw new Error("Deployed Worker version verification failed");
|
|
176
|
-
const ready = await fetch(`${origin}/ready`, { redirect: "error" });
|
|
177
|
-
const readyBody = z
|
|
178
|
-
.object({
|
|
179
|
-
status: z.literal("ready"),
|
|
180
|
-
service: z.literal("wikimemory"),
|
|
181
|
-
version: z.string(),
|
|
182
|
-
schemaVersion: z.string()
|
|
183
|
-
})
|
|
184
|
-
.parse(await ready.json());
|
|
185
|
-
if (!ready.ok ||
|
|
186
|
-
readyBody.version !== manifest.version ||
|
|
187
|
-
readyBody.schemaVersion !== manifest.schemaVersion)
|
|
188
|
-
throw new Error("Deployed schema version verification failed");
|
|
189
|
-
const discovery = await fetch(`${origin}/.well-known/oauth-protected-resource/mcp`, {
|
|
190
|
-
redirect: "error"
|
|
173
|
+
function sleep(milliseconds) {
|
|
174
|
+
return new Promise((resolve) => {
|
|
175
|
+
setTimeout(resolve, milliseconds);
|
|
191
176
|
});
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
if (!
|
|
196
|
-
throw new Error(
|
|
177
|
+
}
|
|
178
|
+
async function responseJson(response, label) {
|
|
179
|
+
const text = await response.text();
|
|
180
|
+
if (!response.ok)
|
|
181
|
+
throw new Error(`${label} returned HTTP ${response.status}: ${text.slice(0, 300)}`);
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(text);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
throw new Error(`${label} returned non-JSON content`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export async function verifyRelease(origin, manifest, fetcher = fetch, sleeper = sleep, attempts = 6) {
|
|
190
|
+
let finalError;
|
|
191
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
192
|
+
try {
|
|
193
|
+
const health = await fetcher(`${origin}/health`, { redirect: "error" });
|
|
194
|
+
const healthBody = z
|
|
195
|
+
.object({ status: z.literal("ok"), service: z.literal("wikimemory"), version: z.string() })
|
|
196
|
+
.parse(await responseJson(health, "Health endpoint"));
|
|
197
|
+
if (healthBody.version !== manifest.version) {
|
|
198
|
+
throw new Error(`Health endpoint reports version ${healthBody.version}; expected ${manifest.version}`);
|
|
199
|
+
}
|
|
200
|
+
const ready = await fetcher(`${origin}/ready`, { redirect: "error" });
|
|
201
|
+
const readyBody = z
|
|
202
|
+
.object({
|
|
203
|
+
status: z.literal("ready"),
|
|
204
|
+
service: z.literal("wikimemory"),
|
|
205
|
+
version: z.string(),
|
|
206
|
+
schemaVersion: z.string()
|
|
207
|
+
})
|
|
208
|
+
.parse(await responseJson(ready, "Readiness endpoint"));
|
|
209
|
+
if (readyBody.version !== manifest.version ||
|
|
210
|
+
readyBody.schemaVersion !== manifest.schemaVersion) {
|
|
211
|
+
throw new Error(`Readiness endpoint reports version ${readyBody.version} and schema ${readyBody.schemaVersion}; expected ${manifest.version} and ${manifest.schemaVersion}`);
|
|
212
|
+
}
|
|
213
|
+
const discovery = await fetcher(`${origin}/.well-known/oauth-protected-resource/mcp`, {
|
|
214
|
+
redirect: "error"
|
|
215
|
+
});
|
|
216
|
+
if (!discovery.ok)
|
|
217
|
+
throw new Error(`OAuth protected-resource discovery returned HTTP ${discovery.status}`);
|
|
218
|
+
const app = await fetcher(`${origin}/app`, { redirect: "error" });
|
|
219
|
+
if (!app.ok || !(await app.text()).includes('<div id="root"></div>'))
|
|
220
|
+
throw new Error("React application verification failed");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
finalError = error;
|
|
225
|
+
if (attempt + 1 < attempts)
|
|
226
|
+
await sleeper(250 * 2 ** attempt);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const detail = finalError instanceof Error ? finalError.message : "Unknown verification failure";
|
|
230
|
+
throw new Error(`Deployed release verification failed after ${attempts} attempts: ${detail}`);
|
|
197
231
|
}
|
|
198
232
|
export async function runUpgrade(args) {
|
|
199
233
|
const options = parseUpgradeOptions(args);
|
|
@@ -271,6 +305,12 @@ export async function runUpgrade(args) {
|
|
|
271
305
|
throw new Error("Current deployment health check failed");
|
|
272
306
|
if (compareSemanticVersions(current, manifest.version) > 0)
|
|
273
307
|
throw new Error(`Refusing to downgrade Wikimemory from ${current} to ${manifest.version}`);
|
|
308
|
+
if (deploymentIsCurrent(current, manifest, pending)) {
|
|
309
|
+
await verifyRelease(record.origin, manifest);
|
|
310
|
+
await writeDeploymentRecord({ ...record, installedVersion: manifest.version }, recordPath);
|
|
311
|
+
console.log(`\nWikimemory ${manifest.version} is already ready. Reconciled the local deployment record without redeploying.`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
274
314
|
await confirmUpgrade(`\nWikimemory upgrade\n Account: ${record.accountId}\n Worker: ${record.workerName}\n D1: ${record.databaseName} (${record.databaseId})\n KV: ${record.kvName} (${record.kvId})\n Origin: ${record.origin}\n Version: ${current} -> ${manifest.version}\n Migrations: ${pending.map((item) => item.name).join(", ") || "none"}`, options.yes);
|
|
275
315
|
for (const migration of pending) {
|
|
276
316
|
const bundlePath = join(temporary, migration.name);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const WIKIMEMORY_VERSION = "0.2.
|
|
1
|
+
export const WIKIMEMORY_VERSION = "0.2.4";
|
|
2
2
|
export const LATEST_SCHEMA_VERSION = "0004_credential_bound_registration_tokens.sql";
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const WIKIMEMORY_VERSION = "0.2.
|
|
1
|
+
export const WIKIMEMORY_VERSION = "0.2.4";
|
|
2
2
|
export const LATEST_SCHEMA_VERSION = "0004_credential_bound_registration_tokens.sql";
|