Giter Site home page Giter Site logo

jetpack-io / typeid-js Goto Github PK

View Code? Open in Web Editor NEW
210.0 7.0 5.0 99 KB

TypeScript implementation of TypeIDs: type-safe, K-sortable, and globally unique identifiers inspired by Stripe IDs

License: Apache License 2.0

TypeScript 100.00%
guid js ts typeid typescript uuid uuidv7

typeid-js's Introduction

Official TypeID-JS Package

JavaScript implementation of TypeIDs using TypeScript.

TypeIDs are a modern, type-safe, globally unique identifier based on the upcoming UUIDv7 standard. They provide a ton of nice properties that make them a great choice as the primary identifiers for your data in a database, APIs, and distributed systems. Read more about TypeIDs in their spec.

This is the official JavaScript / TypeScript implementation of TypeID by the jetify team. It provides an npm package that can be used by any JavaScript or TypeScript project.

_ If you wish to use a string-based representation of typeid (instead of class-based), please follow the instructions here. _

Installation

Using npm:

npm install typeid-js

Using yarn:

yarn add typeid-js

Using pnpm:

pnpm add typeid-js

Note: this package requires Typescript > 5.0.0

Usage

To create a random TypeID of a given type, use the typeid() function:

import { typeid } from 'typeid-js';
const tid = typeid('prefix');

The prefix is optional, so if you need to create an id without a type prefix, you can do that too:

import { typeid } from 'typeid-js';
const tid = typeid();

The return type of typeid("prefix") is TypeID<"prefix">, which lets you use TypeScript's type checking to ensure you are passing the correct type prefix to functions that expect it.

For example, you can create a function that only accepts TypeIDs of type user:

import { typeid, TypeID } from 'typeid-js';

function doSomethingWithUserID(id: TypeID<'user'>) {
    // ...
}

In addition to the typeid() function, the TypeID class has additional methods to encode/decode from other formats.

For example, to parse an existing typeid from a string:

import { TypeID } from 'typeid-js';

// The asType() call is optional, but it converts to type TypeID<"prefix"> instead
// of TypeID<string>
const tid = TypeID.fromString('prefix_00041061050r3gg28a1c60t3gf').asType(
    'prefix'
);

To encode an existing UUID as a TypeID:

import { TypeID } from 'typeid-js';

// In this case TypeID<"prefix"> is inferred from the first argument
const tid = TypeID.fromUUID('prefix', '00000000-0000-0000-0000-000000000000');

The full list of methods includes:

  • getType(): Returns the type of the type prefix
  • getSuffix(): Returns uuid suffix in its base32 representation
  • toString(): Encodes the object as a string, using the canonical format
  • toUUID(): Decodes the TypeID into a UUID string in hex format. The type prefix is ignored
  • toUUIDBytes(): Decodes the TypeID into a UUID byte array. The type prefix is ignored
  • fromString(str): Parses a TypeID from a string
  • fromUUID(prefix, uuid): Creates a TypeID from a prefix and a UUID in hex format
  • fromUUIDBytes(prefix, bytes): Creates a TypeID from a prefix and a UUID in byte array format

typeid-js's People

Contributors

broothie avatar danhulton avatar dbalatero avatar dependabot[bot] avatar loreto avatar lucilleh avatar mikeland73 avatar parasdaryanani avatar reecefenwick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

typeid-js's Issues

Publish to npm

Will this get published to NPM, or do we need to fork it?

Does this require a minimum TypeScript version?

My company is stuck on TS 4.9.4, and out of the box this library is broken.

Is there a minimum TS version that should be documented in the README.md? I see typescript is at some 5.x version in the package.json.

Build errors:

../../../node_modules/typeid-js/dist/typeid.d.ts:1:22 - error TS1139: Type parameter declaration expected.

1 declare class TypeID<const T extends string> {
                       ~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:1:30 - error TS1005: ',' expected.

1 declare class TypeID<const T extends string> {
                               ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:1:44 - error TS1005: ',' expected.

1 declare class TypeID<const T extends string> {
                                             ~

../../../node_modules/typeid-js/dist/typeid.d.ts:2:19 - error TS1005: ',' expected.

2     private prefix;
                    ~

../../../node_modules/typeid-js/dist/typeid.d.ts:3:19 - error TS1005: ',' expected.

3     private suffix;
                    ~

../../../node_modules/typeid-js/dist/typeid.d.ts:5:5 - error TS1005: ',' expected.

5     getType(): T;
      ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:6:5 - error TS1005: ',' expected.

6     getSuffix(): string;
      ~~~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:5 - error TS1005: ',' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
      ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:12 - error TS1139: Type parameter declaration expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
             ~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:18 - error TS1005: ':' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                   ~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:20 - error TS1005: ',' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                     ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:28 - error TS1005: ':' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                             ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:42 - error TS1005: ')' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                                           ~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:45 - error TS1005: ',' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                                              ~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:46 - error TS1136: Property assignment expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                                               ~

../../../node_modules/typeid-js/dist/typeid.d.ts:7:57 - error TS1005: '(' expected.

7     asType<const U extends string>(prefix: U): TypeID<U>;
                                                          ~

../../../node_modules/typeid-js/dist/typeid.d.ts:8:5 - error TS1005: ',' expected.

8     toUUIDBytes(): Uint8Array;
      ~~~~~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:9:5 - error TS1005: ',' expected.

9     toUUID(): string;
      ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:10:5 - error TS1005: ',' expected.

10     toString(): `${T}_${string}` | string;
       ~~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:5 - error TS1005: ',' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
       ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:23 - error TS1139: Type parameter declaration expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                         ~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:29 - error TS1005: ':' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                               ~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:31 - error TS1005: ',' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                 ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:39 - error TS1005: ':' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                         ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:50 - error TS1005: ')' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                                    ~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:58 - error TS1005: ',' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                                            ~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:59 - error TS1136: Property assignment expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                                             ~

../../../node_modules/typeid-js/dist/typeid.d.ts:11:70 - error TS1005: '(' expected.

11     static fromString<const T extends string>(str: string): TypeID<T>;
                                                                        ~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:5 - error TS1005: ',' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
       ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:26 - error TS1139: Type parameter declaration expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                            ~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:32 - error TS1005: ':' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                  ~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:34 - error TS1005: ',' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                    ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:42 - error TS1005: ':' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                            ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:56 - error TS1005: ')' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                                          ~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:78 - error TS1005: ',' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                                                                ~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:79 - error TS1136: Property assignment expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                                                                 ~

../../../node_modules/typeid-js/dist/typeid.d.ts:12:90 - error TS1005: '(' expected.

12     static fromUUIDBytes<const T extends string>(prefix: T, bytes: Uint8Array): TypeID<T>;
                                                                                            ~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:5 - error TS1005: ',' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
       ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:21 - error TS1139: Type parameter declaration expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                       ~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:27 - error TS1005: ':' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                             ~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:29 - error TS1005: ',' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                               ~~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:37 - error TS1005: ':' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                                       ~~~~~~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:51 - error TS1005: ')' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                                                     ~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:68 - error TS1005: ',' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                                                                      ~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:69 - error TS1136: Property assignment expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                                                                       ~

../../../node_modules/typeid-js/dist/typeid.d.ts:13:80 - error TS1005: '(' expected.

13     static fromUUID<const T extends string>(prefix: T, uuid: string): TypeID<T>;
                                                                                  ~


Found 46 errors in the same file, starting at: ../../../node_modules/typeid-js/dist/typeid.d.ts:1

Doesn't work in browser?

Tried this in my frontend project and surprised that is simply crashed with "Buffer is not defined". Looks like it's assuming node.js environment. Is there a plan to make this package work in the browser? Not being able to use on the frontend would severely limit the adoption.

Typed `toString()`?

Typescript, since 4.1, allows for string templates such as \user_${string}``. I've taken advantage of this to create "string types" to pair with my TypeID types:

export type UserTypeString = `user_${string}`;
export type UserTypeID = TypeID<'user'>;

// ...

private connectedUsers: Record<UserTypeString, User> = {};

You can't use UserTypeID as an index, but you can use UserTypeString, and it makes it a lot clearer exactly what you're keying by.

However, later, when you do something like this, it will fail:

const userId = user.id.toString();
connectedUsers[userId] = user;

toString() returns a string, but I want it to return a user_${string}. For now, I'm planning on subclassing TypeID in my project and overriding the toString() function to work the way I want, but is this something there would be interest in having added to the base library?

Specifically, I've added:

  public toTypeString(): `${T}_${string}` {
    return this.toString() as `${T}_${string}`;
  }

Instead of modifying toString(), since that'll break everything that is expecting a regular string from that function. This seems like a pretty simple little addition that gives a fair extra bit of clarity when using the string form of TypeIDs as indexes.

Unboxed TypeScript implementation of TypeIDs

Hi, first of all thanks for this project! I liked using it for my project but had some trouble because of the in-memory representation of TypeIDs using class instances.

One issue was that I needed to serialize and de-serialize it using a custom type in Drizzle ORM:

const makeCustomId = <T extends string>(dbName: string, prefix: T) =>
  customType<{
    data: TypeID<T>;
    driverData: string;
  }>({
    dataType() {
      return "string";
    },
    fromDriver(value: string): TypeID<T> {
      return TypeID.fromString(value).asType(prefix);
    },
  })(dbName);

This works, apart from seeing [Object object] in some devtools.

Another issue was returning TypeID values from a Qwik City routeLoader$. It gives an error that it can't serialize these values as it only supports serializing JS primitives, arrays and plain objects. This meant I had to map every value I get from db first to update the IDs to string, and then back to TypeID's on the client side.

To make my workflow easier, I forked typeid-js and built an alternative that always represents TypeIDs as strings at runtime, provides some helper functions, and uses branded TypeScript types for type safety: https://github.com/ozanmakes/typeid-unboxed

I'm curious to hear what you think. Is this something you'd like to include in this package? Otherwise, do you bless such an approach and would you mind if I publish this on npm under this name or something else?

Branded type usage

Any plans to make TypeIDs even safer at the type level using nominal typing ?

It would be great to have an API that fails typechecking for instances like these :

function getUser(userId: TypeID<'user'>) { ... }

const userId = typeid('user')  // Inferred as TypeID<'user'>
const postId = typeid('post') // Inferred as TypeID<'post'>

getUser(userId) // Ok
getUser(postId) // Fails at compile time

New parsing functions could be added to instanciate properly typed TypeIDs :

// Inferred as TypeId<'prefix'
const prefixId = TypeID.fromPrefixedString('prefix', 'prefix_00041061050r3gg28a1c60t3gf') 

// Inferred as TypeId<'prefix'> but fails at runtime.
const otherPrefixId = TypeID.fromPrefixedString('prefix', 'other_00041061050r3gg28a1c60t3gf') 

Double check implementation?

Using this tool: https://cryptii.com/pipes/crockford-base32

CleanShot 2023-06-29 at 20 45 27@2x

But the tests for the same input shows:

https://github.com/jetpack-io/typeid-ts/blob/091938da886f4d944a685158f9ea4fbcbfdbe1e0/test/typeid.test.ts#L114-L117

I was porting the code to Elixir using https://hex.pm/packages/crockford_base32 and the result from the library matches the online tool but does not match the Typescript implementation.

test "encode" do
  assert Typeid.encode("user", "01889c89-df6b-7f1c-a388-91396ec314bc") == {
           :ok,
           "user_0649s2ezddzhs8w8j4wpxgrmqg"
         }
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.