UNPKG

pika-id

Version:

The pragmatic ID system

97 lines (96 loc) 4.75 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Snowflake_epoch, _Snowflake_nodeId, _Snowflake_seq, _Snowflake_lastSequenceExhaustion; Object.defineProperty(exports, "__esModule", { value: true }); exports.Snowflake = void 0; /** * A class for generating and deconstructing snowflakes. * * Pika has put it's own spin on Twitter snowflakes to simplify deployment * and setup. Instead of having a separate worker and process ID, we have * one node ID that takes up the 10 bits these fields would usually use. * * A node ID is computed by taking the MAC address of the first available * public interface on the device, then calculating the modulo against * 1024 (10b) * * If we have a snowflake `963584775274749952n` we can represent it as binary: * ``` * 64 22 12 0 * 000011010101111101011111011110000011001010 0001000101 000000000000 * number of ms since epoch node id sequence * ``` */ class Snowflake { /** * @param epoch the base epoch to use * @param nodeId optionally pass a static node identifier (0-1023) */ constructor(epoch, nodeId) { /** * Snowflakes generated are derived from this epoch * @internal */ _Snowflake_epoch.set(this, void 0); /** * Passed in node ID for this Snowflake instance * @internal */ _Snowflake_nodeId.set(this, void 0); /** * Current sequence number (0-4095) * @internal */ _Snowflake_seq.set(this, 0n); /** * Last timestamp of the last time the sequence was exhausted * @internal */ _Snowflake_lastSequenceExhaustion.set(this, 0); __classPrivateFieldSet(this, _Snowflake_epoch, this.normalizeEpoch(epoch), "f"); __classPrivateFieldSet(this, _Snowflake_nodeId, BigInt(nodeId), "f"); } get nodeId() { return Number(this.nodeId); } gen({ timestamp = Date.now() } = {}) { const nTimestamp = this.normalizeEpoch(timestamp); if (__classPrivateFieldGet(this, _Snowflake_seq, "f") === 4095n && timestamp === __classPrivateFieldGet(this, _Snowflake_lastSequenceExhaustion, "f")) { // purposely blocking while (Date.now() - timestamp < 1) { continue; } } __classPrivateFieldSet(this, _Snowflake_seq, __classPrivateFieldGet(this, _Snowflake_seq, "f") >= 4095n ? 0n : __classPrivateFieldGet(this, _Snowflake_seq, "f") + 1n, "f"); if (__classPrivateFieldGet(this, _Snowflake_seq, "f") === 4095n) __classPrivateFieldSet(this, _Snowflake_lastSequenceExhaustion, Date.now(), "f"); return (((nTimestamp - __classPrivateFieldGet(this, _Snowflake_epoch, "f")) << 22n) | // millis since epoch ((__classPrivateFieldGet(this, _Snowflake_nodeId, "f") & 1023n) << 12n) | __classPrivateFieldGet(this, _Snowflake_seq, "f")).toString(); } deconstruct(id) { const bigIntId = BigInt(id); return { id: bigIntId, timestamp: (bigIntId >> 22n) + __classPrivateFieldGet(this, _Snowflake_epoch, "f"), nodeId: Number((bigIntId >> 12n) & 1023n), seq: Number(bigIntId & 4095n), epoch: __classPrivateFieldGet(this, _Snowflake_epoch, "f"), }; } normalizeEpoch(epoch) { return BigInt(epoch instanceof Date ? epoch.getTime() : epoch); } } exports.Snowflake = Snowflake; _Snowflake_epoch = new WeakMap(), _Snowflake_nodeId = new WeakMap(), _Snowflake_seq = new WeakMap(), _Snowflake_lastSequenceExhaustion = new WeakMap();