fix(puter-js): return key_undefined for missing kv keys (#3803)

get/del/incr/decr/add/expire/expireAt only checked size, so undefined keys threw TypeError. Add assertKeyPresent first, matching set/update/remove.
This commit is contained in:
Felix-Ayush
2026-09-08 22:32:53 -07:00
committed by GitHub
parent cdc524f504
commit d7877359d4
8 changed files with 30 additions and 7 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
import * as utils from '../../lib/utils.js';
import { isObject, isOptConfigShorthand } from './lib/args.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVAddPath} KVAddPath */
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -55,6 +55,7 @@ export async function add (keyOrOptions, valueOrMap, optConfig) {
};
}
assertKeyPresent(options.key);
assertKeySize(options.key);
return await utils.makeDriverMethod({ iface: 'puter-kvstore', method: 'add', argNames: ['key'], puter: this.puter })(options);
}
+2 -1
View File
@@ -1,6 +1,6 @@
import * as utils from '../../lib/utils.js';
import { parseCounterArgs } from './lib/args.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVIncrementPath} KVIncrementPath */
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -33,6 +33,7 @@ import { assertKeySize } from './lib/validate.js';
*/
export async function decr (keyOrOptions, amountOrMap, optConfig) {
const options = parseCounterArgs(keyOrOptions, amountOrMap, optConfig);
assertKeyPresent(options.key);
assertKeySize(options.key);
return await utils.makeDriverMethod({ iface: 'puter-kvstore', method: 'decr', argNames: ['key'], puter: this.puter })(options);
}
+2 -1
View File
@@ -1,6 +1,6 @@
import * as utils from '../../lib/utils.js';
import { isObject, parseOptConfigThenCallbacks } from './lib/args.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -11,6 +11,7 @@ const delDriverCall = (puter, args) =>
argNames: ['key'],
puter,
preprocess: (driverArgs) => {
assertKeyPresent(driverArgs.key);
assertKeySize(driverArgs.key);
return driverArgs;
},
+2 -1
View File
@@ -1,5 +1,5 @@
import * as utils from '../../lib/utils.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -22,6 +22,7 @@ import { assertKeySize } from './lib/validate.js';
* @returns {Promise<boolean>}
*/
export async function expire (key, ttl, optConfig) {
assertKeyPresent(key);
assertKeySize(key);
return await utils.makeDriverMethod({ iface: 'puter-kvstore', method: 'expire', argNames: ['key', 'ttl'], puter: this.puter })({ key, ttl, optConfig });
}
+2 -1
View File
@@ -1,5 +1,5 @@
import * as utils from '../../lib/utils.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -23,6 +23,7 @@ import { assertKeySize } from './lib/validate.js';
* @returns {Promise<boolean>}
*/
export async function expireAt (key, timestamp, optConfig) {
assertKeyPresent(key);
assertKeySize(key);
return await utils.makeDriverMethod({ iface: 'puter-kvstore', method: 'expireAt', argNames: ['key', 'timestamp'], puter: this.puter })({ key, timestamp, optConfig });
}
+2 -1
View File
@@ -1,6 +1,6 @@
import * as utils from '../../lib/utils.js';
import { isObject, parseOptConfigThenCallbacks } from './lib/args.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -12,6 +12,7 @@ const getDriverCall = (puter, args) =>
puter,
readonly: true,
preprocess: (driverArgs) => {
assertKeyPresent(driverArgs.key);
assertKeySize(driverArgs.key);
return driverArgs;
},
+2 -1
View File
@@ -1,6 +1,6 @@
import * as utils from '../../lib/utils.js';
import { parseCounterArgs } from './lib/args.js';
import { assertKeySize } from './lib/validate.js';
import { assertKeyPresent, assertKeySize } from './lib/validate.js';
/** @typedef {import('./types.js').KVIncrementPath} KVIncrementPath */
/** @typedef {import('./types.js').KVOptConfig} KVOptConfig */
@@ -33,6 +33,7 @@ import { assertKeySize } from './lib/validate.js';
*/
export async function incr (keyOrOptions, amountOrMap, optConfig) {
const options = parseCounterArgs(keyOrOptions, amountOrMap, optConfig);
assertKeyPresent(options.key);
assertKeySize(options.key);
return await utils.makeDriverMethod({ iface: 'puter-kvstore', method: 'incr', argNames: ['key'], puter: this.puter })(options);
}
+16
View File
@@ -232,6 +232,11 @@ describe('kv.get driver payloads', () => {
await expect(kv.get('k'.repeat(1025))).rejects.toMatchObject({ code: 'key_too_large' });
expect(FakeXHR.requests).toHaveLength(0);
});
it('rejects an undefined key without a request', async () => {
await expect(kv.get(undefined)).rejects.toMatchObject({ code: 'key_undefined' });
expect(FakeXHR.requests).toHaveLength(0);
});
});
describe('kv.get GUI boot cache', () => {
@@ -487,6 +492,12 @@ describe('kv.expire / kv.expireAt driver payloads', () => {
await expect(kv.expireAt(bigKey, 1)).rejects.toMatchObject({ code: 'key_too_large' });
expect(FakeXHR.requests).toHaveLength(0);
});
it('both reject an undefined key without a request', async () => {
await expect(kv.expire(undefined, 60)).rejects.toMatchObject({ code: 'key_undefined' });
await expect(kv.expireAt(undefined, 1)).rejects.toMatchObject({ code: 'key_undefined' });
expect(FakeXHR.requests).toHaveLength(0);
});
});
describe('kv.del driver payloads', () => {
@@ -511,6 +522,11 @@ describe('kv.del driver payloads', () => {
await expect(kv.del('k'.repeat(1025))).rejects.toMatchObject({ code: 'key_too_large' });
expect(FakeXHR.requests).toHaveLength(0);
});
it('rejects an undefined key without a request', async () => {
await expect(kv.del(undefined)).rejects.toMatchObject({ code: 'key_undefined' });
expect(FakeXHR.requests).toHaveLength(0);
});
});
describe('kv.list driver payloads', () => {