@prisma/param-graph
Advanced tools
+102
-0
@@ -7,2 +7,104 @@ /** | ||
| * for structural data (nodes, edges, roots). | ||
| * | ||
| * ## Serialized Representation | ||
| * | ||
| * ``` | ||
| * SerializedParamGraph { | ||
| * strings: string[] // String table (field names, enum names, root keys) | ||
| * graph: string // Base64url-encoded binary blob | ||
| * } | ||
| * ``` | ||
| * | ||
| * ## Why Hybrid? | ||
| * | ||
| * - **Strings stay as JSON**: V8's JSON.parse is highly optimized for string arrays | ||
| * - **Structure goes binary**: Indices, flags, masks benefit from compact encoding | ||
| * - **Best of both**: Fast parsing + compact size where it matters | ||
| * | ||
| * ## Format Selection | ||
| * | ||
| * Two binary formats based on data size (selected automatically at serialization): | ||
| * | ||
| * - **Compact (0x00)**: 16-bit indices, for graphs with ≤65534 items | ||
| * - **Wide (0x01)**: 32-bit indices, for larger graphs | ||
| * | ||
| * Sentinel values for "none/undefined": 0xFFFF (compact) or 0xFFFFFFFF (wide) | ||
| * | ||
| * ## Binary Blob Layout | ||
| * | ||
| * All multi-byte integers are little-endian. | ||
| * | ||
| * ``` | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ HEADER │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ format: u8 │ 0x00 = compact (16-bit), 0x01 = wide │ | ||
| * │ padding: 1|3 bytes │ Alignment padding (1 compact, 3 wide) │ | ||
| * │ inputNodeCount: word │ Number of input nodes │ | ||
| * │ outputNodeCount: word │ Number of output nodes │ | ||
| * │ rootCount: word │ Number of root entries │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ INPUT NODES (repeated inputNodeCount times) │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ edgeCount: word │ Number of edges in this node │ | ||
| * │ edges[] │ Edge data (see Input Edge below) │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ INPUT EDGE (compact: 10 bytes, wide: 20 bytes) │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ fieldIndex: word │ Index into string table │ | ||
| * │ scalarMask: u16 │ Scalar type bitmask (0 if none) │ | ||
| * │ [padding: 2 bytes] │ (wide format only, for alignment) │ | ||
| * │ childNodeId: word │ Child input node ID (sentinel=none) │ | ||
| * │ enumNameIndex: word │ Enum name in string table (sentinel=none) │ | ||
| * │ flags: u8 │ Edge capability flags │ | ||
| * │ padding: 1|3 bytes │ Alignment padding (1 compact, 3 wide) │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ OUTPUT NODES (repeated outputNodeCount times) │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ edgeCount: word │ Number of edges in this node │ | ||
| * │ edges[] │ Edge data (see Output Edge below) │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ OUTPUT EDGE (compact: 6 bytes, wide: 12 bytes) │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ fieldIndex: word │ Index into string table │ | ||
| * │ argsNodeId: word │ Args input node ID (sentinel=none) │ | ||
| * │ outputNodeId: word │ Child output node ID (sentinel=none) │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * | ||
| * ┌───────────────────────────────────────────────────────────────────┐ | ||
| * │ ROOTS (repeated rootCount times) │ | ||
| * ├───────────────────────────────────────────────────────────────────┤ | ||
| * │ keyIndex: word │ Root key index in string table │ | ||
| * │ argsNodeId: word │ Args input node ID (sentinel=none) │ | ||
| * │ outputNodeId: word │ Output node ID (sentinel=none) │ | ||
| * └───────────────────────────────────────────────────────────────────┘ | ||
| * ``` | ||
| * | ||
| * Where "word" is u16 (compact) or u32 (wide). | ||
| * | ||
| * ## Size Summary | ||
| * | ||
| * | Component | Compact | Wide | | ||
| * |----------------|----------|----------| | ||
| * | Header | 8 bytes | 16 bytes | | ||
| * | Input Edge | 10 bytes | 20 bytes | | ||
| * | Output Edge | 6 bytes | 12 bytes | | ||
| * | Root Entry | 6 bytes | 12 bytes | | ||
| * | ||
| * ## Embedding in Generated Client | ||
| * | ||
| * ```js | ||
| * config.parameterizationSchema = { | ||
| * strings: JSON.parse('["where","id","email",...]'), | ||
| * graph: "base64url_encoded_binary_blob..." | ||
| * } | ||
| * ``` | ||
| */ | ||
@@ -9,0 +111,0 @@ import type { ParamGraphData } from './types'; |
@@ -102,4 +102,3 @@ "use strict"; | ||
| #calculateBufferSize() { | ||
| let size = 1; | ||
| size += this.#useWide ? 12 : 6; | ||
| let size = this.#useWide ? 16 : 8; | ||
| for (const node of this.#data.inputNodes) { | ||
@@ -120,2 +119,3 @@ size += this.#wordSize; | ||
| this.#writeByte(this.#useWide ? FORMAT_WIDE : FORMAT_COMPACT); | ||
| this.#skip(this.#useWide ? 3 : 1); | ||
| this.#writeWord(this.#data.inputNodes.length); | ||
@@ -159,2 +159,5 @@ this.#writeWord(this.#data.outputNodes.length); | ||
| const keyIndex = this.#data.strings.indexOf(key); | ||
| if (keyIndex === -1) { | ||
| throw new Error(`Root key "${key}" not found in strings table`); | ||
| } | ||
| this.#writeWord(keyIndex); | ||
@@ -223,3 +226,7 @@ this.#writeOptionalWord(root.argsNodeId); | ||
| const format = this.#readByte(); | ||
| if (format !== FORMAT_COMPACT && format !== FORMAT_WIDE) { | ||
| throw new Error(`Unknown param graph format: 0x${format.toString(16).padStart(2, "0")}`); | ||
| } | ||
| this.#useWide = format === FORMAT_WIDE; | ||
| this.#skip(this.#useWide ? 3 : 1); | ||
| const inputNodeCount = this.#readWord(); | ||
@@ -226,0 +233,0 @@ const outputNodeCount = this.#readWord(); |
@@ -78,4 +78,3 @@ function serializeParamGraph(data) { | ||
| #calculateBufferSize() { | ||
| let size = 1; | ||
| size += this.#useWide ? 12 : 6; | ||
| let size = this.#useWide ? 16 : 8; | ||
| for (const node of this.#data.inputNodes) { | ||
@@ -96,2 +95,3 @@ size += this.#wordSize; | ||
| this.#writeByte(this.#useWide ? FORMAT_WIDE : FORMAT_COMPACT); | ||
| this.#skip(this.#useWide ? 3 : 1); | ||
| this.#writeWord(this.#data.inputNodes.length); | ||
@@ -135,2 +135,5 @@ this.#writeWord(this.#data.outputNodes.length); | ||
| const keyIndex = this.#data.strings.indexOf(key); | ||
| if (keyIndex === -1) { | ||
| throw new Error(`Root key "${key}" not found in strings table`); | ||
| } | ||
| this.#writeWord(keyIndex); | ||
@@ -199,3 +202,7 @@ this.#writeOptionalWord(root.argsNodeId); | ||
| const format = this.#readByte(); | ||
| if (format !== FORMAT_COMPACT && format !== FORMAT_WIDE) { | ||
| throw new Error(`Unknown param graph format: 0x${format.toString(16).padStart(2, "0")}`); | ||
| } | ||
| this.#useWide = format === FORMAT_WIDE; | ||
| this.#skip(this.#useWide ? 3 : 1); | ||
| const inputNodeCount = this.#readWord(); | ||
@@ -202,0 +209,0 @@ const outputNodeCount = this.#readWord(); |
+1
-1
| { | ||
| "name": "@prisma/param-graph", | ||
| "version": "7.4.0-integration-parameterization.10", | ||
| "version": "7.4.0-integration-parameterization.11", | ||
| "description": "This package is intended for Prisma's internal use", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
68758
13.41%1623
7.7%3
200%