a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky
atproto bluesky typescript npm
101
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(time-ms): Deno FFI support

Mary 44f0850f 4e2b3ada

+102
+5
.changeset/tidy-teams-think.md
··· 1 + --- 2 + '@atcute/time-ms': minor 3 + --- 4 + 5 + Deno FFI support
+35
packages/misc/time-ms/lib/deno.d.ts
··· 1 + declare namespace Deno { 2 + export const build: { 3 + os: 'darwin' | 'linux' | 'windows' | 'freebsd' | 'netbsd' | 'aix' | 'solaris' | 'illumos'; 4 + }; 5 + 6 + export type PointerValue = null | NonNullable<unknown>; 7 + 8 + export const UnsafePointer: { 9 + of(value: Deno.BufferSource): PointerValue; 10 + }; 11 + 12 + type NativeNumberType = 'u8' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'f64'; 13 + type NativeBigIntType = 'u64' | 'i64' | 'usize' | 'isize'; 14 + type NativePointerType = 'pointer' | 'buffer'; 15 + type NativeVoidType = 'void'; 16 + type NativeType = NativeNumberType | NativeBigIntType | NativePointerType | NativeVoidType; 17 + 18 + interface ForeignFunction { 19 + parameters: readonly NativeType[]; 20 + result: NativeType; 21 + } 22 + 23 + type ForeignFunctionRecord = Record<string, ForeignFunction>; 24 + 25 + type StaticForeignSymbol<T extends ForeignFunction> = { 26 + (...args: unknown[]): T['result'] extends NativeVoidType ? void : unknown; 27 + }; 28 + 29 + type DynamicLibrary<S extends ForeignFunctionRecord> = { 30 + symbols: { [K in keyof S]: StaticForeignSymbol<S[K]> }; 31 + close(): void; 32 + }; 33 + 34 + export function dlopen<S extends ForeignFunctionRecord>(path: string, symbols: S): DynamicLibrary<S>; 35 + }
+61
packages/misc/time-ms/lib/index.deno.ts
··· 1 + const CLOCK_REALTIME = 0; 2 + 3 + // 100-nanosecond intervals between 1601-01-01 and 1970-01-01 4 + const EPOCH_OFFSET = 116444736000000000n; 5 + 6 + /** 7 + * whether the native module is available for the current runtime. 8 + */ 9 + export let hasNative = false; 10 + 11 + /** 12 + * returns the current time in microseconds since unix epoch. 13 + * @returns timestamp in microseconds 14 + */ 15 + export let now = (): number => { 16 + return Date.now() * 1_000; 17 + }; 18 + 19 + try { 20 + if (Deno.build.os === 'windows') { 21 + const lib = Deno.dlopen('kernel32.dll', { 22 + GetSystemTimePreciseAsFileTime: { parameters: ['pointer'], result: 'void' }, 23 + }); 24 + 25 + // FILETIME: { dwLowDateTime: u32, dwHighDateTime: u32 } = 8 bytes 26 + const buf = new Uint32Array(2); 27 + const ptr = Deno.UnsafePointer.of(buf); 28 + 29 + now = (): number => { 30 + lib.symbols.GetSystemTimePreciseAsFileTime(ptr); 31 + const low = BigInt(buf[0]); 32 + const high = BigInt(buf[1]); 33 + const filetime = (high << 32n) | low; 34 + // convert from 100-nanosecond intervals since 1601 to microseconds since 1970 35 + return Number((filetime - EPOCH_OFFSET) / 10n); 36 + }; 37 + 38 + hasNative = true; 39 + } else { 40 + const libPath = Deno.build.os === 'darwin' ? 'libSystem.B.dylib' : 'libc.so.6'; 41 + 42 + const lib = Deno.dlopen(libPath, { 43 + clock_gettime: { parameters: ['i32', 'pointer'], result: 'i32' }, 44 + }); 45 + 46 + // timespec: { tv_sec: i64, tv_nsec: i64 } = 16 bytes on 64-bit 47 + const buf = new BigInt64Array(2); 48 + const ptr = Deno.UnsafePointer.of(buf); 49 + 50 + now = (): number => { 51 + lib.symbols.clock_gettime(CLOCK_REALTIME, ptr); 52 + const sec = buf[0]; 53 + const nsec = buf[1]; 54 + return Number(sec * 1_000_000n + nsec / 1_000n); 55 + }; 56 + 57 + hasNative = true; 58 + } 59 + } catch { 60 + // ffi unavailable, keep fallback 61 + }
+1
packages/misc/time-ms/package.json
··· 22 22 ], 23 23 "exports": { 24 24 ".": { 25 + "deno": "./dist/index.deno.js", 25 26 "node": "./dist/index.node.js", 26 27 "default": "./dist/index.js" 27 28 }