diff --git a/js/nostr/nip07Permissions.js b/js/nostr/nip07Permissions.js index 30826c92..e28c4c4e 100644 --- a/js/nostr/nip07Permissions.js +++ b/js/nostr/nip07Permissions.js @@ -328,13 +328,13 @@ export async function requestEnablePermissions( : []; const permissionVariants = []; - permissionVariants.push(null); if (normalized.length) { permissionVariants.push({ permissions: normalized.map((method) => ({ method })), }); permissionVariants.push({ permissions: normalized }); } + permissionVariants.push(null); const enableTimeoutMs = getEnableVariantTimeoutMs(); const loginTimeoutMs = getNip07LoginTimeoutMs(); diff --git a/tests/nostr-login-permissions.test.mjs b/tests/nostr-login-permissions.test.mjs index 431ca902..a3a5359b 100644 --- a/tests/nostr-login-permissions.test.mjs +++ b/tests/nostr-login-permissions.test.mjs @@ -312,18 +312,15 @@ test("NIP-07 login falls back when structured permissions fail", async () => { const result = await nip07Provider.login({ nostrClient }); const pubkey = result.pubkey; assert.equal(pubkey, HEX_PUBKEY); - assert.ok(env.enableCalls.length >= 3, "should retry with alternate payloads"); - const [plainCall, objectCall, stringCall] = env.enableCalls; - assert.equal( - plainCall, - undefined, - "plain enable() should be attempted first", - ); + // With Structured -> String -> Plain order, this succeeds at step 2 (String). + // So we expect 2 calls. + assert.ok(env.enableCalls.length >= 2, "should retry with alternate payloads"); + const [objectCall, stringCall] = env.enableCalls; assert.ok(Array.isArray(objectCall?.permissions)); assert.equal( typeof objectCall.permissions[0], "object", - "structured permission request should be attempted", + "structured permission request should be attempted first", ); assert.ok(Array.isArray(stringCall?.permissions)); assert.equal( @@ -353,13 +350,19 @@ test("NIP-07 login supports extensions that only allow enable() without payload" const result = await nip07Provider.login({ nostrClient }); const pubkey = result.pubkey; assert.equal(pubkey, HEX_PUBKEY); + // With Structured -> String -> Plain order, we expect 3 calls: + // 1. Structured (rejected) + // 2. String (rejected) + // 3. Plain (accepted) assert.equal( env.enableCalls.length, - 1, - "should succeed with plain enable() immediately", + 3, + "should eventually succeed with plain enable()", ); - const [plainCall] = env.enableCalls; - assert.equal(plainCall, undefined, "first attempt should use plain enable()"); + const [objectCall, stringCall, plainCall] = env.enableCalls; + assert.ok(objectCall !== undefined); + assert.ok(stringCall !== undefined); + assert.equal(plainCall, undefined, "last attempt should use plain enable()"); } finally { env.restore(); nostrClient.logout(); @@ -399,9 +402,10 @@ test("NIP-07 login quickly retries when a permission payload stalls", async () = duration < 500, `login should fall back quickly from stalled enable payloads (duration: ${duration}ms)`, ); - assert.equal(env.enableCalls.length, 3, "should attempt plain, structured and string payload variants"); - const [plainCall, objectCall, stringCall] = env.enableCalls; - assert.equal(plainCall, undefined); + // Structured (stalls) -> String (resolves) + // Plain is skipped because String resolved. + assert.equal(env.enableCalls.length, 2, "should attempt structured (stalls) and then string payload"); + const [objectCall, stringCall] = env.enableCalls; assert.ok(Array.isArray(objectCall?.permissions)); assert.equal(typeof objectCall.permissions[0], "object"); assert.ok(Array.isArray(stringCall?.permissions));