Files
wehub-resource-sync d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

256 lines
6.2 KiB
TypeScript

/**
* Minimal Thrift binary protocol encoder/decoder for Evernote API.
* Supports only the types needed for NoteStore operations.
*/
const THRIFT_VERSION_1 = 0x80010000
const MESSAGE_CALL = 1
const MESSAGE_EXCEPTION = 3
const TYPE_STOP = 0
const TYPE_BOOL = 2
const TYPE_I32 = 8
const TYPE_I64 = 10
const TYPE_STRING = 11
const TYPE_STRUCT = 12
const TYPE_LIST = 15
export class ThriftWriter {
private buffer: number[] = []
writeMessageBegin(name: string, seqId: number): void {
this.writeI32(THRIFT_VERSION_1 | MESSAGE_CALL)
this.writeString(name)
this.writeI32(seqId)
}
writeFieldBegin(type: number, id: number): void {
this.buffer.push(type)
this.writeI16(id)
}
writeFieldStop(): void {
this.buffer.push(TYPE_STOP)
}
writeString(value: string): void {
const encoded = new TextEncoder().encode(value)
this.writeI32(encoded.length)
for (const byte of encoded) {
this.buffer.push(byte)
}
}
writeBool(value: boolean): void {
this.buffer.push(value ? 1 : 0)
}
writeI16(value: number): void {
this.buffer.push((value >> 8) & 0xff)
this.buffer.push(value & 0xff)
}
writeI32(value: number): void {
this.buffer.push((value >> 24) & 0xff)
this.buffer.push((value >> 16) & 0xff)
this.buffer.push((value >> 8) & 0xff)
this.buffer.push(value & 0xff)
}
writeI64(value: bigint): void {
const buf = new ArrayBuffer(8)
const view = new DataView(buf)
view.setBigInt64(0, value, false)
for (let i = 0; i < 8; i++) {
this.buffer.push(view.getUint8(i))
}
}
writeStringField(id: number, value: string): void {
this.writeFieldBegin(TYPE_STRING, id)
this.writeString(value)
}
writeBoolField(id: number, value: boolean): void {
this.writeFieldBegin(TYPE_BOOL, id)
this.writeBool(value)
}
writeI32Field(id: number, value: number): void {
this.writeFieldBegin(TYPE_I32, id)
this.writeI32(value)
}
writeStringListField(id: number, values: string[]): void {
this.writeFieldBegin(TYPE_LIST, id)
this.buffer.push(TYPE_STRING)
this.writeI32(values.length)
for (const v of values) {
this.writeString(v)
}
}
toBuffer(): Buffer {
return Buffer.from(this.buffer)
}
}
export class ThriftReader {
private view: DataView
private pos = 0
constructor(buffer: ArrayBuffer) {
this.view = new DataView(buffer)
}
readMessageBegin(): { name: string; type: number; seqId: number } {
const versionAndType = this.readI32()
const version = versionAndType & 0xffff0000
if (version !== (THRIFT_VERSION_1 | 0)) {
throw new Error(`Unsupported Thrift version: 0x${version.toString(16)}`)
}
const type = versionAndType & 0x000000ff
const name = this.readString()
const seqId = this.readI32()
return { name, type, seqId }
}
readFieldBegin(): { type: number; id: number } {
const type = this.view.getUint8(this.pos++)
if (type === TYPE_STOP) {
return { type: TYPE_STOP, id: 0 }
}
const id = this.view.getInt16(this.pos, false)
this.pos += 2
return { type, id }
}
readString(): string {
const length = this.readI32()
const bytes = new Uint8Array(this.view.buffer, this.pos, length)
this.pos += length
return new TextDecoder().decode(bytes)
}
readBool(): boolean {
return this.view.getUint8(this.pos++) !== 0
}
readI32(): number {
const value = this.view.getInt32(this.pos, false)
this.pos += 4
return value
}
readI64(): bigint {
const value = this.view.getBigInt64(this.pos, false)
this.pos += 8
return value
}
readBinary(): Uint8Array {
const length = this.readI32()
const bytes = new Uint8Array(this.view.buffer, this.pos, length)
this.pos += length
return bytes
}
readListBegin(): { elementType: number; size: number } {
const elementType = this.view.getUint8(this.pos++)
const size = this.readI32()
return { elementType, size }
}
/** Skip a value of the given Thrift type */
skip(type: number): void {
switch (type) {
case TYPE_BOOL:
this.pos += 1
break
case 6: // I16
this.pos += 2
break
case 3: // BYTE
this.pos += 1
break
case TYPE_I32:
this.pos += 4
break
case TYPE_I64:
case 4: // DOUBLE
this.pos += 8
break
case TYPE_STRING: {
const len = this.readI32()
this.pos += len
break
}
case TYPE_STRUCT:
this.skipStruct()
break
case TYPE_LIST:
case 14: {
// SET
const { elementType, size } = this.readListBegin()
for (let i = 0; i < size; i++) {
this.skip(elementType)
}
break
}
case 13: {
// MAP
const keyType = this.view.getUint8(this.pos++)
const valueType = this.view.getUint8(this.pos++)
const count = this.readI32()
for (let i = 0; i < count; i++) {
this.skip(keyType)
this.skip(valueType)
}
break
}
default:
throw new Error(`Cannot skip unknown Thrift type: ${type}`)
}
}
private skipStruct(): void {
for (;;) {
const { type } = this.readFieldBegin()
if (type === TYPE_STOP) break
this.skip(type)
}
}
/** Read struct fields, calling the handler for each field */
readStruct<T>(handler: (reader: ThriftReader, fieldId: number, fieldType: number) => void): void {
for (;;) {
const { type, id } = this.readFieldBegin()
if (type === TYPE_STOP) break
handler(this, id, type)
}
}
/** Check if this is an exception response */
isException(messageType: number): boolean {
return messageType === MESSAGE_EXCEPTION
}
/** Read a Thrift application exception */
readException(): { message: string; type: number } {
let message = ''
let type = 0
this.readStruct((reader, fieldId, fieldType) => {
if (fieldId === 1 && fieldType === TYPE_STRING) {
message = reader.readString()
} else if (fieldId === 2 && fieldType === TYPE_I32) {
type = reader.readI32()
} else {
reader.skip(fieldType)
}
})
return { message, type }
}
}
export { TYPE_BOOL, TYPE_I32, TYPE_I64, TYPE_LIST, TYPE_STRING, TYPE_STRUCT }