Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/vfs_canister/vfs.did
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type DatabaseStatus = variant {
Restoring;
Archiving;
Archived;
Deleted;
Pending;
};
type DatabaseSummary = record {
Expand All @@ -104,6 +105,7 @@ type DatabaseSummary = record {
cycles_suspended_at_ms : opt int64;
database_id : text;
archived_at_ms : opt int64;
deleted_at_ms : opt int64;
};
type DeleteDatabaseRequest = record { database_id : text };
type DeleteNodeRequest = record {
Expand Down
1 change: 1 addition & 0 deletions crates/vfs_cli_app/src/commands_fs_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl VfsApi for MockClient {
cycles_balance: Some(10),
cycles_suspended_at_ms: None,
archived_at_ms: None,
deleted_at_ms: None,
}])
}

Expand Down
1 change: 1 addition & 0 deletions crates/vfs_cli_core/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,7 @@ mod tests {
cycles_balance: Some(1_000_000),
cycles_suspended_at_ms: None,
archived_at_ms: None,
deleted_at_ms: None,
}])
}
async fn begin_database_archive(&self, database_id: &str) -> Result<DatabaseArchiveInfo> {
Expand Down
5 changes: 4 additions & 1 deletion crates/vfs_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5452,7 +5452,7 @@ fn load_database_summaries_for_caller(
.prepare(
"SELECT d.database_id, d.name, d.status, m.role, d.logical_size_bytes,
COALESCE(b.balance_cycles, 0), b.suspended_at_ms,
d.archived_at_ms
d.archived_at_ms, d.deleted_at_ms
FROM databases d
INNER JOIN database_members m ON m.database_id = d.database_id
LEFT JOIN database_cycle_accounts b ON b.database_id = d.database_id
Expand All @@ -5472,6 +5472,7 @@ fn load_database_summaries_for_caller(
cycles_balance: Some(cycles_balance.max(0) as u64),
cycles_suspended_at_ms: crate::sqlite::row_get(row, 6)?,
archived_at_ms: crate::sqlite::row_get(row, 7)?,
deleted_at_ms: crate::sqlite::row_get(row, 8)?,
})
})
.map_err(|error| error.to_string())
Expand Down Expand Up @@ -5569,6 +5570,7 @@ fn status_from_db(status: &str) -> crate::sqlite::Result<DatabaseStatus> {
"archiving" => Ok(DatabaseStatus::Archiving),
"archived" => Ok(DatabaseStatus::Archived),
"restoring" => Ok(DatabaseStatus::Restoring),
"deleted" => Ok(DatabaseStatus::Deleted),
_ => Err(crate::sqlite::invalid_query()),
}
}
Expand All @@ -5580,6 +5582,7 @@ fn status_to_db(status: DatabaseStatus) -> &'static str {
DatabaseStatus::Archiving => "archiving",
DatabaseStatus::Archived => "archived",
DatabaseStatus::Restoring => "restoring",
DatabaseStatus::Deleted => "deleted",
}
}

Expand Down
5 changes: 4 additions & 1 deletion crates/vfs_runtime/tests/database_service_pbt_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,10 @@ proptest! {
service
.finalize_database_archive(&database_id, OWNER, hash.clone(), 22)
.expect("archive should finalize");
assert_eq!(status_and_mount(service, &database_id).0, DatabaseStatus::Archived);
assert_eq!(
status_and_mount(service, &database_id).0,
DatabaseStatus::Archived
);
}

let bad_hash = vec![8_u8; 32];
Expand Down
11 changes: 7 additions & 4 deletions crates/vfs_types/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ pub struct DatabaseMember {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, CandidType)]
#[serde(rename_all = "snake_case")]
pub enum DatabaseStatus {
#[serde(alias = "Pending")]
Pending,
#[serde(alias = "Active")]
Active,
#[serde(alias = "Pending")]
Pending,
#[serde(alias = "Restoring")]
Restoring,
#[serde(alias = "Archiving")]
Archiving,
#[serde(alias = "Archived")]
Archived,
#[serde(alias = "Restoring")]
Restoring,
#[serde(alias = "Deleted")]
Deleted,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, CandidType)]
Expand All @@ -60,6 +62,7 @@ pub struct DatabaseSummary {
pub cycles_balance: Option<u64>,
pub cycles_suspended_at_ms: Option<i64>,
pub archived_at_ms: Option<i64>,
pub deleted_at_ms: Option<i64>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, CandidType)]
Expand Down
5 changes: 3 additions & 2 deletions extensions/wiki-clipper/scripts/check-candid-drift.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const actor = readFileSync(new URL("../src/vfs-actor.js", import.meta.url), "utf

const expectedTypes = {
DatabaseRole: { kind: "variant", fields: { Reader: "null", Writer: "null", Owner: "null" } },
DatabaseStatus: { kind: "variant", fields: { Pending: "null", Active: "null", Restoring: "null", Archiving: "null", Archived: "null" } },
DatabaseStatus: { kind: "variant", fields: { Active: "null", Pending: "null", Restoring: "null", Archiving: "null", Archived: "null", Deleted: "null" } },
DatabaseSummary: {
kind: "record",
fields: {
Expand All @@ -20,7 +20,8 @@ const expectedTypes = {
database_id: "text",
cycles_balance: "opt nat64",
cycles_suspended_at_ms: "opt int64",
archived_at_ms: "opt int64"
archived_at_ms: "opt int64",
deleted_at_ms: "opt int64"
}
},
CyclesBillingConfig: {
Expand Down
12 changes: 8 additions & 4 deletions extensions/wiki-clipper/src/vfs-actor.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ export async function createVfsActor({ canisterId, host, identity }) {
function idlFactory({ IDL: idl }) {
const DatabaseRole = idl.Variant({ Reader: idl.Null, Writer: idl.Null, Owner: idl.Null });
const DatabaseStatus = idl.Variant({
Pending: idl.Null,
Active: idl.Null,
Pending: idl.Null,
Restoring: idl.Null,
Archiving: idl.Null,
Archived: idl.Null
Archived: idl.Null,
Deleted: idl.Null
});
const DatabaseSummary = idl.Record({
status: DatabaseStatus,
Expand All @@ -31,7 +32,8 @@ function idlFactory({ IDL: idl }) {
database_id: idl.Text,
cycles_balance: idl.Opt(idl.Nat64),
cycles_suspended_at_ms: idl.Opt(idl.Int64),
archived_at_ms: idl.Opt(idl.Int64)
archived_at_ms: idl.Opt(idl.Int64),
deleted_at_ms: idl.Opt(idl.Int64)
});
const CyclesBillingConfig = idl.Record({
kinic_ledger_canister_id: idl.Text,
Expand Down Expand Up @@ -164,7 +166,8 @@ function normalizeDatabaseSummary(raw) {
status: normalizeDatabaseStatus(raw.status),
logicalSizeBytes: raw.logical_size_bytes?.toString?.() ?? String(raw.logical_size_bytes ?? "0"),
cyclesBalance: raw.cycles_balance?.[0]?.toString?.() ?? "0",
cyclesSuspendedAtMs: raw.cycles_suspended_at_ms?.[0]?.toString?.() ?? null
cyclesSuspendedAtMs: raw.cycles_suspended_at_ms?.[0]?.toString?.() ?? null,
deletedAtMs: raw.deleted_at_ms?.[0]?.toString?.() ?? null
};
}

Expand All @@ -189,6 +192,7 @@ function databaseCyclesDisabledReason(database, config) {
const minimum = parseCycles(config?.minUpdateCycles);
if (!config) return "Cycles config unavailable.";
if (database.status === "Pending") return "Database activation is pending until its first cycle purchase completes.";
if (database.status !== "Active") return "Database is not writable in its current lifecycle state.";
if (database.cyclesSuspendedAtMs) return "Database cycles are suspended.";
if (balance < minimum) return "Database cycles balance is below the minimum update balance.";
return null;
Expand Down
7 changes: 5 additions & 2 deletions extensions/wiki-clipper/tests/offscreen.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ test("listWritableDatabases returns active writable database summaries", async (
logicalSizeBytes: "0",
cyclesBalance: "20000",
cyclesSuspendedAtMs: null,
deletedAtMs: null,
writeCyclesAvailable: true,
cyclesReason: null
}
Expand Down Expand Up @@ -406,7 +407,8 @@ function writeCyclesActorMethods({ databaseId = "team-db", balanceCycles = 20_00
logical_size_bytes: 0n,
cycles_balance: [balanceCycles],
cycles_suspended_at_ms: suspendedAtMs === null ? [] : [suspendedAtMs],
archived_at_ms: []
archived_at_ms: [],
deleted_at_ms: []
}
]
};
Expand All @@ -433,6 +435,7 @@ function rawDatabase(databaseId, name, role, status) {
logical_size_bytes: 0n,
cycles_balance: [20_000n],
cycles_suspended_at_ms: [],
archived_at_ms: []
archived_at_ms: [],
deleted_at_ms: []
};
}
3 changes: 2 additions & 1 deletion extensions/wiki-clipper/tests/settings.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ function rawDatabase(databaseId, role, status, nameOrBalance = 20_000n, cyclesSu
logical_size_bytes: 0n,
cycles_balance: [cyclesBalance],
cycles_suspended_at_ms: cyclesSuspendedAtMs === null ? [] : [cyclesSuspendedAtMs],
archived_at_ms: []
archived_at_ms: [],
deleted_at_ms: []
};
}
3 changes: 2 additions & 1 deletion skill-registry-web/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export type CanisterHealth = {
};

export type DatabaseRole = "reader" | "writer" | "owner";
export type DatabaseStatus = "pending" | "active" | "restoring" | "archiving" | "archived";
export type DatabaseStatus = "pending" | "active" | "restoring" | "archiving" | "archived" | "deleted";

export type DatabaseSummary = {
databaseId: string;
Expand All @@ -108,6 +108,7 @@ export type DatabaseSummary = {
cyclesBalance: string | null;
cyclesSuspendedAtMs: string | null;
archivedAtMs: string | null;
deletedAtMs: string | null;
};

export type DatabaseMember = {
Expand Down
4 changes: 3 additions & 1 deletion skill-registry-web/lib/vfs-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Variant = Record<string, null>;
type RawNode = { path: string; kind: Variant; content: string; created_at: bigint; updated_at: bigint; etag: string; metadata_json: string };
type RawNodeMutationAck = { path: string; kind: Variant; updated_at: bigint; etag: string };
type RawChild = { path: string; name: string; kind: Variant; updated_at: [] | [bigint]; etag: [] | [string]; size_bytes: [] | [bigint]; is_virtual: boolean; has_children: boolean };
type RawDatabaseSummary = { status: Variant; role: Variant; logical_size_bytes: bigint; database_id: string; name: string; archived_at_ms: [] | [bigint]; cycles_balance: [] | [bigint]; cycles_suspended_at_ms: [] | [bigint] };
type RawDatabaseSummary = { status: Variant; role: Variant; logical_size_bytes: bigint; database_id: string; name: string; archived_at_ms: [] | [bigint]; deleted_at_ms: [] | [bigint]; cycles_balance: [] | [bigint]; cycles_suspended_at_ms: [] | [bigint] };
type RawDatabaseMember = { database_id: string; principal: string; role: Variant; created_at_ms: bigint };
type RawWriteNodeRequest = { database_id: string; path: string; kind: Variant; content: string; metadata_json: string; expected_etag: [] | [string] };
type RawWriteNodeResult = { created: boolean; node: RawNodeMutationAck };
Expand Down Expand Up @@ -182,6 +182,7 @@ function normalizeDatabaseSummary(raw: RawDatabaseSummary): DatabaseSummary {
cyclesBalance: raw.cycles_balance[0]?.toString() ?? null,
cyclesSuspendedAtMs: raw.cycles_suspended_at_ms[0]?.toString() ?? null,
archivedAtMs: raw.archived_at_ms[0]?.toString() ?? null,
deletedAtMs: raw.deleted_at_ms[0]?.toString() ?? null,
};
}

Expand All @@ -191,6 +192,7 @@ function normalizeDatabaseStatus(status: Variant): DatabaseStatus {
if ("Restoring" in status) return "restoring";
if ("Archiving" in status) return "archiving";
if ("Archived" in status) return "archived";
if ("Deleted" in status) return "deleted";
throw new ApiError(`Unknown database status variant: ${Object.keys(status).join(",")}`, 502);
}

Expand Down
4 changes: 3 additions & 1 deletion skill-registry-web/lib/vfs-idl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export const idlFactory: ActorInterfaceFactory = ({ IDL: idl }) => {
const DatabaseRole = idl.Variant({ Reader: idl.Null, Writer: idl.Null, Owner: idl.Null });
const DatabaseStatus = idl.Variant({
Active: idl.Null,
Pending: idl.Null,
Restoring: idl.Null,
Archiving: idl.Null,
Archived: idl.Null,
Pending: idl.Null
Deleted: idl.Null
});
const DatabaseSummary = idl.Record({
status: DatabaseStatus,
Expand All @@ -20,6 +21,7 @@ export const idlFactory: ActorInterfaceFactory = ({ IDL: idl }) => {
database_id: idl.Text,
name: idl.Text,
archived_at_ms: idl.Opt(idl.Int64),
deleted_at_ms: idl.Opt(idl.Int64),
cycles_balance: idl.Opt(idl.Nat64),
cycles_suspended_at_ms: idl.Opt(idl.Int64)
});
Expand Down
6 changes: 5 additions & 1 deletion skill-registry-web/scripts/check-skill-registry-web.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@ assert.match(operations, /frontmatterEnd\(rest\)/);
assert.doesNotMatch(operations, /indexOf\("\\n---"\)/);
assert.match(wikiHelpers, /path === "\/Sources\/raw" \|\| path\.startsWith\("\/Sources\/raw\/"\)/);
assert.doesNotMatch(wikiHelpers, /path\.startsWith\("\/Sources\/raw"\)/);
assert.match(types, /DatabaseStatus = "pending" \| "active" \| "restoring" \| "archiving" \| "archived"/);
assert.match(types, /DatabaseStatus = "pending" \| "active" \| "restoring" \| "archiving" \| "archived" \| "deleted"/);
assert.doesNotMatch(vfsIdl, /Hot: idl\.Null/);
assert.match(vfsIdl, /Pending: idl\.Null/);
assert.match(vfsIdl, /Active: idl\.Null/);
assert.match(vfsIdl, /status: DatabaseStatus/);
assert.match(vfsIdl, /Deleted: idl\.Null/);
assert.match(vfsIdl, /deleted_at_ms: idl\.Opt\(idl\.Int64\)/);
assert.match(vfsClient, /function normalizeDatabaseStatus/);
assert.match(vfsClient, /"Active" in status/);
assert.match(vfsClient, /"Pending" in status/);
assert.match(vfsClient, /"Deleted" in status/);
assert.doesNotMatch(vfsClient, /: "hot"/);
assert.doesNotMatch(client, /from ["']..\/..\/..\/wikibrowser/);
assert.doesNotMatch(panels, /from ["']..\/..\/..\/wikibrowser/);
Expand Down
4 changes: 2 additions & 2 deletions wikibrowser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ pnpm smoke:errors -- --base-url http://127.0.0.1:3000 --database-id <database-id

## Candid Surface

`lib/vfs-idl.ts` is a small hand-written subset of `crates/vfs_canister/vfs.did`.
Run `pnpm test` whenever the canister interface changes.
`lib/vfs-idl.ts` is a small generated subset of the checked-in VFS canister Candid at `crates/vfs_canister/vfs.did`.
Run `pnpm test` after canister interface changes so the drift check verifies the generated subset.

Covered methods:

Expand Down
3 changes: 2 additions & 1 deletion wikibrowser/components/wiki-browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1453,7 +1453,8 @@ function withCurrentDatabase(databases: DatabaseSummary[], databaseId: string):
logicalSizeBytes: "0",
cyclesBalance: "0",
cyclesSuspendedAtMs: null,
archivedAtMs: null
archivedAtMs: null,
deletedAtMs: null
},
...databases
];
Expand Down
1 change: 1 addition & 0 deletions wikibrowser/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export type DatabaseSummary = {
cyclesBalance: string;
cyclesSuspendedAtMs: string | null;
archivedAtMs: string | null;
deletedAtMs: string | null;
};

export type DeleteDatabaseRequest = {
Expand Down
8 changes: 6 additions & 2 deletions wikibrowser/lib/vfs-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,8 @@ function normalizeDatabaseSummary(raw: RawDatabaseSummary): DatabaseSummary {
logicalSizeBytes: raw.logical_size_bytes.toString(),
cyclesBalance: raw.cycles_balance[0]?.toString() ?? "0",
cyclesSuspendedAtMs: raw.cycles_suspended_at_ms[0]?.toString() ?? null,
archivedAtMs: raw.archived_at_ms[0]?.toString() ?? null
archivedAtMs: raw.archived_at_ms[0]?.toString() ?? null,
deletedAtMs: raw.deleted_at_ms[0]?.toString() ?? null
};
}

Expand Down Expand Up @@ -1121,9 +1122,12 @@ function rawSourceRunSessionCheckRequest(request: SourceRunSessionCheckRequest):
}

function normalizeDatabaseStatus(status: Variant): DatabaseStatus {
if ("Hot" in status) {
if ("Active" in status) {
return "active";
}
if ("Pending" in status) {
return "pending";
}
if ("Restoring" in status) {
return "restoring";
}
Expand Down
5 changes: 3 additions & 2 deletions wikibrowser/lib/vfs-idl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated by scripts/generate-vfs-idl.mjs from scripts/candid-shapes.mjs.
// Generated by scripts/generate-vfs-idl.mjs from crates/vfs_canister/vfs.did.
// Do not edit by hand.
import { Actor } from "@icp-sdk/core/agent";
import { IDL } from "@icp-sdk/core/candid";
Expand All @@ -9,7 +9,8 @@ export const idlFactory: ActorInterfaceFactory = ({ IDL: idl }) => {
const CanisterHealth = idl.Record({ cycles_balance: idl.Nat });
const DatabaseRole = idl.Variant({ Reader: idl.Null, Writer: idl.Null, Owner: idl.Null });
const DatabaseStatus = idl.Variant({
Hot: idl.Null,
Active: idl.Null,
Pending: idl.Null,
Restoring: idl.Null,
Archiving: idl.Null,
Archived: idl.Null,
Expand Down
2 changes: 1 addition & 1 deletion wikibrowser/scripts/candid-shapes.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const expectedTypes = {
CanisterHealth: { kind: "record", fields: { cycles_balance: "nat" } },
DatabaseRole: { kind: "variant", cases: { Reader: "null", Writer: "null", Owner: "null" } },
DatabaseStatus: { kind: "variant", cases: { Hot: "null", Restoring: "null", Archiving: "null", Archived: "null", Deleted: "null" } },
DatabaseStatus: { kind: "variant", cases: { Active: "null", Pending: "null", Restoring: "null", Archiving: "null", Archived: "null", Deleted: "null" } },
DatabaseSummary: {
kind: "record",
fields: {
Expand Down
Loading