feat: add typed ESI transport extensions

This commit is contained in:
jb
2026-09-19 15:43:22 -04:00
parent 4d3c7a7521
commit 2675ea8114
14 changed files with 1205 additions and 124 deletions
+31 -1
View File
@@ -540,6 +540,7 @@ export const bridgeSaveTokens = mutationGeneric({
tokenExpiresAt: v.number(),
scopes: v.array(v.string()),
expectedVersion: v.number(),
returnAuthority: v.optional(v.boolean()),
},
handler: async (ctx, args) => {
assertBridge(args.bridgeSecret);
@@ -569,6 +570,15 @@ export const bridgeSaveTokens = mutationGeneric({
datasetStatuses: updated.statuses,
...(updated.assetsInvalidated ? { state: "error" as const, activeGeneration: undefined, syncedAt: undefined, expiresAt: undefined } : {}),
});
if (args.returnAuthority) {
return {
saved: true,
credentialVersion: nextVersion,
grantRevision: nextRevision,
authorizationEpoch: character.authorizationEpoch,
scopes: args.scopes,
};
}
return true;
},
});
@@ -713,7 +723,14 @@ export const bridgeAssetsPage = queryGeneric({
});
export const bridgeBeginSync = mutationGeneric({
args: { ...bridgeArgs, ...characterArgs },
args: {
...bridgeArgs,
...characterArgs,
expectedScopes: v.optional(v.array(v.string())),
expectedGrantRevision: v.optional(v.number()),
expectedAuthorizationEpoch: v.optional(v.number()),
expectedCredentialVersion: v.optional(v.number()),
},
handler: async (ctx, args) => {
assertBridge(args.bridgeSecret);
assertDeploymentCapability('asset_sync');
@@ -722,6 +739,19 @@ export const bridgeBeginSync = mutationGeneric({
if (character.authorizationStatus !== "active" || !character.scopes.includes("esi-assets.read_assets.v1")) {
throw new Error("Asset authorization is not active");
}
if (args.expectedGrantRevision !== undefined && args.expectedGrantRevision !== character.grantRevision) {
throw new Error("Synchronization authorization changed before lease");
}
if (args.expectedAuthorizationEpoch !== undefined && args.expectedAuthorizationEpoch !== character.authorizationEpoch) {
throw new Error("Synchronization authorization changed before lease");
}
if (args.expectedCredentialVersion !== undefined && args.expectedCredentialVersion !== character.credentialVersion) {
throw new Error("Synchronization credential changed before lease");
}
if (args.expectedScopes !== undefined
&& JSON.stringify([...args.expectedScopes].sort()) !== JSON.stringify([...character.scopes].sort())) {
throw new Error("Synchronization scopes changed before lease");
}
const timestamp = now();
if (character.syncGeneration && (character.syncLeaseExpiresAt ?? 0) > timestamp) {
throw new Error("Character synchronization is already leased");