@bsv/sdk 1.8.7 → 1.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +7 -2
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/cjs/src/kvstore/GlobalKVStore.js +26 -4
- package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js +7 -3
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/cjs/src/kvstore/types.js +2 -1
- package/dist/cjs/src/kvstore/types.js.map +1 -1
- package/dist/cjs/src/overlay-tools/LookupResolver.js +7 -2
- package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +7 -2
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/esm/src/kvstore/GlobalKVStore.js +26 -4
- package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/kvStoreInterpreter.js +7 -3
- package/dist/esm/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/esm/src/kvstore/types.js +2 -1
- package/dist/esm/src/kvstore/types.js.map +1 -1
- package/dist/esm/src/overlay-tools/LookupResolver.js +7 -2
- package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts +1 -1
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts.map +1 -1
- package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
- package/dist/types/src/kvstore/kvStoreInterpreter.d.ts +2 -1
- package/dist/types/src/kvstore/kvStoreInterpreter.d.ts.map +1 -1
- package/dist/types/src/kvstore/types.d.ts +10 -0
- package/dist/types/src/kvstore/types.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/dist/umd/bundle.js.map +1 -1
- package/docs/reference/kvstore.md +20 -2
- package/package.json +1 -1
- package/src/auth/transports/SimplifiedFetchTransport.ts +10 -2
- package/src/kvstore/GlobalKVStore.ts +33 -8
- package/src/kvstore/__tests/GlobalKVStore.test.ts +129 -0
- package/src/kvstore/kvStoreInterpreter.ts +8 -3
- package/src/kvstore/types.ts +11 -1
- package/src/overlay-tools/LookupResolver.ts +10 -2
|
@@ -169,6 +169,7 @@ export interface KVStoreEntry {
|
|
|
169
169
|
value: string;
|
|
170
170
|
controller: PubKeyHex;
|
|
171
171
|
protocolID: WalletProtocol;
|
|
172
|
+
tags?: string[];
|
|
172
173
|
token?: KVStoreToken;
|
|
173
174
|
history?: string[];
|
|
174
175
|
}
|
|
@@ -246,6 +247,8 @@ export interface KVStoreQuery {
|
|
|
246
247
|
key?: string;
|
|
247
248
|
controller?: PubKeyHex;
|
|
248
249
|
protocolID?: WalletProtocol;
|
|
250
|
+
tags?: string[];
|
|
251
|
+
tagQueryMode?: "all" | "any";
|
|
249
252
|
limit?: number;
|
|
250
253
|
skip?: number;
|
|
251
254
|
sortOrder?: "asc" | "desc";
|
|
@@ -254,6 +257,16 @@ export interface KVStoreQuery {
|
|
|
254
257
|
|
|
255
258
|
See also: [PubKeyHex](./wallet.md#type-pubkeyhex), [WalletProtocol](./wallet.md#type-walletprotocol)
|
|
256
259
|
|
|
260
|
+
#### Property tagQueryMode
|
|
261
|
+
|
|
262
|
+
Controls tag matching behavior when tags are specified.
|
|
263
|
+
- 'all': Requires all specified tags to be present (default)
|
|
264
|
+
- 'any': Requires at least one of the specified tags to be present
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
tagQueryMode?: "all" | "any"
|
|
268
|
+
```
|
|
269
|
+
|
|
257
270
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
|
|
258
271
|
|
|
259
272
|
---
|
|
@@ -279,6 +292,7 @@ export interface KVStoreSetOptions {
|
|
|
279
292
|
tokenSetDescription?: string;
|
|
280
293
|
tokenUpdateDescription?: string;
|
|
281
294
|
tokenAmount?: number;
|
|
295
|
+
tags?: string[];
|
|
282
296
|
}
|
|
283
297
|
```
|
|
284
298
|
|
|
@@ -577,7 +591,8 @@ kvProtocol = {
|
|
|
577
591
|
key: 1,
|
|
578
592
|
value: 2,
|
|
579
593
|
controller: 3,
|
|
580
|
-
|
|
594
|
+
tags: 4,
|
|
595
|
+
signature: 5
|
|
581
596
|
}
|
|
582
597
|
```
|
|
583
598
|
|
|
@@ -595,7 +610,10 @@ kvStoreInterpreter: InterpreterFunction<string, KVContext> = async (transaction:
|
|
|
595
610
|
if (ctx == null || ctx.key == null)
|
|
596
611
|
return undefined;
|
|
597
612
|
const decoded = PushDrop.decode(output.lockingScript);
|
|
598
|
-
|
|
613
|
+
const expectedFieldCount = Object.keys(kvProtocol).length;
|
|
614
|
+
const hasTagsField = decoded.fields.length === expectedFieldCount;
|
|
615
|
+
const isOldFormat = decoded.fields.length === expectedFieldCount - 1;
|
|
616
|
+
if (!isOldFormat && !hasTagsField)
|
|
599
617
|
return undefined;
|
|
600
618
|
const key = Utils.toUTF8(decoded.fields[kvProtocol.key]);
|
|
601
619
|
const protocolID = Utils.toUTF8(decoded.fields[kvProtocol.protocolID]);
|
package/package.json
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
import { AuthMessage, RequestedCertificateSet, Transport } from '../types.js'
|
|
4
4
|
import * as Utils from '../../primitives/utils.js'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const defaultFetch: typeof fetch =
|
|
7
|
+
typeof globalThis !== 'undefined' && typeof globalThis.fetch === 'function'
|
|
8
|
+
? globalThis.fetch.bind(globalThis)
|
|
9
|
+
: fetch
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Implements an HTTP-specific transport for handling Peer mutual authentication messages.
|
|
@@ -21,6 +23,12 @@ export class SimplifiedFetchTransport implements Transport {
|
|
|
21
23
|
* @param fetchClient - A fetch implementation to use for HTTP requests (default: global fetch).
|
|
22
24
|
*/
|
|
23
25
|
constructor (baseUrl: string, fetchClient = defaultFetch) {
|
|
26
|
+
if (typeof fetchClient !== 'function') {
|
|
27
|
+
throw new Error(
|
|
28
|
+
'SimplifiedFetchTransport requires a fetch implementation. ' +
|
|
29
|
+
'In environments without fetch, provide a polyfill or custom implementation.'
|
|
30
|
+
)
|
|
31
|
+
}
|
|
24
32
|
this.fetchClient = fetchClient
|
|
25
33
|
this.baseUrl = baseUrl
|
|
26
34
|
}
|
|
@@ -138,6 +138,7 @@ export class GlobalKVStore {
|
|
|
138
138
|
const tokenSetDescription = (options.tokenSetDescription != null && options.tokenSetDescription !== '') ? options.tokenSetDescription : `Create KVStore value for ${key}`
|
|
139
139
|
const tokenUpdateDescription = (options.tokenUpdateDescription != null && options.tokenUpdateDescription !== '') ? options.tokenUpdateDescription : `Update KVStore value for ${key}`
|
|
140
140
|
const tokenAmount = options.tokenAmount ?? this.config.tokenAmount
|
|
141
|
+
const tags = options.tags ?? []
|
|
141
142
|
|
|
142
143
|
try {
|
|
143
144
|
// Check for existing token to spend
|
|
@@ -146,13 +147,20 @@ export class GlobalKVStore {
|
|
|
146
147
|
|
|
147
148
|
// Create PushDrop locking script
|
|
148
149
|
const pushdrop = new PushDrop(this.wallet, this.config.originator)
|
|
150
|
+
const lockingScriptFields = [
|
|
151
|
+
Utils.toArray(JSON.stringify(protocolID), 'utf8'),
|
|
152
|
+
Utils.toArray(key, 'utf8'),
|
|
153
|
+
Utils.toArray(value, 'utf8'),
|
|
154
|
+
Utils.toArray(controller, 'hex')
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
// Add tags as optional 5th field for backwards compatibility
|
|
158
|
+
if (tags.length > 0) {
|
|
159
|
+
lockingScriptFields.push(Utils.toArray(JSON.stringify(tags), 'utf8'))
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
const lockingScript = await pushdrop.lock(
|
|
150
|
-
|
|
151
|
-
Utils.toArray(JSON.stringify(protocolID), 'utf8'),
|
|
152
|
-
Utils.toArray(key, 'utf8'),
|
|
153
|
-
Utils.toArray(value, 'utf8'),
|
|
154
|
-
Utils.toArray(controller, 'hex')
|
|
155
|
-
],
|
|
163
|
+
lockingScriptFields,
|
|
156
164
|
protocolID ?? this.config.protocolID as WalletProtocol,
|
|
157
165
|
Utils.toUTF8(Utils.toArray(key, 'utf8')),
|
|
158
166
|
'anyone',
|
|
@@ -409,7 +417,12 @@ export class GlobalKVStore {
|
|
|
409
417
|
const output = tx.outputs[result.outputIndex]
|
|
410
418
|
const decoded = PushDrop.decode(output.lockingScript)
|
|
411
419
|
|
|
412
|
-
|
|
420
|
+
// Support backwards compatibility: old format without tags, new format with tags
|
|
421
|
+
const expectedFieldCount = Object.keys(kvProtocol).length
|
|
422
|
+
const hasTagsField = decoded.fields.length === expectedFieldCount
|
|
423
|
+
const isOldFormat = decoded.fields.length === expectedFieldCount - 1
|
|
424
|
+
|
|
425
|
+
if (!isOldFormat && !hasTagsField) {
|
|
413
426
|
continue
|
|
414
427
|
}
|
|
415
428
|
|
|
@@ -429,11 +442,23 @@ export class GlobalKVStore {
|
|
|
429
442
|
continue
|
|
430
443
|
}
|
|
431
444
|
|
|
445
|
+
// Extract tags if present (backwards compatible)
|
|
446
|
+
let tags: string[] | undefined
|
|
447
|
+
if (hasTagsField && decoded.fields[kvProtocol.tags] != null) {
|
|
448
|
+
try {
|
|
449
|
+
tags = JSON.parse(Utils.toUTF8(decoded.fields[kvProtocol.tags]))
|
|
450
|
+
} catch (e) {
|
|
451
|
+
// If tags parsing fails, continue without tags
|
|
452
|
+
tags = undefined
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
432
456
|
const entry: KVStoreEntry = {
|
|
433
457
|
key: Utils.toUTF8(decoded.fields[kvProtocol.key]),
|
|
434
458
|
value: Utils.toUTF8(decoded.fields[kvProtocol.value]),
|
|
435
459
|
controller: Utils.toHex(decoded.fields[kvProtocol.controller]),
|
|
436
|
-
protocolID: JSON.parse(Utils.toUTF8(decoded.fields[kvProtocol.protocolID]))
|
|
460
|
+
protocolID: JSON.parse(Utils.toUTF8(decoded.fields[kvProtocol.protocolID])),
|
|
461
|
+
tags
|
|
437
462
|
}
|
|
438
463
|
|
|
439
464
|
if (options.includeToken === true) {
|
|
@@ -287,6 +287,46 @@ describe('GlobalKVStore', () => {
|
|
|
287
287
|
})
|
|
288
288
|
})
|
|
289
289
|
|
|
290
|
+
it('returns entry with tags when token includes tags field', async () => {
|
|
291
|
+
primeResolverWithOneOutput(mockResolver)
|
|
292
|
+
|
|
293
|
+
const originalDecode = (MockPushDrop as any).decode
|
|
294
|
+
;(MockPushDrop as any).decode = jest.fn().mockReturnValue({
|
|
295
|
+
fields: [
|
|
296
|
+
Array.from(Buffer.from(JSON.stringify([1, 'kvstore']))), // protocolID
|
|
297
|
+
Array.from(Buffer.from(TEST_KEY)), // key
|
|
298
|
+
Array.from(Buffer.from(TEST_VALUE)), // value
|
|
299
|
+
Array.from(Buffer.from(TEST_CONTROLLER, 'hex')), // controller
|
|
300
|
+
// tags field as JSON string so Utils.toUTF8 returns it directly
|
|
301
|
+
'["alpha","beta"]',
|
|
302
|
+
Array.from(Buffer.from('signature')) // signature
|
|
303
|
+
]
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
const result = await kvStore.get({ key: TEST_KEY })
|
|
307
|
+
|
|
308
|
+
expect(Array.isArray(result)).toBe(true)
|
|
309
|
+
expect(result).toHaveLength(1)
|
|
310
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
311
|
+
expect(result[0].tags).toEqual(['alpha', 'beta'])
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
;(MockPushDrop as any).decode = originalDecode
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('omits tags when token is in old-format (no tags field)', async () => {
|
|
318
|
+
primeResolverWithOneOutput(mockResolver)
|
|
319
|
+
|
|
320
|
+
// primePushDropDecodeToValidValue() already sets old-format (no tags)
|
|
321
|
+
const result = await kvStore.get({ key: TEST_KEY })
|
|
322
|
+
|
|
323
|
+
expect(Array.isArray(result)).toBe(true)
|
|
324
|
+
expect(result).toHaveLength(1)
|
|
325
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
326
|
+
expect(result[0].tags).toBeUndefined()
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
290
330
|
it('returns entry with history when history=true', async () => {
|
|
291
331
|
primeResolverWithOneOutput(mockResolver)
|
|
292
332
|
mockHistorian.buildHistory.mockResolvedValue(['oldValue', TEST_VALUE])
|
|
@@ -320,6 +360,67 @@ describe('GlobalKVStore', () => {
|
|
|
320
360
|
})
|
|
321
361
|
})
|
|
322
362
|
|
|
363
|
+
it('forwards tags-only queries to the resolver', async () => {
|
|
364
|
+
primeResolverEmpty(mockResolver)
|
|
365
|
+
|
|
366
|
+
const tags = ['group:music', 'env:prod']
|
|
367
|
+
const result = await kvStore.get({ tags })
|
|
368
|
+
|
|
369
|
+
expect(Array.isArray(result)).toBe(true)
|
|
370
|
+
expect(mockResolver.query).toHaveBeenCalledWith({
|
|
371
|
+
service: 'ls_kvstore',
|
|
372
|
+
query: expect.objectContaining({ tags })
|
|
373
|
+
})
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it('forwards tagQueryMode "all" to the resolver (default)', async () => {
|
|
377
|
+
primeResolverEmpty(mockResolver)
|
|
378
|
+
|
|
379
|
+
const tags = ['music', 'rock']
|
|
380
|
+
const result = await kvStore.get({ tags, tagQueryMode: 'all' })
|
|
381
|
+
|
|
382
|
+
expect(Array.isArray(result)).toBe(true)
|
|
383
|
+
expect(mockResolver.query).toHaveBeenCalledWith({
|
|
384
|
+
service: 'ls_kvstore',
|
|
385
|
+
query: expect.objectContaining({
|
|
386
|
+
tags,
|
|
387
|
+
tagQueryMode: 'all'
|
|
388
|
+
})
|
|
389
|
+
})
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
it('forwards tagQueryMode "any" to the resolver', async () => {
|
|
393
|
+
primeResolverEmpty(mockResolver)
|
|
394
|
+
|
|
395
|
+
const tags = ['music', 'jazz']
|
|
396
|
+
const result = await kvStore.get({ tags, tagQueryMode: 'any' })
|
|
397
|
+
|
|
398
|
+
expect(Array.isArray(result)).toBe(true)
|
|
399
|
+
expect(mockResolver.query).toHaveBeenCalledWith({
|
|
400
|
+
service: 'ls_kvstore',
|
|
401
|
+
query: expect.objectContaining({
|
|
402
|
+
tags,
|
|
403
|
+
tagQueryMode: 'any'
|
|
404
|
+
})
|
|
405
|
+
})
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
it('defaults to tagQueryMode "all" when not specified', async () => {
|
|
409
|
+
primeResolverEmpty(mockResolver)
|
|
410
|
+
|
|
411
|
+
const tags = ['category:news']
|
|
412
|
+
const result = await kvStore.get({ tags })
|
|
413
|
+
|
|
414
|
+
expect(Array.isArray(result)).toBe(true)
|
|
415
|
+
expect(mockResolver.query).toHaveBeenCalledWith({
|
|
416
|
+
service: 'ls_kvstore',
|
|
417
|
+
query: expect.objectContaining({ tags })
|
|
418
|
+
})
|
|
419
|
+
// Verify tagQueryMode is not explicitly set (will default to 'all' on server side)
|
|
420
|
+
const call = (mockResolver.query as jest.Mock).mock.calls[0][0]
|
|
421
|
+
expect(call.query.tagQueryMode).toBeUndefined()
|
|
422
|
+
})
|
|
423
|
+
|
|
323
424
|
it('includes token data when includeToken=true for key queries', async () => {
|
|
324
425
|
primeResolverWithOneOutput(mockResolver)
|
|
325
426
|
|
|
@@ -644,6 +745,34 @@ describe('GlobalKVStore', () => {
|
|
|
644
745
|
expect(mockBroadcaster.broadcast).toHaveBeenCalled()
|
|
645
746
|
})
|
|
646
747
|
|
|
748
|
+
it('includes tags field in locking script when options.tags provided', async () => {
|
|
749
|
+
primeResolverEmpty(mockResolver)
|
|
750
|
+
|
|
751
|
+
// Override PushDrop to capture the instance used within set()
|
|
752
|
+
const originalImpl = (MockPushDrop as any).mockImplementation
|
|
753
|
+
const mockLockingScript = { toHex: () => 'mockLockingScriptHex' }
|
|
754
|
+
const localPushDrop = {
|
|
755
|
+
lock: jest.fn().mockResolvedValue(mockLockingScript),
|
|
756
|
+
unlock: jest.fn().mockReturnValue({
|
|
757
|
+
sign: jest.fn().mockResolvedValue({ toHex: () => 'mockUnlockingScript' })
|
|
758
|
+
})
|
|
759
|
+
}
|
|
760
|
+
;(MockPushDrop as any).mockImplementation(() => localPushDrop as any)
|
|
761
|
+
|
|
762
|
+
const providedTags = ['primary', 'news']
|
|
763
|
+
await kvStore.set(TEST_KEY, TEST_VALUE, { tags: providedTags })
|
|
764
|
+
|
|
765
|
+
// Validate PushDrop.lock was called with 5 fields (protocolID, key, value, controller, tags)
|
|
766
|
+
expect(localPushDrop.lock).toHaveBeenCalled()
|
|
767
|
+
const lockArgs = (localPushDrop.lock as jest.Mock).mock.calls[0]
|
|
768
|
+
const fields = lockArgs[0]
|
|
769
|
+
expect(Array.isArray(fields)).toBe(true)
|
|
770
|
+
expect(fields.length).toBe(5)
|
|
771
|
+
|
|
772
|
+
// Restore original implementation
|
|
773
|
+
;(MockPushDrop as any).mockImplementation = originalImpl
|
|
774
|
+
})
|
|
775
|
+
|
|
647
776
|
it('updates existing token when one exists', async () => {
|
|
648
777
|
// Mock the queryOverlay to return an entry with a token
|
|
649
778
|
const mockQueryOverlay = jest.spyOn(kvStore as any, 'queryOverlay')
|
|
@@ -10,7 +10,8 @@ export interface KVContext { key: string, protocolID: WalletProtocol }
|
|
|
10
10
|
/**
|
|
11
11
|
* KVStore interpreter used by Historian.
|
|
12
12
|
*
|
|
13
|
-
* Validates the KVStore PushDrop tokens: [protocolID, key, value, controller, signature]
|
|
13
|
+
* Validates the KVStore PushDrop tokens: [protocolID, key, value, controller, signature] (old format)
|
|
14
|
+
* or [protocolID, key, value, controller, tags, signature] (new format).
|
|
14
15
|
* Filters outputs by the provided key in the interpreter context.
|
|
15
16
|
* Produces the plaintext value for matching outputs; returns undefined otherwise.
|
|
16
17
|
*
|
|
@@ -30,8 +31,12 @@ export const kvStoreInterpreter: InterpreterFunction<string, KVContext> = async
|
|
|
30
31
|
// Decode the KVStore token
|
|
31
32
|
const decoded = PushDrop.decode(output.lockingScript)
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
-
|
|
34
|
+
// Support backwards compatibility: old format without tags, new format with tags
|
|
35
|
+
const expectedFieldCount = Object.keys(kvProtocol).length
|
|
36
|
+
const hasTagsField = decoded.fields.length === expectedFieldCount
|
|
37
|
+
const isOldFormat = decoded.fields.length === expectedFieldCount - 1
|
|
38
|
+
|
|
39
|
+
if (!isOldFormat && !hasTagsField) return undefined
|
|
35
40
|
|
|
36
41
|
// Only return values for the given key and protocolID
|
|
37
42
|
const key = Utils.toUTF8(decoded.fields[kvProtocol.key])
|
package/src/kvstore/types.ts
CHANGED
|
@@ -41,6 +41,13 @@ export interface KVStoreQuery {
|
|
|
41
41
|
key?: string
|
|
42
42
|
controller?: PubKeyHex
|
|
43
43
|
protocolID?: WalletProtocol
|
|
44
|
+
tags?: string[]
|
|
45
|
+
/**
|
|
46
|
+
* Controls tag matching behavior when tags are specified.
|
|
47
|
+
* - 'all': Requires all specified tags to be present (default)
|
|
48
|
+
* - 'any': Requires at least one of the specified tags to be present
|
|
49
|
+
*/
|
|
50
|
+
tagQueryMode?: 'all' | 'any'
|
|
44
51
|
limit?: number
|
|
45
52
|
skip?: number
|
|
46
53
|
sortOrder?: 'asc' | 'desc'
|
|
@@ -63,6 +70,7 @@ export interface KVStoreSetOptions {
|
|
|
63
70
|
tokenSetDescription?: string
|
|
64
71
|
tokenUpdateDescription?: string
|
|
65
72
|
tokenAmount?: number
|
|
73
|
+
tags?: string[]
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
export interface KVStoreRemoveOptions {
|
|
@@ -78,6 +86,7 @@ export interface KVStoreEntry {
|
|
|
78
86
|
value: string
|
|
79
87
|
controller: PubKeyHex
|
|
80
88
|
protocolID: WalletProtocol
|
|
89
|
+
tags?: string[]
|
|
81
90
|
token?: KVStoreToken
|
|
82
91
|
history?: string[]
|
|
83
92
|
}
|
|
@@ -110,5 +119,6 @@ export const kvProtocol = {
|
|
|
110
119
|
key: 1,
|
|
111
120
|
value: 2,
|
|
112
121
|
controller: 3,
|
|
113
|
-
|
|
122
|
+
tags: 4,
|
|
123
|
+
signature: 5 // Note: signature moves to position 5 when tags are present
|
|
114
124
|
}
|
|
@@ -2,8 +2,10 @@ import { Transaction } from '../transaction/index.js'
|
|
|
2
2
|
import OverlayAdminTokenTemplate from './OverlayAdminTokenTemplate.js'
|
|
3
3
|
import * as Utils from '../primitives/utils.js'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const defaultFetch: typeof fetch =
|
|
6
|
+
typeof globalThis !== 'undefined' && typeof globalThis.fetch === 'function'
|
|
7
|
+
? globalThis.fetch.bind(globalThis)
|
|
8
|
+
: fetch
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* The question asked to the Overlay Services Engine when a consumer of state wishes to look up information.
|
|
@@ -113,6 +115,12 @@ export class HTTPSOverlayLookupFacilitator implements OverlayLookupFacilitator {
|
|
|
113
115
|
allowHTTP: boolean
|
|
114
116
|
|
|
115
117
|
constructor (httpClient = defaultFetch, allowHTTP: boolean = false) {
|
|
118
|
+
if (typeof httpClient !== 'function') {
|
|
119
|
+
throw new Error(
|
|
120
|
+
'HTTPSOverlayLookupFacilitator requires a fetch implementation. ' +
|
|
121
|
+
'In environments without fetch, provide a polyfill or custom implementation.'
|
|
122
|
+
)
|
|
123
|
+
}
|
|
116
124
|
this.fetchClient = httpClient
|
|
117
125
|
this.allowHTTP = allowHTTP
|
|
118
126
|
}
|