feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
/**
* A value which is wrapped with a CBOR Tag.
* Several tags are registered with defined meanings like 0 for a date string.
* These meanings are **not interpreted** when decoded or encoded.
*
* This class is an immutable record.
* If the tag number or value needs to change, then construct a new tag
*/
export declare class CBORTag {
private tagId;
private tagValue;
/**
* Wrap a value with a tag number.
* When encoded, this tag will be attached to the value.
*
* @param tag Tag number
* @param value Wrapped value
*/
constructor(tag: number, value: CBORType);
/**
* Read the tag number
*/
get tag(): number;
/**
* Read the value
*/
get value(): CBORType;
}
/**
* Supported types which are encodable and decodable with tiny CBOR.
* Note that plain javascript objects are omitted.
*/
export type CBORType = number | bigint | string | Uint8Array | boolean | null | undefined | CBORType[] | CBORTag | Map<string | number, CBORType>;
/**
* Like {decodeCBOR}, but the length of the data is unknown and there is likely
* more -- possibly unrelated non-CBOR -- data afterwards.
*
* Examples:
*
* ```ts
* import {decodePartialCBOR} from './cbor.ts'
* decodePartialCBOR(new Uint8Array([1, 2, 245, 3, 4]), 2)
* // returns [true, 1]
* // It did not decode the leading [1, 2] or trailing [3, 4]
* ```
*
* @param data a data stream to read data from
* @param index where to start reading in the data stream
* @returns a tuple of the value followed by bytes read.
* @throws {Error}
* When the data stream ends early or the CBOR data is not well formed
*/
export declare function decodePartialCBOR(data: DataView | Uint8Array | ArrayBuffer, index: number): [CBORType, number];
/**
* Decode CBOR data from a binary stream
*
* The entire data stream from [0, length) will be consumed.
* If you require a partial decoding, see {decodePartialCBOR}.
*
* Examples:
*
* ```ts
* import {decodeCBOR, CBORTag, CBORType} from './cbor.ts'
* decodeCBOR(new Uint8Array([162, 99, 107, 101, 121, 101, 118, 97, 108, 117, 101, 1, 109, 97, 110, 111, 116, 104, 101, 114, 32, 118, 97, 108, 117, 101]));
* // returns new Map<string | number, CBORType>([
* // ["key", "value"],
* // [1, "another value"]
* // ]);
*
* const taggedItem = new Uint8Array([217, 4, 210, 101, 104, 101, 108, 108, 111]);
* decodeCBOR(new DataView(taggedItem.buffer))
* // returns new CBORTag(1234, "hello")
* ```
*
* @param data a data stream, multiple types are supported
* @returns
*/
export declare function decodeCBOR(data: DataView | Uint8Array | ArrayBuffer): CBORType;
/**
* Encode a supported structure to a CBOR byte string.
*
* Example:
*
* ```ts
* import {encodeCBOR, CBORType, CBORTag} from './cbor.ts'
* encodeCBOR(new Map<string | number, CBORType>([
* ["key", "value"],
* [1, "another value"]
* ]));
* // returns new Uint8Array([162, 99, 107, 101, 121, 101, 118, 97, 108, 117, 101, 1, 109, 97, 110, 111, 116, 104, 101, 114, 32 118, 97, 108, 117, 101])
*
* encodeCBOR(new CBORTag(1234, "hello"))
* // returns new UInt8Array([217, 4, 210, 101, 104, 101, 108, 108, 111])
* ```
*
* @param data Data to encode
* @returns A byte string as a Uint8Array
* @throws Error
* if unsupported data is found during encoding
*/
export declare function encodeCBOR(data: CBORType): Uint8Array;

View File

@@ -0,0 +1,447 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeCBOR = exports.decodeCBOR = exports.decodePartialCBOR = exports.CBORTag = void 0;
const cbor_internal_js_1 = require("./cbor_internal.js");
/**
* A value which is wrapped with a CBOR Tag.
* Several tags are registered with defined meanings like 0 for a date string.
* These meanings are **not interpreted** when decoded or encoded.
*
* This class is an immutable record.
* If the tag number or value needs to change, then construct a new tag
*/
class CBORTag {
/**
* Wrap a value with a tag number.
* When encoded, this tag will be attached to the value.
*
* @param tag Tag number
* @param value Wrapped value
*/
constructor(tag, value) {
Object.defineProperty(this, "tagId", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "tagValue", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.tagId = tag;
this.tagValue = value;
}
/**
* Read the tag number
*/
get tag() {
return this.tagId;
}
/**
* Read the value
*/
get value() {
return this.tagValue;
}
}
exports.CBORTag = CBORTag;
function decodeUnsignedInteger(data, argument, index) {
return (0, cbor_internal_js_1.decodeLength)(data, argument, index);
}
function decodeNegativeInteger(data, argument, index) {
const [value, length] = decodeUnsignedInteger(data, argument, index);
return [-value - 1, length];
}
function decodeByteString(data, argument, index) {
const [lengthValue, lengthConsumed] = (0, cbor_internal_js_1.decodeLength)(data, argument, index);
const dataStartIndex = index + lengthConsumed;
return [
new Uint8Array(data.buffer.slice(dataStartIndex, dataStartIndex + lengthValue)),
lengthConsumed + lengthValue,
];
}
const TEXT_DECODER = new TextDecoder();
function decodeString(data, argument, index) {
const [value, length] = decodeByteString(data, argument, index);
return [TEXT_DECODER.decode(value), length];
}
function decodeArray(data, argument, index) {
if (argument === 0) {
return [[], 1];
}
const [length, lengthConsumed] = (0, cbor_internal_js_1.decodeLength)(data, argument, index);
let consumedLength = lengthConsumed;
const value = [];
for (let i = 0; i < length; i++) {
const remainingDataLength = data.byteLength - index - consumedLength;
if (remainingDataLength <= 0) {
throw new Error("array is not supported or well formed");
}
const [decodedValue, consumed] = decodeNext(data, index + consumedLength);
value.push(decodedValue);
consumedLength += consumed;
}
return [value, consumedLength];
}
const MAP_ERROR = "Map is not supported or well formed";
function decodeMap(data, argument, index) {
if (argument === 0) {
return [new Map(), 1];
}
const [length, lengthConsumed] = (0, cbor_internal_js_1.decodeLength)(data, argument, index);
let consumedLength = lengthConsumed;
const result = new Map();
for (let i = 0; i < length; i++) {
let remainingDataLength = data.byteLength - index - consumedLength;
if (remainingDataLength <= 0) {
throw new Error(MAP_ERROR);
}
// Load key
const [key, keyConsumed] = decodeNext(data, index + consumedLength);
consumedLength += keyConsumed;
remainingDataLength -= keyConsumed;
// Check that there's enough to have a value
if (remainingDataLength <= 0) {
throw new Error(MAP_ERROR);
}
// Technically CBOR maps can have any type as the key, and so can JS Maps
// However, JS Maps can only reference such keys as references which would
// require key iteration and pattern matching.
// For simplicity, since such keys are not in use with WebAuthn, this
// capability is not implemented and the types are restricted to strings
// and numbers.
if (typeof key !== "string" && typeof key !== "number") {
throw new Error(MAP_ERROR);
}
// CBOR Maps are not well formed if there are duplicate keys
if (result.has(key)) {
throw new Error(MAP_ERROR);
}
// Load value
const [value, valueConsumed] = decodeNext(data, index + consumedLength);
consumedLength += valueConsumed;
result.set(key, value);
}
return [result, consumedLength];
}
function decodeFloat16(data, index) {
if (index + 3 > data.byteLength) {
throw new Error("CBOR stream ended before end of Float 16");
}
// Skip the first byte
const result = data.getUint16(index + 1, false);
// A minimal selection of supported values
if (result == 0x7c00) {
return [Infinity, 3];
}
else if (result == 0x7e00) {
return [NaN, 3];
}
else if (result == 0xfc00) {
return [-Infinity, 3];
}
throw new Error("Float16 data is unsupported");
}
function decodeFloat32(data, index) {
if (index + 5 > data.byteLength) {
throw new Error("CBOR stream ended before end of Float 32");
}
// Skip the first byte
const result = data.getFloat32(index + 1, false);
// First byte + 4 byte float
return [result, 5];
}
function decodeFloat64(data, index) {
if (index + 9 > data.byteLength) {
throw new Error("CBOR stream ended before end of Float 64");
}
// Skip the first byte
const result = data.getFloat64(index + 1, false);
// First byte + 8 byte float
return [result, 9];
}
function decodeTag(data, argument, index) {
const [tag, tagBytes] = (0, cbor_internal_js_1.decodeLength)(data, argument, index);
const [value, valueBytes] = decodeNext(data, index + tagBytes);
return [new CBORTag(tag, value), tagBytes + valueBytes];
}
function decodeNext(data, index) {
if (index >= data.byteLength) {
throw new Error("CBOR stream ended before tag value");
}
const byte = data.getUint8(index);
const majorType = byte >> 5;
const argument = byte & 0x1f;
switch (majorType) {
case cbor_internal_js_1.MAJOR_TYPE_UNSIGNED_INTEGER: {
return decodeUnsignedInteger(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_NEGATIVE_INTEGER: {
return decodeNegativeInteger(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_BYTE_STRING: {
return decodeByteString(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_TEXT_STRING: {
return decodeString(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_ARRAY: {
return decodeArray(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_MAP: {
return decodeMap(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_TAG: {
return decodeTag(data, argument, index);
}
case cbor_internal_js_1.MAJOR_TYPE_SIMPLE_OR_FLOAT: {
switch (argument) {
case 20:
return [false, 1];
case 21:
return [true, 1];
case 22:
return [null, 1];
case 23:
return [undefined, 1];
// 24: Simple value (value 32..255 in following byte)
case 25: // IEEE 754 Half-Precision Float (16 bits follow)
return decodeFloat16(data, index);
case 26: // IEEE 754 Single-Precision Float (32 bits follow)
return decodeFloat32(data, index);
case 27: // IEEE 754 Double-Precision Float (64 bits follow)
return decodeFloat64(data, index);
// 28-30: Reserved, not well-formed in the present document
// 31: "break" stop code for indefinite-length items
}
}
}
throw new Error(`Unsupported or not well formed at ${index}`);
}
function encodeSimple(data) {
if (data === true) {
return 0xf5;
}
else if (data === false) {
return 0xf4;
}
else if (data === null) {
return 0xf6;
}
// Else undefined
return 0xf7;
}
function encodeFloat(data) {
if (Math.fround(data) == data || !Number.isFinite(data) || Number.isNaN(data)) {
// Float32
const output = new Uint8Array(5);
output[0] = 0xfa;
const view = new DataView(output.buffer);
view.setFloat32(1, data, false);
return output;
}
else {
// Float64
const output = new Uint8Array(9);
output[0] = 0xfb;
const view = new DataView(output.buffer);
view.setFloat64(1, data, false);
return output;
}
}
function encodeNumber(data) {
if (typeof data == "number") {
if (Number.isSafeInteger(data)) {
// Encode integer
if (data < 0) {
return (0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_NEGATIVE_INTEGER, Math.abs(data));
}
else {
return (0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_UNSIGNED_INTEGER, data);
}
}
return [encodeFloat(data)];
}
else {
if (data < 0n) {
return (0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_NEGATIVE_INTEGER, data * -1n);
}
else {
return (0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_UNSIGNED_INTEGER, data);
}
}
}
const ENCODER = new TextEncoder();
function encodeString(data, output) {
output.push(...(0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_TEXT_STRING, data.length));
output.push(ENCODER.encode(data));
}
function encodeBytes(data, output) {
output.push(...(0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_BYTE_STRING, data.length));
output.push(data);
}
function encodeArray(data, output) {
output.push(...(0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_ARRAY, data.length));
for (const element of data) {
encodePartialCBOR(element, output);
}
}
function encodeMap(data, output) {
output.push(new Uint8Array((0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_MAP, data.size)));
for (const [key, value] of data.entries()) {
encodePartialCBOR(key, output);
encodePartialCBOR(value, output);
}
}
function encodeTag(tag, output) {
output.push(...(0, cbor_internal_js_1.encodeLength)(cbor_internal_js_1.MAJOR_TYPE_TAG, tag.tag));
encodePartialCBOR(tag.value, output);
}
function encodePartialCBOR(data, output) {
if (typeof data == "boolean" || data === null || data == undefined) {
output.push(encodeSimple(data));
return;
}
if (typeof data == "number" || typeof data == "bigint") {
output.push(...encodeNumber(data));
return;
}
if (typeof data == "string") {
encodeString(data, output);
return;
}
if (data instanceof Uint8Array) {
encodeBytes(data, output);
return;
}
if (Array.isArray(data)) {
encodeArray(data, output);
return;
}
if (data instanceof Map) {
encodeMap(data, output);
return;
}
if (data instanceof CBORTag) {
encodeTag(data, output);
return;
}
throw new Error("Not implemented");
}
/**
* Like {decodeCBOR}, but the length of the data is unknown and there is likely
* more -- possibly unrelated non-CBOR -- data afterwards.
*
* Examples:
*
* ```ts
* import {decodePartialCBOR} from './cbor.ts'
* decodePartialCBOR(new Uint8Array([1, 2, 245, 3, 4]), 2)
* // returns [true, 1]
* // It did not decode the leading [1, 2] or trailing [3, 4]
* ```
*
* @param data a data stream to read data from
* @param index where to start reading in the data stream
* @returns a tuple of the value followed by bytes read.
* @throws {Error}
* When the data stream ends early or the CBOR data is not well formed
*/
function decodePartialCBOR(data, index) {
if (data.byteLength === 0 || data.byteLength <= index || index < 0) {
throw new Error("No data");
}
if (data instanceof Uint8Array) {
return decodeNext(new DataView(data.buffer), index);
}
else if (data instanceof ArrayBuffer) {
return decodeNext(new DataView(data), index);
}
// otherwise, it is a data view
return decodeNext(data, index);
}
exports.decodePartialCBOR = decodePartialCBOR;
/**
* Decode CBOR data from a binary stream
*
* The entire data stream from [0, length) will be consumed.
* If you require a partial decoding, see {decodePartialCBOR}.
*
* Examples:
*
* ```ts
* import {decodeCBOR, CBORTag, CBORType} from './cbor.ts'
* decodeCBOR(new Uint8Array([162, 99, 107, 101, 121, 101, 118, 97, 108, 117, 101, 1, 109, 97, 110, 111, 116, 104, 101, 114, 32, 118, 97, 108, 117, 101]));
* // returns new Map<string | number, CBORType>([
* // ["key", "value"],
* // [1, "another value"]
* // ]);
*
* const taggedItem = new Uint8Array([217, 4, 210, 101, 104, 101, 108, 108, 111]);
* decodeCBOR(new DataView(taggedItem.buffer))
* // returns new CBORTag(1234, "hello")
* ```
*
* @param data a data stream, multiple types are supported
* @returns
*/
function decodeCBOR(data) {
const [value, length] = decodePartialCBOR(data, 0);
if (length !== data.byteLength) {
throw new Error(`Data was decoded, but the whole stream was not processed ${length} != ${data.byteLength}`);
}
return value;
}
exports.decodeCBOR = decodeCBOR;
/**
* Encode a supported structure to a CBOR byte string.
*
* Example:
*
* ```ts
* import {encodeCBOR, CBORType, CBORTag} from './cbor.ts'
* encodeCBOR(new Map<string | number, CBORType>([
* ["key", "value"],
* [1, "another value"]
* ]));
* // returns new Uint8Array([162, 99, 107, 101, 121, 101, 118, 97, 108, 117, 101, 1, 109, 97, 110, 111, 116, 104, 101, 114, 32 118, 97, 108, 117, 101])
*
* encodeCBOR(new CBORTag(1234, "hello"))
* // returns new UInt8Array([217, 4, 210, 101, 104, 101, 108, 108, 111])
* ```
*
* @param data Data to encode
* @returns A byte string as a Uint8Array
* @throws Error
* if unsupported data is found during encoding
*/
function encodeCBOR(data) {
const results = [];
encodePartialCBOR(data, results);
let length = 0;
for (const result of results) {
if (typeof result == "number") {
length += 1;
}
else {
length += result.length;
}
}
const output = new Uint8Array(length);
let index = 0;
for (const result of results) {
if (typeof result == "number") {
output[index] = result;
index += 1;
}
else {
output.set(result, index);
index += result.length;
}
}
return output;
}
exports.encodeCBOR = encodeCBOR;

View File

@@ -0,0 +1,11 @@
export declare function decodeLength(data: DataView, argument: number, index: number): [number, number];
export type MajorType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export declare const MAJOR_TYPE_UNSIGNED_INTEGER: MajorType;
export declare const MAJOR_TYPE_NEGATIVE_INTEGER: MajorType;
export declare const MAJOR_TYPE_BYTE_STRING: MajorType;
export declare const MAJOR_TYPE_TEXT_STRING: MajorType;
export declare const MAJOR_TYPE_ARRAY: MajorType;
export declare const MAJOR_TYPE_MAP: MajorType;
export declare const MAJOR_TYPE_TAG: MajorType;
export declare const MAJOR_TYPE_SIMPLE_OR_FLOAT: MajorType;
export declare function encodeLength(major: MajorType, argument: number | bigint): number[];

View File

@@ -0,0 +1,116 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeLength = exports.MAJOR_TYPE_SIMPLE_OR_FLOAT = exports.MAJOR_TYPE_TAG = exports.MAJOR_TYPE_MAP = exports.MAJOR_TYPE_ARRAY = exports.MAJOR_TYPE_TEXT_STRING = exports.MAJOR_TYPE_BYTE_STRING = exports.MAJOR_TYPE_NEGATIVE_INTEGER = exports.MAJOR_TYPE_UNSIGNED_INTEGER = exports.decodeLength = void 0;
function decodeLength(data, argument, index) {
if (argument < 24) {
return [argument, 1];
}
const remainingDataLength = data.byteLength - index - 1;
const view = new DataView(data.buffer, index + 1);
let output;
let bytes = 0;
switch (argument) {
case 24: {
if (remainingDataLength > 0) {
output = view.getUint8(0);
bytes = 2;
}
break;
}
case 25: {
if (remainingDataLength > 1) {
output = view.getUint16(0, false);
bytes = 3;
}
break;
}
case 26: {
if (remainingDataLength > 3) {
output = view.getUint32(0, false);
bytes = 5;
}
break;
}
case 27: {
if (remainingDataLength > 7) {
const bigOutput = view.getBigUint64(0, false);
// Bound it to [24, MAX_SAFE_INTEGER], where it is safe
// to encode as a javascript number
if (bigOutput >= 24n && bigOutput <= Number.MAX_SAFE_INTEGER) {
return [Number(bigOutput), 9];
}
}
break;
}
}
if (output && output >= 24) {
return [output, bytes];
}
throw new Error("Length not supported or not well formed");
}
exports.decodeLength = decodeLength;
exports.MAJOR_TYPE_UNSIGNED_INTEGER = 0;
exports.MAJOR_TYPE_NEGATIVE_INTEGER = 1;
exports.MAJOR_TYPE_BYTE_STRING = 2;
exports.MAJOR_TYPE_TEXT_STRING = 3;
exports.MAJOR_TYPE_ARRAY = 4;
exports.MAJOR_TYPE_MAP = 5;
exports.MAJOR_TYPE_TAG = 6;
exports.MAJOR_TYPE_SIMPLE_OR_FLOAT = 7;
function encodeLength(major, argument) {
const majorEncoded = major << 5;
if (argument < 0) {
throw new Error("CBOR Data Item argument must not be negative");
}
// Convert to bigint first.
// Encode integers around and above 32 bits in big endian / network byte order
// is unreliable in javascript.
// https://tc39.es/ecma262/#sec-bitwise-shift-operators
// Bit shifting operations result in 32 bit signed numbers
let bigintArgument;
if (typeof argument == "number") {
if (!Number.isInteger(argument)) {
throw new Error("CBOR Data Item argument must be an integer");
}
bigintArgument = BigInt(argument);
}
else {
bigintArgument = argument;
}
// Negative 0 is not a thing
if (major == exports.MAJOR_TYPE_NEGATIVE_INTEGER) {
if (bigintArgument == 0n) {
throw new Error("CBOR Data Item argument cannot be zero when negative");
}
bigintArgument = bigintArgument - 1n;
}
if (bigintArgument > 18446744073709551615n) {
throw new Error("CBOR number out of range");
}
// Encode into 64 bits and extract the tail
const buffer = new Uint8Array(8);
const view = new DataView(buffer.buffer);
view.setBigUint64(0, bigintArgument, false);
if (bigintArgument <= 23) {
return [majorEncoded | buffer[7]];
}
else if (bigintArgument <= 255) {
return [majorEncoded | 24, buffer[7]];
}
else if (bigintArgument <= 65535) {
return [majorEncoded | 25, ...buffer.slice(6)];
}
else if (bigintArgument <= 4294967295) {
return [
majorEncoded | 26,
...buffer.slice(4),
];
}
else {
return [
majorEncoded | 27,
...buffer,
];
}
}
exports.encodeLength = encodeLength;

View File

@@ -0,0 +1,2 @@
export { CBORTag, decodeCBOR, decodePartialCBOR, encodeCBOR, } from "./cbor/cbor.js";
export type { CBORType } from "./cbor/cbor.js";

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeCBOR = exports.decodePartialCBOR = exports.decodeCBOR = exports.CBORTag = void 0;
var cbor_js_1 = require("./cbor/cbor.js");
Object.defineProperty(exports, "CBORTag", { enumerable: true, get: function () { return cbor_js_1.CBORTag; } });
Object.defineProperty(exports, "decodeCBOR", { enumerable: true, get: function () { return cbor_js_1.decodeCBOR; } });
Object.defineProperty(exports, "decodePartialCBOR", { enumerable: true, get: function () { return cbor_js_1.decodePartialCBOR; } });
Object.defineProperty(exports, "encodeCBOR", { enumerable: true, get: function () { return cbor_js_1.encodeCBOR; } });

View File

@@ -0,0 +1,3 @@
{
"type": "commonjs"
}