@forge/kvs

1.2.7-next.0-experimental-2682d7a1.2.7-next.0-experimental-d997307
out/__test__/index.test.js
out/__test__/index.test.js
+432−18
Index: package/out/__test__/index.test.js
===================================================================
--- package/out/__test__/index.test.js
+++ package/out/__test__/index.test.js
@@ -29,28 +29,67 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/get', expect.objectContaining({
             body: JSON.stringify({ key: 'foo' })
         }));
     });
-    it('should get with metadata fields correctly', async () => {
-        const response = new Response(JSON.stringify({ key: 'foo', value: 'bar', createdAt: 1718236800, updatedAt: 1718236800 }), {
+    it('should get with metadata fields correctly for get', async () => {
+        const response = new Response(JSON.stringify({
+            key: 'foo',
+            value: 'bar',
+            createdAt: 1718236800,
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
+        }), {
             status: 200,
             headers: { 'x-trace-id': traceId }
         });
         const { sut, apiClient } = prepare(response);
-        const rs = await sut.get('foo', { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] });
+        const rs = await sut.get('foo', {
+            metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
         expect(rs).toEqual({
             key: 'foo',
             value: 'bar',
             createdAt: 1718236800,
-            updatedAt: 1718236800
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
         });
         expect(apiClient).toHaveBeenCalledWith('/api/v1/get', expect.objectContaining({
             body: JSON.stringify({
                 key: 'foo',
-                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] }
+                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME] }
             })
         }));
     });
+    it('should get with metadata fields correctly for entity.get', async () => {
+        const response = new Response(JSON.stringify({
+            key: 'key-foo',
+            value: { foo: 'bar' },
+            createdAt: 1718236800,
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
+        }), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.entity('foo').get('key-foo', {
+            metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual({
+            key: 'key-foo',
+            value: { foo: 'bar' },
+            createdAt: 1718236800,
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
+        });
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/get', expect.objectContaining({
+            body: JSON.stringify({
+                entityName: 'foo',
+                key: 'key-foo',
+                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME] }
+            })
+        }));
+    });
     it('should return undefined when get receives 404', async () => {
         const response = new Response(JSON.stringify({ code: 'KEY_NOT_FOUND', message: 'Provided key does not exist' }), {
             status: 404,
             headers: { 'x-trace-id': traceId }
@@ -103,24 +142,33 @@
             body: JSON.stringify({ key: 'foo' })
         }));
     });
     it('should getSecret with metadata fields correctly', async () => {
-        const response = new Response(JSON.stringify({ key: 'foo', value: 'bar', createdAt: 1718236800, updatedAt: 1718236800 }), {
+        const response = new Response(JSON.stringify({
+            key: 'foo',
+            value: 'bar',
+            createdAt: 1718236800,
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
+        }), {
             status: 200,
             headers: { 'x-trace-id': traceId }
         });
         const { sut, apiClient } = prepare(response);
-        const rs = await sut.getSecret('foo', { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] });
+        const rs = await sut.getSecret('foo', {
+            metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
         expect(rs).toEqual({
             key: 'foo',
             value: 'bar',
             createdAt: 1718236800,
-            updatedAt: 1718236800
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
         });
         expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/get', expect.objectContaining({
             body: JSON.stringify({
                 key: 'foo',
-                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] }
+                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME] }
             })
         }));
     });
     it('should return undefined when getSecret receives 404', async () => {
@@ -147,27 +195,34 @@
             body: JSON.stringify({ entityName: 'employees', key: 'foo' })
         }));
     });
     it('should getEntity with metadata fields correctly', async () => {
-        const response = new Response(JSON.stringify({ key: 'foo', value: { name: 'Jane Doe' }, createdAt: 1718236800, updatedAt: 1718236800 }), {
+        const response = new Response(JSON.stringify({
+            key: 'foo',
+            value: { name: 'Jane Doe' },
+            createdAt: 1718236800,
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
+        }), {
             status: 200,
             headers: { 'x-trace-id': traceId }
         });
         const { sut, apiClient } = prepare(response);
         const rs = await sut
             .entity('employees')
-            .get('foo', { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] });
+            .get('foo', { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME] });
         expect(rs).toEqual({
             key: 'foo',
             value: { name: 'Jane Doe' },
             createdAt: 1718236800,
-            updatedAt: 1718236800
+            updatedAt: 1718236800,
+            expireTime: '2025-01-12T13:00:00Z'
         });
         expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/get', expect.objectContaining({
             body: JSON.stringify({
                 entityName: 'employees',
                 key: 'foo',
-                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT] }
+                options: { metadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME] }
             })
         }));
     });
     it('should return undefined when getEntity receives 404', async () => {
@@ -193,8 +248,95 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/set', expect.objectContaining({
             body: JSON.stringify({ key: 'foo', value: 'bar' })
         }));
     });
+    it('should set correctly with TTL', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.set('foo', 'bar', { ttl: { value: 5, unit: 'MINUTES' } });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/set', expect.objectContaining({
+            body: JSON.stringify({ key: 'foo', value: 'bar', options: { ttl: { value: 5, unit: 'MINUTES' } } })
+        }));
+    });
+    it('should set correctly with keyPolicy "FAIL_IF_EXISTS"', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.set('foo', 'bar', { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' }
+            })
+        }));
+    });
+    it('should set correctly with keyPolicy "OVERRIDE" and return value', async () => {
+        const responseBody = {
+            key: 'foo',
+            value: 'bar',
+            createdAt: Date.now(),
+            updatedAt: Date.now(),
+            expireTime: '2025-01-12T13:00:00Z'
+        };
+        const response = new Response(JSON.stringify(responseBody), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.set('foo', 'bar', {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'LATEST',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual(responseBody);
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'LATEST',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
+    it('should set and return undefined when no previous value exists', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.set('foo', 'bar', {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'PREVIOUS',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual(undefined);
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'PREVIOUS',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
     it('should setSecret correctly', async () => {
         const response = new Response(undefined, {
             status: 204,
             headers: { 'x-trace-id': traceId }
@@ -205,8 +347,95 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/set', expect.objectContaining({
             body: JSON.stringify({ key: 'foo', value: 'bar' })
         }));
     });
+    it('should setSecret correctly with TTL', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.setSecret('foo', 'bar', { ttl: { value: 5, unit: 'MINUTES' } });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/set', expect.objectContaining({
+            body: JSON.stringify({ key: 'foo', value: 'bar', options: { ttl: { value: 5, unit: 'MINUTES' } } })
+        }));
+    });
+    it('should setSecret correctly with keyPolicy "FAIL_IF_EXISTS"', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.setSecret('foo', 'bar', { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' }
+            })
+        }));
+    });
+    it('should setSecret correctly with keyPolicy "OVERRIDE" and return value', async () => {
+        const responseBody = {
+            key: 'foo',
+            value: 'bar',
+            createdAt: Date.now(),
+            updatedAt: Date.now(),
+            expireTime: '2025-01-12T13:00:00Z'
+        };
+        const response = new Response(JSON.stringify(responseBody), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.setSecret('foo', 'bar', {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'LATEST',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual(responseBody);
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'LATEST',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
+    it('should setSecret and return undefined when no previous value exists', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.setSecret('foo', 'bar', {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'PREVIOUS',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual(undefined);
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/secret/set', expect.objectContaining({
+            body: JSON.stringify({
+                key: 'foo',
+                value: 'bar',
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'PREVIOUS',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
     it('should setEntity correctly', async () => {
         const response = new Response(undefined, {
             status: 204,
             headers: { 'x-trace-id': traceId }
@@ -217,8 +446,105 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/set', expect.objectContaining({
             body: JSON.stringify({ entityName: 'employees', key: 'foo', value: { name: 'Jane Doe' } })
         }));
     });
+    it('should setEntity correctly with TTL', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.entity('employees').set('foo', { name: 'Jane Doe' }, { ttl: { value: 5, unit: 'MINUTES' } });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/set', expect.objectContaining({
+            body: JSON.stringify({
+                entityName: 'employees',
+                key: 'foo',
+                value: { name: 'Jane Doe' },
+                options: { ttl: { value: 5, unit: 'MINUTES' } }
+            })
+        }));
+    });
+    it('should setEntity correctly with "FAIL_IF_EXISTS"', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut
+            .entity('employees')
+            .set('foo', { name: 'Jane Doe' }, { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/set', expect.objectContaining({
+            body: JSON.stringify({
+                entityName: 'employees',
+                key: 'foo',
+                value: { name: 'Jane Doe' },
+                options: { ttl: { value: 5, unit: 'MINUTES' }, keyPolicy: 'FAIL_IF_EXISTS' }
+            })
+        }));
+    });
+    it('should setEntity correctly with "OVERRIDE" and return value', async () => {
+        const responseBody = {
+            key: 'foo',
+            value: 'bar',
+            createdAt: Date.now(),
+            updatedAt: Date.now(),
+            expireTime: '2025-01-12T13:00:00Z'
+        };
+        const response = new Response(JSON.stringify(responseBody), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.entity('employees').set('foo', { name: 'Jane Doe' }, {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'LATEST',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toEqual(responseBody);
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/set', expect.objectContaining({
+            body: JSON.stringify({
+                entityName: 'employees',
+                key: 'foo',
+                value: { name: 'Jane Doe' },
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'LATEST',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
+    it('should setEntity and return undefined when no previous value exists', async () => {
+        const response = new Response(undefined, {
+            status: 204,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut.entity('employees').set('foo', { name: 'Jane Doe' }, {
+            ttl: { value: 5, unit: 'MINUTES' },
+            keyPolicy: 'OVERRIDE',
+            returnValue: 'PREVIOUS',
+            returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+        });
+        expect(rs).toBeUndefined();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/set', expect.objectContaining({
+            body: JSON.stringify({
+                entityName: 'employees',
+                key: 'foo',
+                value: { name: 'Jane Doe' },
+                options: {
+                    ttl: { value: 5, unit: 'MINUTES' },
+                    keyPolicy: 'OVERRIDE',
+                    returnValue: 'PREVIOUS',
+                    returnMetadataFields: [types_1.MetadataField.CREATED_AT, types_1.MetadataField.UPDATED_AT, types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
     it('should delete correctly', async () => {
         const response = new Response(undefined, {
             status: 204,
             headers: { 'x-trace-id': traceId }
@@ -313,8 +639,38 @@
                 where: [{ property: 'key', condition: 'BEGINS_WITH', values: ['fo'] }]
             })
         }));
     });
+    it('should query correctly with TTL fields', async () => {
+        const response = new Response(JSON.stringify({
+            cursor: 'third-page',
+            data: [{ key: 'foo', value: 'bar', expireTime: '2025-01-12T13:00:00Z' }]
+        }), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const rs = await sut
+            .query({ metadataFields: [types_1.MetadataField.EXPIRE_TIME] })
+            .cursor('second-page')
+            .limit(1)
+            .where('key', conditions_1.WhereConditions.beginsWith('fo'))
+            .getMany();
+        expect(rs).toEqual({
+            results: [{ key: 'foo', value: 'bar', expireTime: '2025-01-12T13:00:00Z' }],
+            nextCursor: 'third-page'
+        });
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/query', expect.objectContaining({
+            body: JSON.stringify({
+                limit: 1,
+                after: 'second-page',
+                where: [{ property: 'key', condition: 'BEGINS_WITH', values: ['fo'] }],
+                options: {
+                    metadataFields: [types_1.MetadataField.EXPIRE_TIME]
+                }
+            })
+        }));
+    });
     it('should getOne out of a list of results', async () => {
         const response = new Response(JSON.stringify({
             data: [
                 { key: 'foo', value: 'bar' },
@@ -342,27 +698,30 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/query', expect.objectContaining({
             body: JSON.stringify({ limit: 1 })
         }));
     });
-    it('should query entity correctly and pass partition with index', async () => {
-        const response = new Response(JSON.stringify({ data: [{ key: 'foo', value: { name: 'Jane Doe' } }] }), {
+    it('should query entity correctly and pass partition with index and metadata fields', async () => {
+        const response = new Response(JSON.stringify({ data: [{ key: 'foo', value: { name: 'Jane Doe' }, expireTime: '2025-01-12T13:00:00Z' }] }), {
             status: 200,
             headers: { 'x-trace-id': traceId }
         });
         const { sut, apiClient } = prepare(response);
         const rs = await sut
             .entity('employees')
-            .query()
+            .query({ metadataFields: [types_1.MetadataField.EXPIRE_TIME] })
             .index('by-employmentyear', { partition: [2000] })
             .getMany();
         expect(rs).toEqual({
-            results: [{ key: 'foo', value: { name: 'Jane Doe' } }]
+            results: [{ key: 'foo', value: { name: 'Jane Doe' }, expireTime: '2025-01-12T13:00:00Z' }]
         });
         expect(apiClient).toHaveBeenCalledWith('/api/v1/entity/query', expect.objectContaining({
             body: JSON.stringify({
                 entityName: 'employees',
                 indexName: 'by-employmentyear',
-                partition: [2000]
+                partition: [2000],
+                options: {
+                    metadataFields: [types_1.MetadataField.EXPIRE_TIME]
+                }
             })
         }));
     });
     it('should query entity correctly (without any filters)', async () => {
@@ -657,8 +1016,26 @@
                 delete: [{ key: 'bar' }]
             })
         }));
     });
+    it('should sumbit transaction correctly with TTL', async () => {
+        const response = new Response(undefined, {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        await sut
+            .transact()
+            .set('foo', 'bar', undefined, { ttl: { unit: 'SECONDS', value: 5 } })
+            .delete('bar')
+            .execute();
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/transaction', expect.objectContaining({
+            body: JSON.stringify({
+                set: [{ key: 'foo', value: 'bar', options: { ttl: { unit: 'SECONDS', value: 5 } } }],
+                delete: [{ key: 'bar' }]
+            })
+        }));
+    });
     it('should batchSet correctly with mixed entity and non-entity items', async () => {
         const response = new Response(JSON.stringify({
             successfulKeys: [{ key: 'foo', entityName: 'employees' }, { key: 'bar' }],
             failedKeys: [
@@ -692,8 +1069,45 @@
         expect(apiClient).toHaveBeenCalledWith('/api/v1/batch/set', expect.objectContaining({
             body: JSON.stringify(items)
         }));
     });
+    it('should batchSet correctly with mixed entity and non-entity items with TTL', async () => {
+        const response = new Response(JSON.stringify({
+            successfulKeys: [{ key: 'foo', entityName: 'employees' }, { key: 'bar' }, { key: 'xxx' }],
+            failedKeys: [
+                {
+                    key: 'baz',
+                    entityName: 'departments',
+                    error: { code: 'VALIDATION_ERROR', message: 'Invalid value' }
+                }
+            ]
+        }), {
+            status: 200,
+            headers: { 'x-trace-id': traceId }
+        });
+        const { sut, apiClient } = prepare(response);
+        const ttl = { value: 10, unit: 'MINUTES' };
+        const items = [
+            { key: 'foo', value: 'John Doe', entityName: 'employees', options: { ttl } },
+            { key: 'bar', value: 'simple value', options: { ttl } },
+            { key: 'baz', value: 'IT Department', entityName: 'departments', options: { ttl } },
+            { key: 'xxx', value: 'yyy', options: { ttl } }
+        ];
+        const rs = await sut.batchSet(items);
+        expect(rs).toEqual({
+            successfulKeys: [{ key: 'foo', entityName: 'employees' }, { key: 'bar' }, { key: 'xxx' }],
+            failedKeys: [
+                {
+                    key: 'baz',
+                    entityName: 'departments',
+                    error: { code: 'VALIDATION_ERROR', message: 'Invalid value' }
+                }
+            ]
+        });
+        expect(apiClient).toHaveBeenCalledWith('/api/v1/batch/set', expect.objectContaining({
+            body: JSON.stringify(items)
+        }));
+    });
     it('should handle batchSet with all successful keys', async () => {
         const response = new Response(JSON.stringify({
             successfulKeys: [{ key: 'foo' }, { key: 'bar' }],
             failedKeys: []