UNPKG

minigame-std

Version:

Mini Game Standard Development Library.

1 lines 75.4 kB
{"version":3,"file":"types.d.ts","sources":["../src/std/assert/assertions.ts","../src/std/audio/audio_defines.ts","../src/std/audio/web_audio.ts","../src/std/base64/base64.ts","../src/std/base64/mod.ts","../src/std/clipboard/mod.ts","../src/std/defines.ts","../src/std/codec/mod.ts","../src/std/crypto/crypto_defines.ts","../src/std/crypto/hmac/mod.ts","../src/std/crypto/md/md5.ts","../src/std/crypto/md/mod.ts","../src/std/crypto/random/random_defines.ts","../src/std/crypto/random/mod.ts","../src/std/crypto/rsa/mod.ts","../src/std/crypto/sha/mod.ts","../src/std/event/mod.ts","../src/std/fetch/fetch_defines.ts","../src/std/fetch/mod.ts","../src/std/fs/fs_define.ts","../src/std/fs/fs_async.ts","../src/std/fs/fs_sync.ts","../src/std/image/mod.ts","../src/std/lbs/lbs_defines.ts","../src/std/platform/base.ts","../src/std/platform/device.ts","../src/std/platform/target.ts","../src/std/platform/mod.ts","../src/std/socket/socket_define.ts","../src/std/storage/mod.ts","../src/std/utils/promisify.ts","../src/std/utils/mod.ts"],"sourcesContent":["import invariant from 'tiny-invariant';\n\n/**\n * 断言传入的是一个字符串。\n * @param str - 需要断言的字符串。\n */\nexport function assertString(str: string): void {\n invariant(typeof str === 'string', () => `Param must be a string but received ${ str }`);\n}\n\n/**\n * 断言传入的 URL 是否为 `https` 协议。\n * @param url - 需要断言的 URL 字符串。\n */\nexport function assertSafeUrl(url: string): void {\n invariant(typeof url === 'string', () => `Url must be a string but received ${ url }`);\n invariant(url.startsWith('https://'), () => `Url must start with https:// but received ${ url }`);\n}\n\n/**\n * 断言传入的 WebSocket URL 是否为 `wss` 协议。\n * @param url - 需要断言的 WebSocket URL 字符串。\n */\nexport function assertSafeSocketUrl(url: string): void {\n invariant(typeof url === 'string', () => `SocketUrl must be a string but received ${ url }`);\n invariant(url.startsWith('wss://'), () => `SocketUrl must start with wss:// but received ${ url }`);\n}","/**\n * 播放音频的选项。\n */\nexport interface PlayOptions {\n /**\n * 是否循环播放。\n * @defaultValue `false`\n */\n loop?: boolean;\n\n /**\n * 播放完后是否自动调用 `source.disconnect`。\n * @defaultValue `true`\n */\n autoDisconnect?: boolean;\n}","import { Err, Ok, RESULT_VOID, type AsyncIOResult, type AsyncVoidIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport { readFile } from '../fs/mod.ts';\nimport { bufferSource2Ab } from '../utils/mod.ts';\nimport type { PlayOptions } from './audio_defines.ts';\n\n/**\n * Cache AudioContext.\n */\nlet audioContext: AudioContext | null;\n\n/**\n * 获取缓存的 AudioContext。\n * @returns 返回缓存的 AudioContext。\n */\nexport function getGlobalAudioContext(): AudioContext {\n audioContext ??= createWebAudioContext();\n return audioContext;\n}\n\n/**\n * 关闭缓存的 AudioContext。\n * @returns 返回一个 AsyncVoidIOResult。\n */\nexport async function closeGlobalAudioContext(): AsyncVoidIOResult {\n try {\n await audioContext?.close();\n audioContext = null;\n\n return RESULT_VOID;\n } catch (e) {\n return Err(e as DOMException);\n }\n}\n\n/**\n * 创建一个 AudioContext。\n * 如果要获取缓存的实例,请使用 `getGlobalAudioContext`。\n * @returns 返回一个 AudioContext实例。\n */\nexport function createWebAudioContext(): AudioContext {\n return isMinaEnv()\n // 两者 API 基本兼容\n ? (wx.createWebAudioContext() as unknown as AudioContext)\n : new AudioContext();\n}\n\n/**\n * 播放一个 AudioBuffer。\n * @param buffer - 解码后的 AudioBuffer。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n */\nexport function playWebAudioFromAudioBuffer(buffer: AudioBuffer, options?: PlayOptions): AudioBufferSourceNode {\n const {\n loop = false,\n autoDisconnect = true,\n } = options ?? {};\n\n const context = getGlobalAudioContext();\n const source = context.createBufferSource();\n\n source.buffer = buffer;\n source.loop = loop;\n source.connect(context.destination);\n\n if (autoDisconnect) {\n source.onended = () => {\n source.disconnect();\n };\n }\n\n source.start();\n\n return source;\n}\n\n/**\n * 使用 Buffer 进行解码播放。\n * @param buffer - 需要解码的 Buffer。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n */\nexport async function playWebAudioFromArrayBuffer(buffer: BufferSource, options?: PlayOptions): Promise<AudioBufferSourceNode> {\n const context = getGlobalAudioContext();\n const audioBuffer = await context.decodeAudioData(bufferSource2Ab(buffer));\n\n return playWebAudioFromAudioBuffer(audioBuffer, options);\n}\n\n/**\n * 读取文件并播放。\n * @param filePath - 文件路径。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n */\nexport async function playWebAudioFromFile(filePath: string, options?: PlayOptions): AsyncIOResult<AudioBufferSourceNode> {\n return (await readFile(filePath)).andThenAsync(async buffer => {\n return Ok(await playWebAudioFromArrayBuffer(buffer, options));\n })\n}","/**\n * @fileoverview Encode/Decode between Uint8Array and base64 encoded string.\n *\n * Forked from @std/encoding/base64 and https://github.com/cross-org/base64\n */\n\nimport { bufferSource2U8a } from '../utils/mod.ts';\n\n/**\n * A string containing standard base64 characters\n */\nconst chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Standard base64 characters\n */\nconst base64abc = chars.split('');\n\n/**\n * Lookup table for standard base64 characters\n */\nconst lookup = ((): Uint8Array => {\n const lookupTemp = new Uint8Array(256); // base64abc.length * 4\n\n for (let i = 0; i < base64abc.length; i++) {\n lookupTemp[base64abc[i].charCodeAt(0)] = i;\n }\n\n return lookupTemp;\n})();\n\n/**\n * Converts BufferSource into a base64 encoded string.\n *\n * @param data - The data to encode.\n * @returns The base64 encoded string.\n */\nexport function base64FromBuffer(data: BufferSource): string {\n let result = '';\n\n const u8a = bufferSource2U8a(data);\n\n const len = u8a.length;\n let i: number;\n\n for (i = 2; i < len; i += 3) {\n result += base64abc[(u8a[i - 2]) >> 2];\n result += base64abc[\n (((u8a[i - 2]) & 0x03) << 4)\n | ((u8a[i - 1]) >> 4)\n ];\n result += base64abc[\n (((u8a[i - 1]) & 0x0f) << 2)\n | ((u8a[i]) >> 6)\n ];\n result += base64abc[(u8a[i]) & 0x3f];\n }\n\n if (i === len + 1) {\n // 1 octet yet to write\n result += base64abc[(u8a[i - 2]) >> 2];\n result += base64abc[((u8a[i - 2]) & 0x03) << 4];\n result += '==';\n }\n\n if (i === len) {\n // 2 octets yet to write\n result += base64abc[(u8a[i - 2]) >> 2];\n result += base64abc[\n (((u8a[i - 2]) & 0x03) << 4)\n | ((u8a[i - 1]) >> 4)\n ];\n result += base64abc[((u8a[i - 1]) & 0x0f) << 2];\n result += '=';\n }\n\n return result;\n}\n\n/**\n * Converts a base64 encoded string to an Uint8Array\n *\n * @param data - Base64 encoded string\n * @returns The decoded data as an Uint8Array.\n */\nexport function base64ToBuffer(data: string): Uint8Array {\n const len = data.length;\n\n let bufferLength = len * 0.75;\n\n if (data[len - 1] === '=') {\n bufferLength--;\n if (data[len - 2] === '=') {\n bufferLength--;\n }\n }\n\n const u8a = new Uint8Array(bufferLength);\n\n let pos = 0;\n\n for (let i = 0; i < len; i += 4) {\n const encoded1 = lookup[data.charCodeAt(i)];\n const encoded2 = lookup[data.charCodeAt(i + 1)];\n const encoded3 = lookup[data.charCodeAt(i + 2)];\n const encoded4 = lookup[data.charCodeAt(i + 3)];\n\n u8a[pos++] = (encoded1 << 2) | (encoded2 >> 4);\n u8a[pos++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);\n u8a[pos++] = ((encoded3 & 3) << 6) | (encoded4 & 63);\n }\n\n return u8a;\n}","import { isMinaEnv } from '../../macros/env.ts';\nimport { decodeBase64 as minaDecodeBase64, encodeBase64 as minaEncodeBase64 } from './mina_base64.ts';\nimport { decodeBase64 as webDecodeBase64, encodeBase64 as webEncodeBase64 } from './web_base64.ts';\nexport { base64FromBuffer, base64ToBuffer } from './base64.ts';\n\n/**\n * 将字符串数据编码为 Base64 格式。\n * @param data - 需要编码的字符串数据。\n * @returns 编码后的 Base64 字符串。\n */\nexport function encodeBase64(data: string): string {\n return (isMinaEnv() ? minaEncodeBase64 : webEncodeBase64)(data);\n}\n\n/**\n * 将 Base64 格式的字符串数据解码。\n * @param data - 需要解码的 Base64 字符串。\n * @returns 解码后的字符串。\n */\nexport function decodeBase64(data: string): string {\n return (isMinaEnv() ? minaDecodeBase64 : webDecodeBase64)(data);\n}","import type { AsyncIOResult, AsyncVoidIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport { readText as minaReadText, writeText as minaWriteText } from './mina_clipboard.ts';\nimport { readText as webReadText, writeText as webWriteText } from './web_clipboard.ts';\n\n/**\n * 异步写入文本数据到剪贴板。\n * @param data - 需要写入的文本数据。\n * @returns 写入操作的结果。\n */\nexport function writeText(data: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaWriteText : webWriteText)(data);\n}\n\n/**\n * 异步读取剪贴板文本数据。\n * @returns 读取操作的结果。\n */\nexport function readText(): AsyncIOResult<string> {\n return (isMinaEnv() ? minaReadText : webReadText)();\n}","/**\n * The data source.\n */\nexport type DataSource = string | BufferSource;","import { isMinaEnv } from '../../macros/env.ts';\nimport type { DataSource } from '../defines.ts';\nimport { bufferSource2Ab, bufferSource2U8a } from '../utils/mod.ts';\nimport { textDecode as minaTextDecode, textEncode as minaTextEncode } from './mina_codec.ts';\nimport { textDecode as webTextDecode, textEncode as webTextEncode } from './web_codec.ts';\n\n/**\n * 将字符串数据编码为 `Uint8Array`\n * @param data - 需要编码的字符串数据。\n * @returns 编码后的 `Uint8Array`\n */\nexport function textEncode(data: string): Uint8Array {\n return isMinaEnv()\n ? bufferSource2U8a(minaTextEncode(data))\n : webTextEncode(data);\n}\n\n/**\n * 将二进制数据解码为字符串。\n * @param data - 需要解码的二进制数据。\n * @returns 解码后的字符串。\n */\nexport function textDecode(data: BufferSource): string {\n return isMinaEnv()\n ? minaTextDecode(bufferSource2Ab(data))\n : webTextDecode(data);\n}\n\n/**\n * 将 BufferSource 转换为十六进制字符串。\n * @param buffer - 需要转换的 BufferSource。\n * @returns 十六进制字符串。\n */\nexport function hexFromBuffer(buffer: BufferSource): string {\n return Array.from(bufferSource2U8a(buffer)).map(byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * 将字符串转换为 Uint8Array。\n * @param str - 需要转换的字符串。\n * @returns Uint8Array。\n */\nexport function byteStringToBuffer(str: string): Uint8Array {\n const { length } = str;\n const u8a = new Uint8Array(length);\n\n for (let i = 0; i < length; i++) {\n u8a[i] = str.charCodeAt(i);\n }\n\n return u8a;\n}\n\n/**\n * 将 Buffer 转换为 ByteString。\n * @param buffer - 需要转换的 Buffer。\n * @returns ByteString。\n */\nexport function byteStringFromBuffer(buffer: BufferSource): string {\n return String.fromCharCode(...bufferSource2U8a(buffer));\n}\n\n/**\n * 将 UTF-8 字符串转换为 ByteString。\n *\n * @param data - 需要转换的字符串或 BufferSource。\n * @returns 转换后的 ByteString。\n */\nexport function toByteString(data: DataSource): string {\n const buffer = typeof data === 'string'\n ? textEncode(data)\n : data;\n\n return byteStringFromBuffer(buffer);\n}","/**\n * The RSA public key.\n */\nexport interface RSAPublicKey {\n /**\n * Use the RSA-OAEP algorithm to encrypt the data.\n * @param data - The data to encrypt.\n * @returns Encrypted data.\n */\n encrypt(data: string): Promise<ArrayBuffer>;\n\n /**\n * `encrypt` then convert to base64 string.\n */\n encryptToString(data: string): Promise<string>;\n}\n\n/**\n * Supported hash algorithms.\n */\nexport type SHA = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';","import { isMinaEnv } from '../../../macros/env.ts';\nimport { toByteString } from '../../codec/mod.ts';\nimport type { DataSource } from '../../defines.ts';\nimport type { SHA } from '../crypto_defines.ts';\nimport { createHMAC as minaCreateHMAC } from './mina_hmac.ts';\nimport { createHMAC as webCreateHMAC } from './web_hmac.ts';\n\nfunction shaHMAC(sha: SHA, key: DataSource, data: DataSource): Promise<string> {\n if (isMinaEnv()) {\n const hmac = minaCreateHMAC(sha, toByteString(key));\n hmac.update(toByteString(data));\n return Promise.resolve(hmac.digest().toHex());\n }\n\n return webCreateHMAC(sha, key, data);\n}\n\n/**\n * 计算 SHA-1 HMAC。\n */\nexport function sha1HMAC(key: DataSource, data: DataSource): Promise<string> {\n return shaHMAC('SHA-1', key, data);\n}\n\n/**\n * 计算 SHA-256 HMAC。\n */\nexport function sha256HMAC(key: DataSource, data: DataSource): Promise<string> {\n return shaHMAC('SHA-256', key, data);\n}\n\n/**\n * 计算 SHA-384 HMAC。\n */\nexport function sha384HMAC(key: DataSource, data: DataSource): Promise<string> {\n return shaHMAC('SHA-384', key, data);\n}\n\n/**\n * 计算 SHA-512 HMAC。\n */\nexport function sha512HMAC(key: DataSource, data: DataSource): Promise<string> {\n return shaHMAC('SHA-512', key, data);\n}","// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.\n// This module is browser compatible.\n\n/**\n * Forked from https://github.com/denoland/std/blob/0.160.0/hash/md5.ts\n */\n\nimport { hexFromBuffer, textEncode } from '../../codec/mod.ts';\nimport type { DataSource } from '../../defines.ts';\nimport { bufferSource2U8a } from '../../utils/mod.ts';\n\nconst BLOCK_SIZE = 64 as const;\n\n/**\n * Md5 hash\n */\nexport class Md5 {\n private a = 0x67452301;\n private b = 0xefcdab89;\n private c = 0x98badcfe;\n private d = 0x10325476;\n private block = new Uint8Array(BLOCK_SIZE);\n private pos = 0;\n private n0 = 0;\n private n1 = 0;\n\n private addLength(len: number): void {\n let n0 = this.n0;\n n0 += len;\n if (n0 > 0xffffffff) this.n1 += 1;\n this.n0 = n0 >>> 0;\n }\n\n private hash(block: Uint8Array): void {\n let a = this.a;\n let b = this.b;\n let c = this.c;\n let d = this.d;\n\n const blk = (i: number): number =>\n block[i] |\n (block[i + 1] << 8) |\n (block[i + 2] << 16) |\n (block[i + 3] << 24);\n\n const rol32 = (x: number, n: number): number => (x << n) | (x >>> (32 - n));\n\n const x0 = blk(0);\n const x1 = blk(4);\n const x2 = blk(8);\n const x3 = blk(12);\n const x4 = blk(16);\n const x5 = blk(20);\n const x6 = blk(24);\n const x7 = blk(28);\n const x8 = blk(32);\n const x9 = blk(36);\n const xa = blk(40);\n const xb = blk(44);\n const xc = blk(48);\n const xd = blk(52);\n const xe = blk(56);\n const xf = blk(60);\n\n // round 1\n a = b + rol32((((c ^ d) & b) ^ d) + a + x0 + 0xd76aa478, 7);\n d = a + rol32((((b ^ c) & a) ^ c) + d + x1 + 0xe8c7b756, 12);\n c = d + rol32((((a ^ b) & d) ^ b) + c + x2 + 0x242070db, 17);\n b = c + rol32((((d ^ a) & c) ^ a) + b + x3 + 0xc1bdceee, 22);\n a = b + rol32((((c ^ d) & b) ^ d) + a + x4 + 0xf57c0faf, 7);\n d = a + rol32((((b ^ c) & a) ^ c) + d + x5 + 0x4787c62a, 12);\n c = d + rol32((((a ^ b) & d) ^ b) + c + x6 + 0xa8304613, 17);\n b = c + rol32((((d ^ a) & c) ^ a) + b + x7 + 0xfd469501, 22);\n a = b + rol32((((c ^ d) & b) ^ d) + a + x8 + 0x698098d8, 7);\n d = a + rol32((((b ^ c) & a) ^ c) + d + x9 + 0x8b44f7af, 12);\n c = d + rol32((((a ^ b) & d) ^ b) + c + xa + 0xffff5bb1, 17);\n b = c + rol32((((d ^ a) & c) ^ a) + b + xb + 0x895cd7be, 22);\n a = b + rol32((((c ^ d) & b) ^ d) + a + xc + 0x6b901122, 7);\n d = a + rol32((((b ^ c) & a) ^ c) + d + xd + 0xfd987193, 12);\n c = d + rol32((((a ^ b) & d) ^ b) + c + xe + 0xa679438e, 17);\n b = c + rol32((((d ^ a) & c) ^ a) + b + xf + 0x49b40821, 22);\n\n // round 2\n a = b + rol32((((b ^ c) & d) ^ c) + a + x1 + 0xf61e2562, 5);\n d = a + rol32((((a ^ b) & c) ^ b) + d + x6 + 0xc040b340, 9);\n c = d + rol32((((d ^ a) & b) ^ a) + c + xb + 0x265e5a51, 14);\n b = c + rol32((((c ^ d) & a) ^ d) + b + x0 + 0xe9b6c7aa, 20);\n a = b + rol32((((b ^ c) & d) ^ c) + a + x5 + 0xd62f105d, 5);\n d = a + rol32((((a ^ b) & c) ^ b) + d + xa + 0x02441453, 9);\n c = d + rol32((((d ^ a) & b) ^ a) + c + xf + 0xd8a1e681, 14);\n b = c + rol32((((c ^ d) & a) ^ d) + b + x4 + 0xe7d3fbc8, 20);\n a = b + rol32((((b ^ c) & d) ^ c) + a + x9 + 0x21e1cde6, 5);\n d = a + rol32((((a ^ b) & c) ^ b) + d + xe + 0xc33707d6, 9);\n c = d + rol32((((d ^ a) & b) ^ a) + c + x3 + 0xf4d50d87, 14);\n b = c + rol32((((c ^ d) & a) ^ d) + b + x8 + 0x455a14ed, 20);\n a = b + rol32((((b ^ c) & d) ^ c) + a + xd + 0xa9e3e905, 5);\n d = a + rol32((((a ^ b) & c) ^ b) + d + x2 + 0xfcefa3f8, 9);\n c = d + rol32((((d ^ a) & b) ^ a) + c + x7 + 0x676f02d9, 14);\n b = c + rol32((((c ^ d) & a) ^ d) + b + xc + 0x8d2a4c8a, 20);\n\n // round 3\n a = b + rol32((b ^ c ^ d) + a + x5 + 0xfffa3942, 4);\n d = a + rol32((a ^ b ^ c) + d + x8 + 0x8771f681, 11);\n c = d + rol32((d ^ a ^ b) + c + xb + 0x6d9d6122, 16);\n b = c + rol32((c ^ d ^ a) + b + xe + 0xfde5380c, 23);\n a = b + rol32((b ^ c ^ d) + a + x1 + 0xa4beea44, 4);\n d = a + rol32((a ^ b ^ c) + d + x4 + 0x4bdecfa9, 11);\n c = d + rol32((d ^ a ^ b) + c + x7 + 0xf6bb4b60, 16);\n b = c + rol32((c ^ d ^ a) + b + xa + 0xbebfbc70, 23);\n a = b + rol32((b ^ c ^ d) + a + xd + 0x289b7ec6, 4);\n d = a + rol32((a ^ b ^ c) + d + x0 + 0xeaa127fa, 11);\n c = d + rol32((d ^ a ^ b) + c + x3 + 0xd4ef3085, 16);\n b = c + rol32((c ^ d ^ a) + b + x6 + 0x04881d05, 23);\n a = b + rol32((b ^ c ^ d) + a + x9 + 0xd9d4d039, 4);\n d = a + rol32((a ^ b ^ c) + d + xc + 0xe6db99e5, 11);\n c = d + rol32((d ^ a ^ b) + c + xf + 0x1fa27cf8, 16);\n b = c + rol32((c ^ d ^ a) + b + x2 + 0xc4ac5665, 23);\n\n // round 4\n a = b + rol32((c ^ (b | ~d)) + a + x0 + 0xf4292244, 6);\n d = a + rol32((b ^ (a | ~c)) + d + x7 + 0x432aff97, 10);\n c = d + rol32((a ^ (d | ~b)) + c + xe + 0xab9423a7, 15);\n b = c + rol32((d ^ (c | ~a)) + b + x5 + 0xfc93a039, 21);\n a = b + rol32((c ^ (b | ~d)) + a + xc + 0x655b59c3, 6);\n d = a + rol32((b ^ (a | ~c)) + d + x3 + 0x8f0ccc92, 10);\n c = d + rol32((a ^ (d | ~b)) + c + xa + 0xffeff47d, 15);\n b = c + rol32((d ^ (c | ~a)) + b + x1 + 0x85845dd1, 21);\n a = b + rol32((c ^ (b | ~d)) + a + x8 + 0x6fa87e4f, 6);\n d = a + rol32((b ^ (a | ~c)) + d + xf + 0xfe2ce6e0, 10);\n c = d + rol32((a ^ (d | ~b)) + c + x6 + 0xa3014314, 15);\n b = c + rol32((d ^ (c | ~a)) + b + xd + 0x4e0811a1, 21);\n a = b + rol32((c ^ (b | ~d)) + a + x4 + 0xf7537e82, 6);\n d = a + rol32((b ^ (a | ~c)) + d + xb + 0xbd3af235, 10);\n c = d + rol32((a ^ (d | ~b)) + c + x2 + 0x2ad7d2bb, 15);\n b = c + rol32((d ^ (c | ~a)) + b + x9 + 0xeb86d391, 21);\n\n this.a = (this.a + a) >>> 0;\n this.b = (this.b + b) >>> 0;\n this.c = (this.c + c) >>> 0;\n this.d = (this.d + d) >>> 0;\n }\n\n /**\n * Update internal state.\n * @param data data to update, data cannot exceed 2^32 bytes.\n */\n update(data: DataSource): this {\n const msg = typeof data === 'string'\n ? textEncode(data)\n : bufferSource2U8a(data);\n\n let pos = this.pos;\n const free = BLOCK_SIZE - pos;\n\n if (msg.length < free) {\n this.block.set(msg, pos);\n pos += msg.length;\n } else {\n // hash first block\n this.block.set(msg.slice(0, free), pos);\n this.hash(this.block);\n\n // hash as many blocks as possible\n let i = free;\n while (i + BLOCK_SIZE <= msg.length) {\n this.hash(msg.slice(i, i + BLOCK_SIZE));\n i += BLOCK_SIZE;\n }\n\n // store leftover\n this.block.fill(0).set(msg.slice(i), 0);\n pos = msg.length - i;\n }\n\n this.pos = pos;\n this.addLength(msg.length);\n\n return this;\n }\n\n /**\n * Returns final hash.\n */\n digest(): ArrayBuffer {\n let padLen = BLOCK_SIZE - this.pos;\n if (padLen < 9) padLen += BLOCK_SIZE;\n\n const pad = new Uint8Array(padLen);\n\n pad[0] = 0x80;\n\n const n0 = this.n0 << 3;\n const n1 = (this.n1 << 3) | (this.n0 >>> 29);\n pad[pad.length - 8] = n0 & 0xff;\n pad[pad.length - 7] = (n0 >>> 8) & 0xff;\n pad[pad.length - 6] = (n0 >>> 16) & 0xff;\n pad[pad.length - 5] = (n0 >>> 24) & 0xff;\n pad[pad.length - 4] = n1 & 0xff;\n pad[pad.length - 3] = (n1 >>> 8) & 0xff;\n pad[pad.length - 2] = (n1 >>> 16) & 0xff;\n pad[pad.length - 1] = (n1 >>> 24) & 0xff;\n\n this.update(pad.buffer);\n\n const hash = new ArrayBuffer(16);\n const hashView = new DataView(hash);\n hashView.setUint32(0, this.a, true);\n hashView.setUint32(4, this.b, true);\n hashView.setUint32(8, this.c, true);\n hashView.setUint32(12, this.d, true);\n\n return hash;\n }\n\n /**\n * Returns hash as a hex string.\n */\n toString(): string {\n return hexFromBuffer(this.digest());\n }\n}","import type { DataSource } from '../../defines.ts';\nimport { Md5 } from './md5.ts';\n\nexport { Md5 } from './md5.ts';\n\n/**\n * 计算字符串或者 buffer 的 MD5 值,结果用16进制字符串表示。\n * @param data - 需要计算 MD5 值的数据。\n * @returns 计算得到的 MD5 十六进制字符串。\n */\nexport function md5(data: DataSource): string {\n return new Md5().update(data).toString();\n}","/**\n * UUID.\n */\nexport type UUID = `${ string }-${ string }-${ string }-${ string }-${ string }`;","import { Ok, type AsyncIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../../macros/env.ts';\nimport {\n getRandomValues as minaGetRandomValues,\n randomUUID as minaRandomUUID,\n} from './mina_random.ts';\nimport type { UUID } from './random_defines.ts';\nimport {\n getRandomValues as webGetRandomValues,\n randomUUID as webRandomUUID,\n} from './web_random.ts';\n\nexport * from './random_defines.ts';\n\n/**\n * 获取密码学安全随机数。\n * @param length - 要生成的字节数。\n * @returns 生成的随机数 Buffer。\n */\nexport function getRandomValues(length: number): AsyncIOResult<Uint8Array> {\n return isMinaEnv()\n ? minaGetRandomValues(length)\n : Promise.resolve(Ok(webGetRandomValues(length)))\n}\n\n/**\n * 生成 UUID。\n * @returns UUID 字符串。\n */\nexport function randomUUID(): AsyncIOResult<UUID> {\n return isMinaEnv()\n ? minaRandomUUID()\n : Promise.resolve(Ok(webRandomUUID()))\n}","import invariant from 'tiny-invariant';\nimport { isMinaEnv } from '../../../macros/env.ts';\nimport type { RSAPublicKey, SHA } from '../crypto_defines.ts';\nimport { importPublicKey as minaImportPublicKey } from './mina_rsa.ts';\nimport { importPublicKey as webImportPublicKey } from './web_rsa.ts';\n\n/**\n * Import a public key from a PEM encoded string for encryption.\n * @param pem - PEM encoded string.\n * @param hash - Hash algorithm.\n * @returns\n */\nexport function importPublicKey(pem: string, hash: SHA): Promise<RSAPublicKey> {\n invariant(\n hash === 'SHA-1'\n || hash === 'SHA-256'\n || hash === 'SHA-384'\n || hash === 'SHA-512',\n 'Unsupported hash algorithm.'\n );\n return isMinaEnv()\n ? Promise.resolve(minaImportPublicKey(pem, hash))\n : webImportPublicKey(pem, hash);\n}","import { isMinaEnv } from '../../../macros/env.ts';\nimport type { DataSource } from '../../defines.ts';\nimport {\n sha1 as minaSHA1,\n sha256 as minaSHA256,\n sha384 as minaSHA384,\n sha512 as minaSHA512,\n} from './mina_sha.ts';\nimport { sha as webSHA } from './web_sha.ts';\n\n/**\n * 计算 SHA-1。\n */\nexport function sha1(data: DataSource): Promise<string> {\n return isMinaEnv()\n ? Promise.resolve(minaSHA1(data))\n : webSHA(data, 'SHA-1');\n}\n\n/**\n * 计算 SHA-256。\n */\nexport function sha256(data: DataSource): Promise<string> {\n return isMinaEnv()\n ? Promise.resolve(minaSHA256(data))\n : webSHA(data, 'SHA-256');\n}\n\n/**\n * 计算 SHA-384。\n */\nexport function sha384(data: DataSource): Promise<string> {\n return isMinaEnv()\n ? Promise.resolve(minaSHA384(data))\n : webSHA(data, 'SHA-384');\n}\n\n/**\n * 计算 SHA-512。\n */\nexport function sha512(data: DataSource): Promise<string> {\n return isMinaEnv()\n ? Promise.resolve(minaSHA512(data))\n : webSHA(data, 'SHA-512');\n}","import { isMinaEnv } from '../../macros/env.ts';\nimport {\n addErrorListener as minaAddErrorListener,\n addResizeListener as minaAddResizeListener,\n addUnhandledrejectionListener as minaAddUnhandledrejectionListener,\n} from './mina_event.ts';\nimport {\n addErrorListener as webAddErrorListener,\n addResizeListener as webAddResizeListener,\n addUnhandledrejectionListener as webAddUnhandledrejectionListener,\n} from './web_event.ts';\n\n/**\n * 添加错误监听器,用于监听标准的错误事件。\n * @param listener - 错误事件的回调函数。\n * @returns 返回一个函数,调用该函数可以移除监听器。\n */\nexport function addErrorListener(listener: (ev: WechatMinigame.Error) => void): () => void {\n if (isMinaEnv()) {\n return minaAddErrorListener(listener);\n }\n\n const webListener = (ev: ErrorEvent) => {\n listener({\n message: ev.message,\n stack: ev.error.stack,\n });\n };\n\n return webAddErrorListener(webListener);\n}\n\n/**\n * 添加未处理的 Promise 拒绝事件监听器。\n * @param listener - 未处理的 Promise 拒绝事件的回调函数。\n * @returns 返回一个函数,调用该函数可以移除监听器。\n */\nexport function addUnhandledrejectionListener(listener: (ev: Pick<PromiseRejectionEvent, 'reason' | 'promise'>) => void): () => void {\n return isMinaEnv()\n ? minaAddUnhandledrejectionListener(listener as unknown as WechatMinigame.OnUnhandledRejectionCallback)\n : webAddUnhandledrejectionListener(listener);\n}\n\n/**\n * 添加窗口大小变化监听器。\n * @param listener - 窗口大小变化的回调函数。\n * @returns 返回一个函数,调用该函数可以移除监听器。\n */\nexport function addResizeListener(listener: WechatMinigame.OnWindowResizeCallback): () => void {\n return isMinaEnv()\n ? minaAddResizeListener(listener)\n : webAddResizeListener(ev => {\n listener({\n windowWidth: (ev.target as Window).innerWidth,\n windowHeight: (ev.target as Window).innerHeight,\n });\n });\n}","import type { FetchInit } from '@happy-ts/fetch-t';\nexport { ABORT_ERROR, FetchError, TIMEOUT_ERROR, type FetchTask } from '@happy-ts/fetch-t';\n\n/**\n * 微信小游戏网络请求初始化配置接口,继承自微信小游戏请求选项,除去'url'和'responseType'。\n */\nexport interface MinaFetchInit extends Omit<WechatMinigame.RequestOption, 'url' | 'dataType' | 'responseType' | 'success' | 'fail'> {\n responseType?: 'arraybuffer' | 'text' | 'json';\n onChunk?: FetchInit['onChunk'];\n}\n\n/**\n * 联合网络请求初始化配置类型,结合了 FetchInit 和 MinaFetchInit。\n */\nexport type UnionFetchInit = FetchInit & MinaFetchInit;","import { fetchT as webFetch, type FetchTask } from '@happy-ts/fetch-t';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport type { UnionFetchInit } from './fetch_defines.ts';\nimport { minaFetch } from './mina_fetch.ts';\n\nexport * from './fetch_defines.ts';\n\n/**\n * 发起一个可中断的文本类型响应的网络请求。\n * @param url - 请求的 URL 地址。\n * @param init - 请求的初始化配置,指定响应类型为文本且请求可中断。\n * @returns 返回一个文本类型的 FetchTask。\n */\nexport function fetchT(url: string, init: UnionFetchInit & {\n responseType: 'text';\n}): FetchTask<string>;\n\n/**\n * 发起一个可中断的 ArrayBuffer 类型响应的网络请求。\n * @param url - 请求的 URL 地址。\n * @param init - 请求的初始化配置,指定响应类型为 ArrayBuffer 且请求可中断。\n * @returns 返回一个 ArrayBuffer 类型的 FetchTask。\n */\nexport function fetchT(url: string, init: UnionFetchInit & {\n responseType: 'arraybuffer';\n}): FetchTask<ArrayBuffer>;\n\n/**\n * 发起一个可中断的 JSON 类型响应的网络请求。\n * @typeParam T - 预期的 JSON 响应数据类型。\n * @param url - 请求的 URL 地址。\n * @param init - 请求的初始化配置,指定响应类型为 JSON 且请求可中断。\n * @returns 返回一个 JSON 类型的 FetchTask。\n */\nexport function fetchT<T>(url: string, init: UnionFetchInit & {\n responseType: 'json';\n}): FetchTask<T>;\n\n/**\n * 发起一个可中断的网络请求,默认返回文本类型响应。\n * @typeParam T - 预期的响应数据类型。\n * @param url - 请求的 URL 地址。\n * @param init - 请求的初始化配置,指定请求可中断。\n * @returns FetchTask。\n */\nexport function fetchT(url: string, init?: UnionFetchInit): FetchTask<string | Response>;\n\n/**\n * 发起一个网络请求,根据初始化配置返回对应类型的 FetchTask。\n * @typeParam T - 预期的响应数据类型。\n * @param url - 请求的 URL 地址。\n * @param init - 请求的初始化配置。\n * @returns FetchTask。\n */\nexport function fetchT<T>(url: string, init?: UnionFetchInit): FetchTask<T> {\n const defaultInit = init ?? {};\n // default is text type\n defaultInit.responseType ??= 'text';\n\n return (isMinaEnv() ? minaFetch(url, defaultInit) : webFetch(url, {\n ...defaultInit,\n abortable: true,\n })) as FetchTask<T>;\n}","import type { FetchInit } from '@happy-ts/fetch-t';\nimport type { FsRequestInit, ReadFileContent as OPFSReadFileContent, WriteFileContent as OPFSWriteFileContent, UploadRequestInit, ZipOptions } from 'happy-opfs';\n\n/**\n * File content type for write, support `ArrayBuffer` `TypedArray` `string`.\n */\nexport type WriteFileContent = Exclude<OPFSWriteFileContent, Blob>;\n\n/**\n * File content type for read result, support `ArrayBuffer` `string`.\n */\nexport type ReadFileContent = Exclude<OPFSReadFileContent, Blob>;\n\n/**\n * Options for reading files with specified encoding.\n */\nexport interface ReadOptions {\n /**\n * Read file encoding type, support `binary(ArrayBuffer)` `utf8(string)` `blob(Blob)`\n *\n * @defaultValue `'binary'`\n */\n encoding?: FileEncoding;\n}\n\n/**\n * Supported file encodings for reading and writing files.\n */\nexport type FileEncoding = 'binary' | 'utf8';\n\n/**\n * Options for downloading files.\n */\nexport interface DownloadFileOptions extends Omit<WechatMinigame.DownloadFileOption, 'url' | 'filePath' | 'success' | 'fail'> {\n onProgress?: FetchInit['onProgress'];\n}\n\n/**\n * Options for uploading files.\n */\nexport interface UploadFileOptions extends Omit<WechatMinigame.UploadFileOption, 'url' | 'filePath' | 'name' | 'success' | 'fail'> {\n /**\n * Optional file name.\n */\n name?: string\n}\n\n/**\n * Options for union requests.\n */\nexport type UnionDownloadFileOptions = FsRequestInit & DownloadFileOptions;\n\n/**\n * Options for union requests.\n */\nexport type UnionUploadFileOptions = UploadRequestInit & UploadFileOptions;\n\n/**\n * Options for stat operations.\n */\nexport interface StatOptions {\n /**\n * Whether to recursively read the contents of directories.\n */\n recursive: boolean;\n}\n\n/**\n * Union options for `unzipFromUrl`.\n */\nexport type ZipFromUrlOptions = (DownloadFileOptions & ZipOptions) & FsRequestInit;","import type { FetchTask } from '@happy-ts/fetch-t';\nimport {\n appendFile as webAppendFile,\n copy as webCopy,\n downloadFile as webDownloadFile,\n emptyDir as webEmptyDir,\n exists as webExists,\n mkdir as webMkdir,\n move as webMove,\n readDir as webReadDir,\n readFile as webReadFile,\n readJsonFile as webReadJsonFile,\n readTextFile as webReadTextFile,\n remove as webRemove,\n stat as webStat,\n unzip as webUnzip,\n unzipFromUrl as webUnzipFromUrl,\n uploadFile as webUploadFile,\n writeFile as webWriteFile,\n zip as webZip,\n zipFromUrl as webZipFromUrl,\n type DownloadFileTempResponse,\n type WriteOptions,\n type ZipOptions,\n} from 'happy-opfs';\nimport { Ok, type AsyncIOResult, type AsyncVoidIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport type { StatOptions, UnionDownloadFileOptions, UnionUploadFileOptions, WriteFileContent, ZipFromUrlOptions } from './fs_define.ts';\nimport { convertFileSystemHandleToStats } from './fs_helpers.ts';\nimport {\n appendFile as minaAppendFile,\n copy as minaCopy,\n downloadFile as minaDownloadFile,\n emptyDir as minaEmptyDir,\n exists as minaExists,\n mkdir as minaMkdir,\n move as minaMove,\n readDir as minaReadDir,\n readFile as minaReadFile,\n readJsonFile as minaReadJsonFile,\n readTextFile as minaReadTextFile,\n remove as minaRemove,\n stat as minaStat,\n unzip as minaUnzip,\n unzipFromUrl as minaUnzipFromUrl,\n uploadFile as minaUploadFile,\n writeFile as minaWriteFile,\n zip as minaZip,\n zipFromUrl as minaZipFromUrl,\n} from './mina_fs_async.ts';\n\n/**\n * 递归创建文件夹,相当于`mkdir -p`。\n * @param dirPath - 将要创建的目录的路径。\n * @returns 创建成功返回 true 的异步操作结果。\n */\nexport function mkdir(dirPath: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaMkdir : webMkdir)(dirPath);\n}\n\n/**\n * 重命名文件或目录。\n * @param srcPath - 原始路径。\n * @param destPath - 新路径。\n * @returns 重命名成功返回 true 的异步操作结果。\n */\nexport function move(srcPath: string, destPath: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaMove : webMove)(srcPath, destPath);\n}\n\n/**\n * 异步读取指定目录下的所有文件和子目录。\n * @param dirPath - 需要读取的目录路径。\n * @returns 包含目录内容的字符串数组的异步操作结果。\n */\nexport async function readDir(dirPath: string): AsyncIOResult<string[]> {\n if (isMinaEnv()) {\n return minaReadDir(dirPath);\n }\n\n return (await webReadDir(dirPath)).andThenAsync(async entries => {\n const items: string[] = [];\n for await (const { path } of entries) {\n items.push(path);\n }\n return Ok(items);\n });\n}\n\n/**\n * 读取文件内容。\n * @param filePath - 文件的路径。\n * @returns 包含文件内容的 ArrayBuffer 的异步操作结果。\n */\nexport function readFile(filePath: string): AsyncIOResult<ArrayBuffer> {\n return (isMinaEnv() ? minaReadFile : webReadFile)(filePath);\n}\n\n/**\n * 删除文件或目录。\n * @param path - 要删除的文件或目录的路径。\n * @returns 删除成功返回 true 的异步操作结果。\n */\nexport function remove(path: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaRemove : webRemove)(path);\n}\n\nexport async function stat(path: string): AsyncIOResult<WechatMinigame.Stats>;\nexport async function stat(path: string, options: StatOptions & {\n recursive: true;\n}): AsyncIOResult<WechatMinigame.FileStats[]>;\nexport async function stat(path: string, options?: StatOptions): AsyncIOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]>\n/**\n * 获取文件或目录的状态信息。\n * @param path - 文件或目录的路径。\n * @param options - 可选选项。\n * @returns 包含状态信息的异步操作结果。\n */\nexport async function stat(path: string, options?: StatOptions): AsyncIOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]> {\n if (isMinaEnv()) {\n return await minaStat(path, options);\n }\n\n return (await webStat(path)).andThenAsync(async (handle): AsyncIOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]> => {\n const entryStats = await convertFileSystemHandleToStats(handle);\n\n if (entryStats.isFile() || !options?.recursive) {\n return Ok(entryStats);\n }\n\n // 递归读取目录\n return (await webReadDir(path)).andThenAsync(async entries => {\n const statsArr: WechatMinigame.FileStats[] = [{\n path,\n stats: entryStats,\n }];\n\n for await (const { path, handle } of entries) {\n statsArr.push({\n path,\n stats: await convertFileSystemHandleToStats(handle),\n })\n }\n\n return Ok(statsArr);\n });\n });\n}\n\n/**\n * 写入文件,不存在则创建,同时创建对应目录,contents只支持ArrayBuffer和string,并且需要确保string一定是utf8编码的。\n * @param filePath - 文件路径。\n * @param contents - 要写入的内容。\n * @param options - 可选选项。\n * @returns 写入成功返回 true 的异步操作结果。\n */\nexport function writeFile(filePath: string, contents: WriteFileContent, options?: WriteOptions): AsyncVoidIOResult {\n return (isMinaEnv() ? minaWriteFile : webWriteFile)(filePath, contents, options);\n}\n\n/**\n * 向文件追加内容。\n * @param filePath - 文件路径。\n * @param contents - 要追加的内容。\n * @returns 追加成功返回 true 的异步操作结果。\n */\nexport function appendFile(filePath: string, contents: WriteFileContent): AsyncVoidIOResult {\n return (isMinaEnv() ? minaAppendFile : webAppendFile)(filePath, contents);\n}\n\n/**\n * 复制文件或文件夹。\n *\n * @param srcPath - 源文件或文件夹路径。\n * @param destPath - 目标文件或文件夹路径。\n * @returns 操作的异步结果。\n */\nexport function copy(srcPath: string, destPath: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaCopy : webCopy)(srcPath, destPath);\n}\n\n/**\n * 检查指定路径的文件或目录是否存在。\n * @param path - 文件或目录的路径。\n * @returns 存在返回 true 的异步操作结果。\n */\nexport function exists(path: string): AsyncIOResult<boolean> {\n return (isMinaEnv() ? minaExists : webExists)(path);\n}\n\n/**\n * 清空指定目录下的所有文件和子目录。\n * @param dirPath - 目录路径。\n * @returns 清空成功返回 true 的异步操作结果。\n */\nexport function emptyDir(dirPath: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaEmptyDir : webEmptyDir)(dirPath);\n}\n\n/**\n * 读取文件并解析为 JSON。\n * @param filePath - 文件路径。\n * @returns 读取结果。\n */\nexport function readJsonFile<T>(filePath: string): AsyncIOResult<T> {\n return (isMinaEnv() ? minaReadJsonFile : webReadJsonFile)(filePath);\n}\n\n/**\n * 读取文本文件的内容。\n * @param filePath - 文件路径。\n * @returns 包含文件文本内容的异步操作结果。\n */\nexport function readTextFile(filePath: string): AsyncIOResult<string> {\n return (isMinaEnv() ? minaReadTextFile : webReadTextFile)(filePath);\n}\n\n/**\n * 下载文件并保存到临时文件。\n * @param fileUrl - 文件的网络 URL。\n * @param options - 可选参数。\n * @returns 下载操作的异步结果,成功时返回 true。\n */\nexport function downloadFile(fileUrl: string, options?: UnionDownloadFileOptions): FetchTask<WechatMinigame.DownloadFileSuccessCallbackResult | DownloadFileTempResponse>;\n/**\n * 下载文件。\n * @param fileUrl - 文件的网络 URL。\n * @param filePath - 可选的下载后文件存储的路径,没传则存到临时文件。\n * @param options - 可选的请求初始化参数。\n * @returns 下载成功返回原始结果。\n */\nexport function downloadFile(fileUrl: string, filePath: string, options?: UnionDownloadFileOptions): FetchTask<WechatMinigame.DownloadFileSuccessCallbackResult | Response>\nexport function downloadFile(fileUrl: string, filePath?: string | UnionDownloadFileOptions, options?: UnionDownloadFileOptions): FetchTask<WechatMinigame.DownloadFileSuccessCallbackResult | DownloadFileTempResponse | Response> {\n if (typeof filePath === 'string') {\n return isMinaEnv()\n ? minaDownloadFile(fileUrl, filePath, options)\n : webDownloadFile(fileUrl, filePath, options);\n } else {\n return isMinaEnv()\n ? minaDownloadFile(fileUrl, filePath)\n : webDownloadFile(fileUrl, filePath);\n }\n}\n\n/**\n * 上传本地文件。\n * @param filePath - 需要上传的文件路径。\n * @param fileUrl - 目标服务器的 URL。\n * @param options - 可选的请求初始化参数。\n * @returns 上传成功返回原始结果。\n */\nexport function uploadFile(filePath: string, fileUrl: string, options?: UnionUploadFileOptions): FetchTask<WechatMinigame.UploadFileSuccessCallbackResult | Response> {\n return (isMinaEnv() ? minaUploadFile : webUploadFile)(filePath, fileUrl, options);\n}\n\n/**\n * 解压 zip 文件。\n * @param zipFilePath - 要解压的 zip 文件路径。\n * @param targetPath - 要解压到的目标文件夹路径。\n * @returns 解压操作的异步结果。\n */\nexport function unzip(zipFilePath: string, targetPath: string): AsyncVoidIOResult {\n return (isMinaEnv() ? minaUnzip : webUnzip)(zipFilePath, targetPath);\n}\n\n/**\n * 从网络下载 zip 文件并解压。\n * @param zipFileUrl - Zip 文件的网络地址。\n * @param targetPath - 要解压到的目标文件夹路径。\n * @param options - 可选的下载参数。\n * @returns 下载并解压操作的异步结果。\n */\nexport async function unzipFromUrl(zipFileUrl: string, targetPath: string, options?: UnionDownloadFileOptions): AsyncVoidIOResult {\n return (isMinaEnv() ? minaUnzipFromUrl : webUnzipFromUrl)(zipFileUrl, targetPath, options);\n}\n\n/**\n * 压缩文件到内存。\n * @param sourcePath - 需要压缩的文件(夹)路径。\n * @param options - 可选的压缩参数。\n * @returns 压缩成功的异步结果。\n */\nexport function zip(sourcePath: string, options?: ZipOptions): AsyncIOResult<Uint8Array>;\n/**\n * 压缩文件。\n * @param sourcePath - 需要压缩的文件(夹)路径。\n * @param zipFilePath - 压缩后的 zip 文件路径。\n * @param options - 可选的压缩参数。\n * @returns 压缩成功的异步结果。\n */\nexport function zip(sourcePath: string, zipFilePath: string, options?: ZipOptions): AsyncVoidIOResult;\nexport function zip(sourcePath: string, zipFilePath?: string | ZipOptions, options?: ZipOptions): AsyncVoidIOResult | AsyncIOResult<Uint8Array> {\n if (typeof zipFilePath === 'string') {\n return isMinaEnv()\n ? minaZip(sourcePath, zipFilePath, options)\n : webZip(sourcePath, zipFilePath, options);\n } else {\n return isMinaEnv()\n ? minaZip(sourcePath, zipFilePath)\n : webZip(sourcePath, zipFilePath);\n }\n}\n\n/**\n * 下载文件并压缩到内存。\n * @param sourceUrl - 要下载的文件 URL。\n * @param options - 合并的下载和压缩选项。\n */\nexport function zipFromUrl(sourceUrl: string, options?: ZipFromUrlOptions): AsyncIOResult<Uint8Array>;\n/**\n * 下载文件并压缩为 zip 文件。\n * @param sourceUrl - 要下载的文件 URL。\n * @param zipFilePath - 要输出的 zip 文件路径。\n * @param options - 合并的下载和压缩选项。\n */\nexport function zipFromUrl(sourceUrl: string, zipFilePath: string, options?: ZipFromUrlOptions): AsyncVoidIOResult;\nexport function zipFromUrl(sourceUrl: string, zipFilePath?: string | ZipFromUrlOptions, options?: ZipFromUrlOptions): AsyncVoidIOResult | AsyncIOResult<Uint8Array> {\n if (typeof zipFilePath === 'string') {\n return isMinaEnv()\n ? minaZipFromUrl(sourceUrl, zipFilePath, options)\n : webZipFromUrl(sourceUrl, zipFilePath, options);\n } else {\n return isMinaEnv()\n ? minaZipFromUrl(sourceUrl, zipFilePath)\n : webZipFromUrl(sourceUrl, zipFilePath);\n }\n}","import {\n appendFileSync as webAppendFileSync,\n copySync as webCopySync,\n emptyDirSync as webEmptyDirSync,\n existsSync as webExistsSync,\n mkdirSync as webMkdirSync,\n moveSync as webMoveSync,\n readDirSync as webReadDirSync,\n readFileSync as webReadFileSync,\n readJsonFileSync as webReadJsonFileSync,\n readTextFileSync as webReadTextFileSync,\n removeSync as webRemoveSync,\n statSync as webStatSync,\n unzipSync as webUnzipSync,\n writeFileSync as webWriteFileSync,\n zipSync as webZipSync,\n type ZipOptions,\n} from 'happy-opfs';\nimport { Ok, type IOResult, type VoidIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport type { StatOptions, WriteFileContent } from './fs_define.ts';\nimport { convertFileSystemHandleLikeToStats } from './fs_helpers.ts';\nimport {\n appendFileSync as minaAppendFileSync,\n copySync as minaCopySync,\n emptyDirSync as minaEmptyDirSync,\n existsSync as minaExistsSync,\n mkdirSync as minaMkdirSync,\n moveSync as minaMoveSync,\n readDirSync as minaReadDirSync,\n readFileSync as minaReadFileSync,\n readJsonFileSync as minaReadJsonFileSync,\n readTextFileSync as minaReadTextFileSync,\n removeSync as minaRemoveSync,\n statSync as minaStatSync,\n unzipSync as minaUnzipSync,\n writeFileSync as minaWriteFileSync,\n zipSync as minaZipSync,\n} from './mina_fs_sync.ts';\n\n/**\n * `mkdir` 的同步版本。\n */\nexport function mkdirSync(dirPath: string): VoidIOResult {\n return (isMinaEnv() ? minaMkdirSync : webMkdirSync)(dirPath);\n}\n\n/**\n * `move` 的同步版本。\n */\nexport function moveSync(srcPath: string, destPath: string): VoidIOResult {\n return (isMinaEnv() ? minaMoveSync : webMoveSync)(srcPath, destPath);\n}\n\n/**\n * `readDir` 的同步版本。\n */\nexport function readDirSync(dirPath: string): IOResult<string[]> {\n return isMinaEnv()\n ? minaReadDirSync(dirPath)\n : webReadDirSync(dirPath).map(x => {\n return x.map(y => y.path);\n });\n}\n\n/**\n * `readFile` 的同步版本。\n */\nexport function readFileSync(filePath: string): IOResult<ArrayBuffer> {\n return (isMinaEnv() ? minaReadFileSync : webReadFileSync)(filePath);\n}\n\n/**\n * `remove` 的同步版本。\n */\nexport function removeSync(path: string): VoidIOResult {\n return (isMinaEnv() ? minaRemoveSync : webRemoveSync)(path);\n}\n\n/**\n * `stat` 的同步版本。\n */\nexport function statSync(path: string): IOResult<WechatMinigame.Stats>;\nexport function statSync(path: string, options: StatOptions & {\n recursive: true;\n}): IOResult<WechatMinigame.FileStats[]>;\nexport function statSync(path: string, options?: StatOptions): IOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]>\nexport function statSync(path: string, options?: StatOptions): IOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]> {\n if (isMinaEnv()) {\n return minaStatSync(path, options);\n }\n\n return webStatSync(path).andThen((handleLike): IOResult<WechatMinigame.Stats | WechatMinigame.FileStats[]> => {\n const entryStats = convertFileSystemHandleLikeToStats(handleLike);\n\n if (entryStats.isFile() || !options?.recursive) {\n return Ok(entryStats);\n }\n\n // 递归读取目录\n return webReadDirSync(path).andThen(entries => {\n const statsArr: WechatMinigame.FileStats[] = [{\n path,\n stats: entryStats,\n }];\n\n for (const { path, handle } of entries) {\n statsArr.push({\n path,\n stats: convertFileSystemHandleLikeToStats(handle),\n })\n }\n\n return Ok(statsArr);\n });\n });\n}\n\n/**\n * `writeFile` 的同步版本。\n */\nexport function writeFileSync(filePath: string, contents: WriteFileContent): VoidIOResult {\n return (isMinaEnv() ? minaWriteFileSync : webWriteFileSync)(filePath, contents);\n}\n\n/**\n * `copy` 的同步版本。\n */\nexport function copySync(srcPath: string, destPath: string): VoidIOResult {\n return (isMinaEnv() ? minaCopySync : webCopySync)(srcPath, destPath);\n}\n\n/**\n * `appendFile` 的同步版本。\n */\nexport function appendFileSync(filePath: string, contents: WriteFileContent): VoidIOResult {\n return (isMinaEnv() ? minaAppendFileSync : webAppendFileSync)(filePath, contents);\n}\n\n/**\n * `exists` 的同步版本。\n */\nexport function existsSync(path: string): IOResult<boolean> {\n return (isMinaEnv() ? minaExistsSync : webExistsSync)(path);\n}\n\n/**\n * `emptyDir` 的同步版本。\n */\nexport function emptyDirSync(dirPath: string): VoidIOResult {\n return (isMinaEnv() ? minaEmptyDirSync : webEmptyDirSync)(dirPath);\n}\n\n/**\n * `readJsonFile` 的同步版本。\n */\nexport function readJsonFileSync<T>(filePath: string): IOResult<T> {\n return (isMinaEnv() ? minaReadJsonFileSync : webReadJsonFileSync)(filePath);\n}\n\n/**\n * `readTextFile` 的同步版本。\n */\nexport function readTextFileSync(filePath: string): IOResult<string> {\n return (isMinaEnv() ? minaReadTextFileSync : webReadTextFileSync)(filePath);\n}\n\n/**\n * `unzip` 的同步版本。\n */\nexport function unzipSync(zipFilePath: string, targetPath: string): VoidIOResult {\n return (isMinaEnv() ? minaUnzipSync : webUnzipSync)(zipFilePath, targetPath);\n}\n\n/**\n * `zip` 的同步版本。\n */\nexport function zipSync(sourcePath: string, zipFilePath: string, options?: ZipOptions): VoidIOResult {\n return (isMinaEnv() ? minaZipSync : webZipSync)(sourcePath, zipFilePath, options);\n}","import { Ok, type AsyncIOResult } from 'happy-rusty';\nimport { isMinaEnv } from '../../macros/env.ts';\nimport {\n createImageFromFile as minaCreateImageFromFile,\n createImageFromUrl as minaCreateImageFromUrl,\n} from './mina_image.ts';\nimport {\n createImageFromFile as webCreateImageFromFile,\n createImageFromUrl as webCreateImageFromUrl,\n} from './web_image.ts';\n\n/**\n * 从URL创建图片。\n * @param url - 图片URL。\n * @returns Image对象。\n */\nexport function createImageFromUrl(url: string): HTMLImageElement | WechatMinigame.Image {\n return (isMinaEnv() ? minaCreateImageFromUrl : webCreateImageFromUrl)(url);\n}\n\n/**\n * 从文件创建图片。\n * @param filePath - 文件路径。\n * @returns 异步的Image对象。\n */\nexport function createImageFromFile(filePath: string): AsyncIOResult<HTMLImageElement | WechatMinigame.Image> {\n return isMinaEnv()\n ? Promise.resolve(Ok(minaCreateImageFromFile(filePath)))\n : webCreateImageFromFile(filePath);\n}","/**\n * geo 坐标。\n */\nexport interface GeoPosition {\n /**\n * 纬度。\n */\n latitude: number;\n\n /**\n * 经度。\n */\n longitude: number;\n}","/**\n * 平台类型,Web 或者小游戏。\n */\nexport type TargetType = 'minigame' | 'web';\n\n/**\n * 获取当前的平台类型。\n * @returns 返回当前的运行环境类型,可能是 'minigame' 或 'web'。\n */\nexport function getTargetType(): TargetType {\n return 'wx' in globalThis ? 'minigame' : 'web';\n}\n\n/**\n * 判断当前是否在 Web 环境中。\n * @returns 如果在 Web 现境中返回 true,否则返回 false。\n */\nexport function isWeb(): boolean {\n return getTargetType() === 'web';\n}\n\n/**\n * 判断当前是否在小游戏环境中。\n * @returns 如果在小游戏环境中返回 true,否则返回 false。\n */\nexport function isMiniGame(): boolean {\n return getTargetType() === 'minigame';\n}","import { Err, Ok, type AsyncIOResult } from 'happy-rusty';\nimport { miniGameFailureToError, promisifyWithResult } from '../utils/mod.ts';\nimport { isWeb } from './base.ts';\n\n// 以下变量一旦获取则不会变化\nlet deviceInfo: WechatMinigame.DeviceInfo | undefined;\nlet benchmarkLevel: number | undefined;\n\n/**\n * 获取设备信息。\n * @returns 返回小游戏的设备信息对象。\n */\nexport function getDeviceInfo(): WechatMinigame.DeviceInfo {\n // 兼容基础库低版本\n // TODO 暂时只用了platform属性,可安全强转类型\n deviceInfo ??= wx.getDeviceInfo ? wx.getDeviceI