+68
src/pds.js
+68
src/pds.js
···
1
+
// === CBOR ENCODING ===
2
+
// Minimal deterministic CBOR (RFC 8949) - sorted keys, minimal integers
3
+
4
+
function cborEncode(value) {
5
+
const parts = []
6
+
7
+
function encode(val) {
8
+
if (val === null) {
9
+
parts.push(0xf6) // null
10
+
} else if (val === true) {
11
+
parts.push(0xf5) // true
12
+
} else if (val === false) {
13
+
parts.push(0xf4) // false
14
+
} else if (typeof val === 'number') {
15
+
encodeInteger(val)
16
+
} else if (typeof val === 'string') {
17
+
const bytes = new TextEncoder().encode(val)
18
+
encodeHead(3, bytes.length) // major type 3 = text string
19
+
parts.push(...bytes)
20
+
} else if (val instanceof Uint8Array) {
21
+
encodeHead(2, val.length) // major type 2 = byte string
22
+
parts.push(...val)
23
+
} else if (Array.isArray(val)) {
24
+
encodeHead(4, val.length) // major type 4 = array
25
+
for (const item of val) encode(item)
26
+
} else if (typeof val === 'object') {
27
+
// Sort keys for deterministic encoding
28
+
const keys = Object.keys(val).sort()
29
+
encodeHead(5, keys.length) // major type 5 = map
30
+
for (const key of keys) {
31
+
encode(key)
32
+
encode(val[key])
33
+
}
34
+
}
35
+
}
36
+
37
+
function encodeHead(majorType, length) {
38
+
const mt = majorType << 5
39
+
if (length < 24) {
40
+
parts.push(mt | length)
41
+
} else if (length < 256) {
42
+
parts.push(mt | 24, length)
43
+
} else if (length < 65536) {
44
+
parts.push(mt | 25, length >> 8, length & 0xff)
45
+
} else if (length < 4294967296) {
46
+
parts.push(mt | 26, (length >> 24) & 0xff, (length >> 16) & 0xff, (length >> 8) & 0xff, length & 0xff)
47
+
}
48
+
}
49
+
50
+
function encodeInteger(n) {
51
+
if (n >= 0) {
52
+
encodeHead(0, n) // major type 0 = unsigned int
53
+
} else {
54
+
encodeHead(1, -n - 1) // major type 1 = negative int
55
+
}
56
+
}
57
+
58
+
encode(value)
59
+
return new Uint8Array(parts)
60
+
}
61
+
1
62
export class PersonalDataServer {
2
63
constructor(state, env) {
3
64
this.state = state
···
5
66
}
6
67
7
68
async fetch(request) {
69
+
const url = new URL(request.url)
70
+
if (url.pathname === '/test/cbor') {
71
+
const encoded = cborEncode({ hello: 'world', num: 42 })
72
+
return new Response(encoded, {
73
+
headers: { 'content-type': 'application/cbor' }
74
+
})
75
+
}
8
76
return new Response('pds running', { status: 200 })
9
77
}
10
78
}