nappup 1.9.1 → 2.0.1
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/package.json +5 -8
- package/src/index.js +130 -626
- package/src/services/blossom-upload.js +3 -2
- package/src/services/irfs-upload.js +81 -106
- package/src/services/nostr-signer.js +1 -1
- package/src/services/site-manifest.js +216 -0
- package/bin/GEMINI.md +0 -6
- package/src/helpers/GEMINI.md +0 -12
- package/src/helpers/base36.js +0 -74
- package/src/helpers/base62.js +0 -59
- package/src/helpers/bech32.js +0 -131
- package/src/helpers/nip19.js +0 -112
- package/src/services/GEMINI.md +0 -9
- package/src/services/base93-decoder.js +0 -107
- package/src/services/base93-encoder.js +0 -96
package/src/helpers/bech32.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
const ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
|
|
2
|
-
|
|
3
|
-
const ALPHABET_MAP = {}
|
|
4
|
-
for (let z = 0; z < ALPHABET.length; z++) {
|
|
5
|
-
const x = ALPHABET.charAt(z)
|
|
6
|
-
ALPHABET_MAP[x] = z
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function polymod (values) {
|
|
10
|
-
const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
|
|
11
|
-
let chk = 1
|
|
12
|
-
for (let p = 0; p < values.length; ++p) {
|
|
13
|
-
const top = chk >> 25
|
|
14
|
-
chk = (chk & 0x1ffffff) << 5 ^ values[p]
|
|
15
|
-
for (let i = 0; i < 5; ++i) {
|
|
16
|
-
if ((top >> i) & 1) {
|
|
17
|
-
chk ^= GEN[i]
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return chk
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function hrpExpand (hrp) {
|
|
25
|
-
const ret = []
|
|
26
|
-
for (let p = 0; p < hrp.length; ++p) {
|
|
27
|
-
ret.push(hrp.charCodeAt(p) >> 5)
|
|
28
|
-
}
|
|
29
|
-
ret.push(0)
|
|
30
|
-
for (let p = 0; p < hrp.length; ++p) {
|
|
31
|
-
ret.push(hrp.charCodeAt(p) & 31)
|
|
32
|
-
}
|
|
33
|
-
return ret
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function verifyChecksum (hrp, data) {
|
|
37
|
-
return polymod(hrpExpand(hrp).concat(data)) === 1
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function createChecksum (hrp, data) {
|
|
41
|
-
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0])
|
|
42
|
-
const mod = polymod(values) ^ 1
|
|
43
|
-
const ret = []
|
|
44
|
-
for (let p = 0; p < 6; ++p) {
|
|
45
|
-
ret.push((mod >> 5 * (5 - p)) & 31)
|
|
46
|
-
}
|
|
47
|
-
return ret
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function encode (hrp, data) {
|
|
51
|
-
const combined = data.concat(createChecksum(hrp, data))
|
|
52
|
-
let ret = hrp + '1'
|
|
53
|
-
for (let p = 0; p < combined.length; ++p) {
|
|
54
|
-
ret += ALPHABET.charAt(combined[p])
|
|
55
|
-
}
|
|
56
|
-
return ret
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function decode (bechString, limit = 90) {
|
|
60
|
-
let p
|
|
61
|
-
let hasLower = false
|
|
62
|
-
let hasUpper = false
|
|
63
|
-
for (p = 0; p < bechString.length; ++p) {
|
|
64
|
-
if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
|
|
65
|
-
return null
|
|
66
|
-
}
|
|
67
|
-
if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
|
|
68
|
-
hasLower = true
|
|
69
|
-
}
|
|
70
|
-
if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
|
|
71
|
-
hasUpper = true
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (hasLower && hasUpper) {
|
|
75
|
-
return null
|
|
76
|
-
}
|
|
77
|
-
bechString = bechString.toLowerCase()
|
|
78
|
-
const pos = bechString.lastIndexOf('1')
|
|
79
|
-
if (pos < 1 || pos + 7 > bechString.length || bechString.length > limit) {
|
|
80
|
-
return null
|
|
81
|
-
}
|
|
82
|
-
const hrp = bechString.substring(0, pos)
|
|
83
|
-
const data = []
|
|
84
|
-
for (p = pos + 1; p < bechString.length; ++p) {
|
|
85
|
-
const d = ALPHABET_MAP[bechString.charAt(p)]
|
|
86
|
-
if (d === undefined) {
|
|
87
|
-
return null
|
|
88
|
-
}
|
|
89
|
-
data.push(d)
|
|
90
|
-
}
|
|
91
|
-
if (!verifyChecksum(hrp, data)) {
|
|
92
|
-
return null
|
|
93
|
-
}
|
|
94
|
-
return { hrp, data: data.slice(0, data.length - 6) }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function toWords (data) {
|
|
98
|
-
let value = 0
|
|
99
|
-
let bits = 0
|
|
100
|
-
const maxV = 31
|
|
101
|
-
const result = []
|
|
102
|
-
for (let i = 0; i < data.length; ++i) {
|
|
103
|
-
value = (value << 8) | data[i]
|
|
104
|
-
bits += 8
|
|
105
|
-
while (bits >= 5) {
|
|
106
|
-
bits -= 5
|
|
107
|
-
result.push((value >> bits) & maxV)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (bits > 0) {
|
|
111
|
-
result.push((value << (5 - bits)) & maxV)
|
|
112
|
-
}
|
|
113
|
-
return result
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function fromWords (data) {
|
|
117
|
-
let value = 0
|
|
118
|
-
let bits = 0
|
|
119
|
-
const maxV = 255
|
|
120
|
-
const result = []
|
|
121
|
-
for (let i = 0; i < data.length; ++i) {
|
|
122
|
-
const element = data[i]
|
|
123
|
-
value = (value << 5) | element
|
|
124
|
-
bits += 5
|
|
125
|
-
while (bits >= 8) {
|
|
126
|
-
bits -= 8
|
|
127
|
-
result.push((value >> bits) & maxV)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return result
|
|
131
|
-
}
|
package/src/helpers/nip19.js
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { bytesToBase16, base16ToBytes } from '#helpers/base16.js'
|
|
2
|
-
import { bytesToBase62, base62ToBytes, BASE62_ALPHABET } from '#helpers/base62.js'
|
|
3
|
-
import { encode as bech32Encode, decode as bech32Decode, toWords, fromWords } from '#helpers/bech32.js'
|
|
4
|
-
import { isNostrAppDTagSafe } from '#helpers/app.js'
|
|
5
|
-
|
|
6
|
-
const MAX_SIZE = 5000
|
|
7
|
-
export const NAPP_ENTITY_REGEX = new RegExp(`^\\+{1,3}[${BASE62_ALPHABET}]{48,${MAX_SIZE}}$`)
|
|
8
|
-
const textEncoder = new TextEncoder()
|
|
9
|
-
const textDecoder = new TextDecoder()
|
|
10
|
-
|
|
11
|
-
const kindByChannel = {
|
|
12
|
-
main: 35128,
|
|
13
|
-
next: 35129,
|
|
14
|
-
draft: 35130
|
|
15
|
-
}
|
|
16
|
-
const channelByKind = Object.fromEntries(
|
|
17
|
-
Object.entries(kindByChannel).map(([k, v]) => [v, k])
|
|
18
|
-
)
|
|
19
|
-
const prefixByChannel = {
|
|
20
|
-
main: '+',
|
|
21
|
-
next: '++',
|
|
22
|
-
draft: '+++'
|
|
23
|
-
}
|
|
24
|
-
const channelByPrefix = Object.fromEntries(
|
|
25
|
-
Object.entries(prefixByChannel).map(([k, v]) => [v, k])
|
|
26
|
-
)
|
|
27
|
-
export function appEncode (ref) {
|
|
28
|
-
if (!isNostrAppDTagSafe(ref.dTag)) { throw new Error('Invalid deduplication tag') }
|
|
29
|
-
const channel = ref.channel ? (prefixByChannel[ref.channel] && ref.channel) : channelByKind[ref.kind]
|
|
30
|
-
if (!channel) throw new Error('Wrong channel')
|
|
31
|
-
const tlv = toTlv([
|
|
32
|
-
[textEncoder.encode(ref.dTag)], // type 0 (the array index)
|
|
33
|
-
(ref.relays || []).map(url => textEncoder.encode(url)), // type 1
|
|
34
|
-
[base16ToBytes(ref.pubkey)] // type 2
|
|
35
|
-
])
|
|
36
|
-
const base62 = bytesToBase62(tlv)
|
|
37
|
-
const prefix = prefixByChannel[channel]
|
|
38
|
-
return `${prefix}${base62}`
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function appDecode (entity) {
|
|
42
|
-
const prefix = entity.match(/^\+*/)[0]
|
|
43
|
-
const channel = channelByPrefix[prefix]
|
|
44
|
-
if (!channel) throw new Error('Invalid channel')
|
|
45
|
-
const base62 = entity.slice(prefix.length)
|
|
46
|
-
const tlv = tlvToObj(base62ToBytes(base62))
|
|
47
|
-
if (!tlv[0]?.[0]) throw new Error('Missing deduplication tag')
|
|
48
|
-
if (!tlv[2]?.[0]) throw new Error('Missing author pubkey')
|
|
49
|
-
if (tlv[2][0].length !== 32) throw new Error('Author pubkey should be 32 bytes')
|
|
50
|
-
const dTag = textDecoder.decode(tlv[0][0])
|
|
51
|
-
if (!isNostrAppDTagSafe(dTag)) { throw new Error('Invalid deduplication tag') }
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
dTag,
|
|
55
|
-
pubkey: bytesToBase16(tlv[2][0]),
|
|
56
|
-
kind: kindByChannel[channel],
|
|
57
|
-
channel,
|
|
58
|
-
relays: tlv[1] ? tlv[1].map(url => textDecoder.decode(url)) : []
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function nsecEncode (hex) {
|
|
63
|
-
const bytes = base16ToBytes(hex)
|
|
64
|
-
const words = toWords(bytes)
|
|
65
|
-
return bech32Encode('nsec', words)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function nsecDecode (nsec) {
|
|
69
|
-
const decoded = bech32Decode(nsec, MAX_SIZE)
|
|
70
|
-
if (!decoded) throw new Error('Invalid nsec')
|
|
71
|
-
const { hrp, data } = decoded
|
|
72
|
-
if (hrp !== 'nsec') throw new Error('Invalid nsec')
|
|
73
|
-
const bytes = fromWords(data)
|
|
74
|
-
if (bytes.length !== 32) throw new Error('Invalid nsec length')
|
|
75
|
-
return bytesToBase16(new Uint8Array(bytes))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function toTlv (tlvConfig) {
|
|
79
|
-
const arrays = []
|
|
80
|
-
tlvConfig
|
|
81
|
-
.map((v, i) => [i, v])
|
|
82
|
-
.reverse() // if the first type is 0, entity always starts with the '0' char
|
|
83
|
-
.forEach(([type, values]) => {
|
|
84
|
-
// just non-empty values will be included
|
|
85
|
-
values.forEach(v => {
|
|
86
|
-
if (v.length > 255) throw new Error('Value is too big')
|
|
87
|
-
const array = new Uint8Array(v.length + 2)
|
|
88
|
-
array.set([type], 0) // t
|
|
89
|
-
array.set([v.length], 1) // l
|
|
90
|
-
array.set(v, 2) // v
|
|
91
|
-
arrays.push(array)
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
return new Uint8Array(arrays.reduce((r, v) => [...r, ...v]))
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// { 0: [t0v0], 1: [t1v0, t1v2], 3: [t3v0] }
|
|
98
|
-
function tlvToObj (tlv) {
|
|
99
|
-
const ret = {}
|
|
100
|
-
let rest = tlv
|
|
101
|
-
let t, l, v
|
|
102
|
-
while (rest.length > 0) {
|
|
103
|
-
t = rest[0]
|
|
104
|
-
l = rest[1]
|
|
105
|
-
v = rest.slice(2, 2 + l)
|
|
106
|
-
rest = rest.slice(2 + l)
|
|
107
|
-
if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)
|
|
108
|
-
ret[t] ??= []
|
|
109
|
-
ret[t].push(v)
|
|
110
|
-
}
|
|
111
|
-
return ret
|
|
112
|
-
}
|
package/src/services/GEMINI.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# src/services folder
|
|
2
|
-
|
|
3
|
-
- Place services here. Services are multi-step functionality that make the code more
|
|
4
|
-
readable than if placing every step together on a single function.
|
|
5
|
-
|
|
6
|
-
## General Instructions:
|
|
7
|
-
|
|
8
|
-
- Use object-oriented programming paradigm.
|
|
9
|
-
- Each file default exports one class or singleton.
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
// https://github.com/ticlo/arrow-code/blob/master/src/base93.ts
|
|
2
|
-
// https://github.com/ticlo/arrow-code/blob/master/LICENSE - Apache 2.0
|
|
3
|
-
|
|
4
|
-
// JSON-safe (space included; " and \ excluded)
|
|
5
|
-
const BASE93_ALPHABET =
|
|
6
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()*+,-./:;<=>?@[]^_`{|}~ "
|
|
7
|
-
|
|
8
|
-
const DECODING_TABLE = (() => {
|
|
9
|
-
const out = new Int16Array(128)
|
|
10
|
-
out.fill(93) // sentinel = invalid
|
|
11
|
-
for (let i = 0; i < 93; i++) out[BASE93_ALPHABET.charCodeAt(i)] = i
|
|
12
|
-
return out
|
|
13
|
-
})()
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Decode Base93 string to Uint8Array
|
|
17
|
-
* @param {string} str - The Base93 encoded string to decode
|
|
18
|
-
* @param {number} [offset=0] - The starting position in the string
|
|
19
|
-
* @param {number} [length=-1] - The number of characters to decode, or -1 for all remaining
|
|
20
|
-
* @returns {Uint8Array} The decoded bytes
|
|
21
|
-
*/
|
|
22
|
-
export function decode (str, offset = 0, length = -1) {
|
|
23
|
-
let end = offset + length
|
|
24
|
-
if (length < 0 || end > str.length) end = str.length
|
|
25
|
-
|
|
26
|
-
// Over-allocate; we’ll trim at the end
|
|
27
|
-
const out = new Uint8Array(Math.ceil((end - offset) * 7 / 8))
|
|
28
|
-
|
|
29
|
-
let dbq = 0
|
|
30
|
-
let dn = 0
|
|
31
|
-
let dv = -1
|
|
32
|
-
let pos = 0
|
|
33
|
-
|
|
34
|
-
for (let i = offset; i < end; i++) {
|
|
35
|
-
const code = str.charCodeAt(i)
|
|
36
|
-
if (code > 126) continue // ignore non-ASCII
|
|
37
|
-
const v = DECODING_TABLE[code]
|
|
38
|
-
if (v === 93) continue // ignore invalids
|
|
39
|
-
if (dv === -1) {
|
|
40
|
-
dv = v
|
|
41
|
-
} else {
|
|
42
|
-
const t = dv + v * 93
|
|
43
|
-
dv = -1
|
|
44
|
-
dbq |= t << dn
|
|
45
|
-
dn += ((t & 0x1fff) > 456 ? 13 : 14)
|
|
46
|
-
while (dn > 7) {
|
|
47
|
-
out[pos++] = dbq & 0xff
|
|
48
|
-
dbq >>>= 8
|
|
49
|
-
dn -= 8
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (dv !== -1) {
|
|
55
|
-
out[pos++] = (dbq | (dv << dn)) & 0xff
|
|
56
|
-
}
|
|
57
|
-
return out.subarray(0, pos)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export default class Base93Decoder {
|
|
61
|
-
constructor (source, { mimeType = '', preferTextStreamDecoding = false } = {}) {
|
|
62
|
-
this.sourceIterator = source?.[Symbol.iterator]?.() || source?.[Symbol.asyncIterator]?.() || source()
|
|
63
|
-
this.asTextStream = preferTextStreamDecoding && mimeType.startsWith('text/')
|
|
64
|
-
if (this.asTextStream) this.textDecoder = new TextDecoder()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// decoder generator
|
|
68
|
-
* [Symbol.iterator] (base93String) {
|
|
69
|
-
if (this.asTextStream) {
|
|
70
|
-
while (base93String) {
|
|
71
|
-
// stream=true avoids cutting a multi-byte character
|
|
72
|
-
base93String = yield this.textDecoder.decode(decode(base93String), { stream: true })
|
|
73
|
-
}
|
|
74
|
-
} else {
|
|
75
|
-
while (base93String) {
|
|
76
|
-
base93String = yield decode(base93String)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Gets the decoded data.
|
|
82
|
-
getDecoded () { return iteratorToStream(this, this.sourceIterator) }
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function iteratorToStream (decoder, sourceIterator) {
|
|
86
|
-
return new ReadableStream({
|
|
87
|
-
decoderIterator: null,
|
|
88
|
-
async start (controller) {
|
|
89
|
-
const { value: chunk, done } = await sourceIterator.next()
|
|
90
|
-
if (done) return controller.close()
|
|
91
|
-
|
|
92
|
-
// Pass first chunk when instantiating the decoder generator
|
|
93
|
-
this.decoderIterator = decoder[Symbol.iterator](chunk)
|
|
94
|
-
const { value } = this.decoderIterator.next()
|
|
95
|
-
if (value) controller.enqueue(value)
|
|
96
|
-
},
|
|
97
|
-
async pull (controller) {
|
|
98
|
-
if (!this.decoderIterator) return
|
|
99
|
-
|
|
100
|
-
const { value: chunk, done: sourceDone } = await sourceIterator.next()
|
|
101
|
-
const { value, done } = this.decoderIterator.next(chunk)
|
|
102
|
-
|
|
103
|
-
if (value) controller.enqueue(value)
|
|
104
|
-
if (done || sourceDone) controller.close()
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// https://github.com/ticlo/arrow-code/blob/master/src/base93.ts
|
|
2
|
-
// https://github.com/ticlo/arrow-code/blob/master/LICENSE - Apache 2.0
|
|
3
|
-
|
|
4
|
-
// JSON-safe (space included; " and \ excluded)
|
|
5
|
-
const BASE93_ALPHABET =
|
|
6
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()*+,-./:;<=>?@[]^_`{|}~ "
|
|
7
|
-
const ENCODING_TABLE = (() => {
|
|
8
|
-
const out = new Uint16Array(93)
|
|
9
|
-
for (let i = 0; i < 93; i++) out[i] = BASE93_ALPHABET.charCodeAt(i)
|
|
10
|
-
return out
|
|
11
|
-
})()
|
|
12
|
-
|
|
13
|
-
function codesToString (codes, len) {
|
|
14
|
-
const CHUNK = 16384 // 16k chars per slice
|
|
15
|
-
let s = ''
|
|
16
|
-
for (let i = 0; i < len; i += CHUNK) {
|
|
17
|
-
const end = i + CHUNK < len ? i + CHUNK : len
|
|
18
|
-
s += String.fromCharCode.apply(
|
|
19
|
-
null,
|
|
20
|
-
Array.prototype.slice.call(codes, i, end)
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
return s
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default class Base93Encoder {
|
|
27
|
-
constructor (prefix = '') {
|
|
28
|
-
// bit reservoir
|
|
29
|
-
this._ebq = 0 // queued bits
|
|
30
|
-
this._en = 0 // number of bits in ebq
|
|
31
|
-
|
|
32
|
-
// output parts
|
|
33
|
-
this._parts = []
|
|
34
|
-
this._finished = false
|
|
35
|
-
|
|
36
|
-
if (prefix) this._parts.push(prefix)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Stream bytes; keeps reservoir across calls.
|
|
40
|
-
update (bytes) {
|
|
41
|
-
if (this._finished) throw new Error('Encoder already finalized.')
|
|
42
|
-
const src = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes)
|
|
43
|
-
|
|
44
|
-
// Over-allocate for this update; we’ll trim to 'pos'
|
|
45
|
-
const outCodes = new Uint16Array(Math.ceil(src.length * 8 / 6.5) + 4)
|
|
46
|
-
let pos = 0
|
|
47
|
-
|
|
48
|
-
let ebq = this._ebq
|
|
49
|
-
let en = this._en
|
|
50
|
-
let ev = 0
|
|
51
|
-
|
|
52
|
-
for (let i = 0; i < src.length; i++) {
|
|
53
|
-
ebq |= (src[i] & 0xff) << en
|
|
54
|
-
en += 8
|
|
55
|
-
if (en > 13) {
|
|
56
|
-
ev = ebq & 0x1fff
|
|
57
|
-
if (ev > 456) {
|
|
58
|
-
ebq >>>= 13
|
|
59
|
-
en -= 13
|
|
60
|
-
} else {
|
|
61
|
-
ev = ebq & 0x3fff
|
|
62
|
-
ebq >>>= 14
|
|
63
|
-
en -= 14
|
|
64
|
-
}
|
|
65
|
-
outCodes[pos++] = ENCODING_TABLE[ev % 93]
|
|
66
|
-
outCodes[pos++] = ENCODING_TABLE[(ev / 93) | 0]
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// persist reservoir
|
|
71
|
-
this._ebq = ebq
|
|
72
|
-
this._en = en
|
|
73
|
-
|
|
74
|
-
if (pos) this._parts.push(codesToString(outCodes, pos))
|
|
75
|
-
return this
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Finalize on first call: flush trailing partial block, join, lock.
|
|
79
|
-
getEncoded () {
|
|
80
|
-
if (!this._finished) {
|
|
81
|
-
if (this._en > 0) {
|
|
82
|
-
const outCodes = new Uint16Array(2)
|
|
83
|
-
let pos = 0
|
|
84
|
-
outCodes[pos++] = ENCODING_TABLE[this._ebq % 93]
|
|
85
|
-
if (this._en > 7 || this._ebq > 92) {
|
|
86
|
-
outCodes[pos++] = ENCODING_TABLE[(this._ebq / 93) | 0]
|
|
87
|
-
}
|
|
88
|
-
this._parts.push(codesToString(outCodes, pos))
|
|
89
|
-
}
|
|
90
|
-
this._finished = true
|
|
91
|
-
this._ebq = 0
|
|
92
|
-
this._en = 0
|
|
93
|
-
}
|
|
94
|
-
return this._parts.join('')
|
|
95
|
-
}
|
|
96
|
-
}
|