pika-id
Version:
The pragmatic ID system
97 lines (96 loc) • 4.75 kB
JavaScript
;
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();