diff --git a/.gitmodules b/.gitmodules index ca42c7a95..9236f112c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -328,3 +328,8 @@ url = https://github.com/distilled-mirror/spec-mirror-trigger-dev.git ignore = dirty shallow = true +[submodule "packages/turbopuffer/specs/spec-mirror-turbopuffer"] + path = packages/turbopuffer/specs/spec-mirror-turbopuffer + url = https://github.com/distilled-mirror/spec-mirror-turbopuffer.git + ignore = dirty + shallow = true diff --git a/packages/turbopuffer/.generated-specs/turbopuffer.json b/packages/turbopuffer/.generated-specs/turbopuffer.json new file mode 100644 index 000000000..c2b63dada --- /dev/null +++ b/packages/turbopuffer/.generated-specs/turbopuffer.json @@ -0,0 +1,2520 @@ +{ + "smithy": "2.0", + "metadata": { + "suppressions": [ + { + "id": "HttpUriConflict", + "namespace": "*" + }, + { + "id": "HttpMethodSemantics", + "namespace": "*" + }, + { + "id": "UnreferencedShape", + "namespace": "*" + } + ], + "distilled.finalized": true + }, + "shapes": { + "com.turbopuffer.api#ListNamespacesRequest": { + "type": "structure", + "members": { + "cursor": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpQuery": "cursor", + "smithy.api#documentation": "Retrieve the next page of results." + } + }, + "prefix": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpQuery": "prefix", + "smithy.api#documentation": "Retrieve only the namespaces that match the prefix." + } + }, + "page_size": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#httpQuery": "page_size", + "smithy.api#documentation": "Limit the number of results per page." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#NamespaceSummary": { + "type": "structure", + "members": { + "id": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The namespace ID.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "A summary of a namespace." + } + }, + "com.turbopuffer.api#ListNamespacesResponseNamespacesList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#NamespaceSummary" + }, + "traits": { + "smithy.api#documentation": "The list of namespaces." + } + }, + "com.turbopuffer.api#ListNamespacesResponse": { + "type": "structure", + "members": { + "namespaces": { + "target": "com.turbopuffer.api#ListNamespacesResponseNamespacesList", + "traits": { + "smithy.api#documentation": "The list of namespaces." + } + }, + "next_cursor": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The cursor to use to retrieve the next page of results." + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#ListNamespaces": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#ListNamespacesRequest" + }, + "output": { + "target": "com.turbopuffer.api#ListNamespacesResponse" + }, + "traits": { + "smithy.api#http": { + "method": "GET", + "uri": "/v1/namespaces", + "code": 200 + }, + "smithy.api#documentation": "List namespaces." + } + }, + "com.turbopuffer.api#GetNamespaceSchemaRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#AttributeSchemaConfig": { + "type": "structure", + "members": { + "type": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {} + } + }, + "filterable": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether or not the attributes can be used in filters.\n" + } + }, + "regex": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether to enable Regex filters on this attribute.\n" + } + }, + "glob": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether to enable Glob filters on this attribute.\n" + } + }, + "fuzzy": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether to enable Fuzzy filters on this attribute.\n" + } + }, + "full_text_search": { + "target": "com.turbopuffer.api#FullTextSearch" + }, + "ann": { + "target": "com.turbopuffer.api#Ann" + }, + "sparse_knn": { + "target": "com.turbopuffer.api#SparseKnn" + }, + "embed": { + "target": "com.turbopuffer.api#AttributeEmbed", + "traits": { + "com.distilled.openapi#nullable": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Detailed configuration for an attribute attached to a document.\n" + } + }, + "com.turbopuffer.api#FullTextSearch": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Boolean" + }, + "FullTextSearchConfig": { + "target": "com.turbopuffer.api#FullTextSearchConfig" + } + }, + "traits": { + "smithy.api#documentation": "Whether this attribute can be used as part of a BM25 full-text search. Requires the `string` or `[]string` type, and by default, BM25-enabled attributes are not filterable. You can override this by setting `filterable: true`.\n" + } + }, + "com.turbopuffer.api#FullTextSearchConfig": { + "type": "structure", + "members": { + "k1": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The `k1` term saturation parameter for BM25. Defaults to `1.2`.\n" + } + }, + "b": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The `b` document length normalization parameter for BM25. Defaults to `0.75`.\n" + } + }, + "language": { + "target": "smithy.api#Document" + }, + "stemming": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Language-specific stemming for the text. Defaults to `false` (i.e., do not stem).\n" + } + }, + "remove_stopwords": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Removes common words from the text based on language. Defaults to `true` (i.e. remove common words).\n" + } + }, + "ascii_folding": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether to convert each non-ASCII character in a token to its ASCII equivalent, if one exists (e.g., à -> a). Defaults to `false` (i.e., no folding).\n" + } + }, + "case_sensitive": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether searching is case-sensitive. Defaults to `false` (i.e. case-insensitive).\n" + } + }, + "max_token_length": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Maximum length of a token in bytes. Tokens larger than this value during tokenization will be filtered out. Has to be between `1` and `254` (inclusive). Defaults to `39`.\n" + } + }, + "tokenizer": { + "target": "smithy.api#Document" + } + }, + "traits": { + "smithy.api#documentation": "Configuration options for full-text search." + } + }, + "com.turbopuffer.api#Ann": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Boolean" + }, + "AnnConfig": { + "target": "com.turbopuffer.api#AnnConfig" + } + }, + "traits": { + "smithy.api#documentation": "Whether to create an approximate nearest neighbor index for the attribute. Can be a boolean or a detailed configuration object.\n" + } + }, + "com.turbopuffer.api#AnnConfig": { + "type": "structure", + "members": { + "distance_metric": { + "target": "smithy.api#Document" + }, + "late_interaction": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Opt in to late-interaction (MUVERA) indexing. Only valid on fixed-dim `[][N]f32` vector array attributes, and is required to enable an ANN index on such attributes. Defaults to `false`.\n" + } + } + }, + "traits": { + "smithy.api#documentation": "Configuration options for ANN (Approximate Nearest Neighbor) indexing." + } + }, + "com.turbopuffer.api#SparseKnn": { + "type": "structure", + "members": { + "distance_metric": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Whether to create a sparse kNN index for the attribute. Requires the `{}f16` type.\n" + } + }, + "com.turbopuffer.api#AttributeEmbed": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#String" + }, + "AttributeEmbedConfig": { + "target": "com.turbopuffer.api#AttributeEmbedConfig" + } + }, + "traits": { + "smithy.api#documentation": "Whether to automatically embed this string attribute into a vector attribute. Can be a model name, a detailed configuration object, or `null` to remove an existing embedding configuration.\n" + } + }, + "com.turbopuffer.api#AttributeEmbedConfig": { + "type": "structure", + "members": { + "attribute": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The name of an existing vector attribute to store embeddings in. If omitted, turbopuffer will generate a computed vector attribute named `$embed_`.\n" + } + }, + "model": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The model to use for embedding. See our documentation for a list of models supported in each region.\n", + "smithy.api#required": {} + } + }, + "dims": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The dimensionality to embed at. If not set, will pick the default for this model. If you're storing embeddings in an existing attribute, this can be omitted, and may not be set to a value other than the dimensions of that attribute.\n" + } + } + }, + "traits": { + "smithy.api#documentation": "Configuration options for automatic embedding." + } + }, + "com.turbopuffer.api#GetNamespaceSchemaResponseBodyMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "com.turbopuffer.api#AttributeSchemaConfig" + }, + "traits": { + "smithy.api#documentation": "The response to a successful namespace schema request." + } + }, + "com.turbopuffer.api#GetNamespaceSchemaResponse": { + "type": "structure", + "members": { + "body": { + "target": "com.turbopuffer.api#GetNamespaceSchemaResponseBodyMap", + "traits": { + "com.distilled.openapi#rawResponse": {}, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#GetNamespaceSchema": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#GetNamespaceSchemaRequest" + }, + "output": { + "target": "com.turbopuffer.api#GetNamespaceSchemaResponse" + }, + "traits": { + "smithy.api#http": { + "method": "GET", + "uri": "/v1/namespaces/{namespace}/schema", + "code": 200 + }, + "smithy.api#documentation": "Get namespace schema." + } + }, + "com.turbopuffer.api#AttributeSchema": { + "type": "union", + "members": { + "AttributeType": { + "target": "smithy.api#String" + }, + "AttributeSchemaConfig": { + "target": "com.turbopuffer.api#AttributeSchemaConfig" + } + }, + "traits": { + "smithy.api#documentation": "The schema for an attribute attached to a document." + } + }, + "com.turbopuffer.api#CreateNamespaceSchemaRequestBodyMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "com.turbopuffer.api#AttributeSchema" + }, + "traits": { + "smithy.api#documentation": "The desired schema for the namespace." + } + }, + "com.turbopuffer.api#CreateNamespaceSchemaRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "body": { + "target": "com.turbopuffer.api#CreateNamespaceSchemaRequestBodyMap", + "traits": { + "smithy.api#httpPayload": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#CreateNamespaceSchemaResponseBodyMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "com.turbopuffer.api#AttributeSchemaConfig" + }, + "traits": { + "smithy.api#documentation": "The updated schema for the namespace." + } + }, + "com.turbopuffer.api#CreateNamespaceSchemaResponse": { + "type": "structure", + "members": { + "body": { + "target": "com.turbopuffer.api#CreateNamespaceSchemaResponseBodyMap", + "traits": { + "com.distilled.openapi#rawResponse": {}, + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#CreateNamespaceSchema": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#CreateNamespaceSchemaRequest" + }, + "output": { + "target": "com.turbopuffer.api#CreateNamespaceSchemaResponse" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v1/namespaces/{namespace}/schema", + "code": 200 + }, + "smithy.api#documentation": "Update namespace schema." + } + }, + "com.turbopuffer.api#GetNamespaceMetadataRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#NamespaceMetadata": { + "type": "structure", + "members": { + "schema": { + "target": "com.turbopuffer.api#NamespaceMetadataSchemaMap", + "traits": { + "smithy.api#documentation": "The schema of the namespace.", + "smithy.api#required": {} + } + }, + "approx_row_count": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The approximate number of rows in the namespace.", + "smithy.api#required": {} + } + }, + "approx_logical_bytes": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The approximate number of logical bytes in the namespace.", + "smithy.api#required": {} + } + }, + "created_at": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The timestamp when the namespace was created.", + "smithy.api#required": {} + } + }, + "updated_at": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The timestamp when the namespace was last modified by a write operation.", + "smithy.api#required": {} + } + }, + "encryption": { + "target": "com.turbopuffer.api#Encryption", + "traits": { + "smithy.api#required": {} + } + }, + "index": { + "target": "com.turbopuffer.api#NamespaceMetadataIndex", + "traits": { + "smithy.api#required": {} + } + }, + "pinning": { + "target": "com.turbopuffer.api#PinningConfigResponse" + }, + "sharding": { + "target": "com.turbopuffer.api#ShardingConfig" + } + }, + "traits": { + "smithy.api#documentation": "Metadata about a namespace." + } + }, + "com.turbopuffer.api#NamespaceMetadataSchemaMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "com.turbopuffer.api#AttributeSchemaConfig" + }, + "traits": { + "smithy.api#documentation": "The schema of the namespace." + } + }, + "com.turbopuffer.api#Encryption": { + "type": "union", + "members": { + "Case0": { + "target": "com.turbopuffer.api#EncryptionCase0" + }, + "Case1": { + "target": "com.turbopuffer.api#EncryptionCase1" + } + }, + "traits": { + "smithy.api#documentation": "The encryption configuration for a namespace." + } + }, + "com.turbopuffer.api#EncryptionCase0": { + "type": "structure", + "members": { + "mode": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#required": {} + } + }, + "key_name": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The identifier of the CMEK key to use for encryption. For GCP, the fully-qualified resource name of the key. For AWS, the ARN of the key.\n", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Encrypt the namespace with a customer-managed encryption key (CMEK)." + } + }, + "com.turbopuffer.api#EncryptionCase1": { + "type": "structure", + "members": { + "mode": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Use the default server-side encryption (SSE)." + } + }, + "com.turbopuffer.api#NamespaceMetadataIndexCase0": { + "type": "structure", + "members": { + "status": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#NamespaceMetadataIndexCase1": { + "type": "structure", + "members": { + "status": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#required": {} + } + }, + "unindexed_bytes": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of bytes in the namespace that are in the write-ahead log but have not yet been indexed.", + "smithy.api#required": {} + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#NamespaceMetadataIndex": { + "type": "union", + "members": { + "Case0": { + "target": "com.turbopuffer.api#NamespaceMetadataIndexCase0" + }, + "Case1": { + "target": "com.turbopuffer.api#NamespaceMetadataIndexCase1" + } + }, + "traits": {} + }, + "com.turbopuffer.api#PinningConfigResponse": { + "type": "structure", + "members": { + "replicas": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of read replicas to provision. Defaults to 1 if not specified." + } + }, + "status": { + "target": "com.turbopuffer.api#PinningStatus" + } + }, + "traits": { + "smithy.api#documentation": "Configuration for namespace pinning, along with the current status of the pinned namespace.\n" + } + }, + "com.turbopuffer.api#PinningStatus": { + "type": "structure", + "members": { + "updated_at": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The timestamp of the latest pinning status snapshot.", + "smithy.api#required": {} + } + }, + "ready_replicas": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of replicas that are warm and serving traffic.", + "smithy.api#required": {} + } + }, + "utilization": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "Aggregate utilization for the pinned namespace, reported as a value between 0.0 and 1.0.\n", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Operational status for a pinned namespace." + } + }, + "com.turbopuffer.api#ShardingConfig": { + "type": "structure", + "members": { + "num_shards": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of shards to partition the namespace into.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Configuration for namespace sharding, which partitions a namespace's documents across multiple internal shards to scale indexing and query throughput beyond a single machine.\nSharding can only be configured on a namespace's inaugural write, and cannot be added to or changed on an existing namespace.\n" + } + }, + "com.turbopuffer.api#GetNamespaceMetadata": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#GetNamespaceMetadataRequest" + }, + "output": { + "target": "com.turbopuffer.api#NamespaceMetadata" + }, + "traits": { + "smithy.api#http": { + "method": "GET", + "uri": "/v2/namespaces/{namespace}/metadata", + "code": 200 + }, + "smithy.api#documentation": "Get metadata about a namespace." + } + }, + "com.turbopuffer.api#PinningConfig": { + "type": "structure", + "members": { + "replicas": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of read replicas to provision. Defaults to 1 if not specified." + } + } + }, + "traits": { + "smithy.api#documentation": "Configuration for namespace pinning." + } + }, + "com.turbopuffer.api#UpdateNamespaceMetadataRequestPinning": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Boolean" + }, + "PinningConfig": { + "target": "com.turbopuffer.api#PinningConfig" + } + }, + "traits": { + "smithy.api#documentation": "Configuration for namespace pinning.\n- Missing field: no change to pinning configuration\n- `null` or `false`: explicitly remove pinning\n- `true`: enable pinning with default configuration\n- Object: set pinning configuration\n" + } + }, + "com.turbopuffer.api#UpdateNamespaceMetadataRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "pinning": { + "target": "com.turbopuffer.api#UpdateNamespaceMetadataRequestPinning", + "traits": { + "smithy.api#documentation": "Configuration for namespace pinning.\n- Missing field: no change to pinning configuration\n- `null` or `false`: explicitly remove pinning\n- `true`: enable pinning with default configuration\n- Object: set pinning configuration\n", + "com.distilled.openapi#nullable": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#UpdateNamespaceMetadata": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#UpdateNamespaceMetadataRequest" + }, + "output": { + "target": "com.turbopuffer.api#NamespaceMetadata" + }, + "traits": { + "smithy.api#http": { + "method": "PATCH", + "uri": "/v1/namespaces/{namespace}/metadata", + "code": 200 + }, + "smithy.api#documentation": "Update metadata configuration for a namespace." + } + }, + "com.turbopuffer.api#GetNamespaceHintCacheWarmRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#GetNamespaceHintCacheWarmResponse": { + "type": "structure", + "members": { + "status": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The status of the request.", + "smithy.api#required": {} + } + }, + "message": { + "target": "smithy.api#String" + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#GetNamespaceHintCacheWarm": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#GetNamespaceHintCacheWarmRequest" + }, + "output": { + "target": "com.turbopuffer.api#GetNamespaceHintCacheWarmResponse" + }, + "traits": { + "smithy.api#http": { + "method": "GET", + "uri": "/v1/namespaces/{namespace}/hint_cache_warm", + "code": 200 + }, + "smithy.api#documentation": "Signal turbopuffer to prepare for low-latency requests." + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "num": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of searches to run." + } + }, + "top_k": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Search for `top_k` nearest neighbors." + } + }, + "filters": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "Filter by attributes. Same syntax as the query endpoint." + } + }, + "include_ground_truth": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Include ground truth data (query vectors and true nearest neighbors) in the response." + } + }, + "rank_by": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The ranking function to evaluate recall for. If provided, `num` must be either null or 1.\n" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList": { + "type": "list", + "member": { + "target": "smithy.api#Double" + }, + "traits": { + "smithy.api#documentation": "The query vector used for this search." + } + }, + "com.turbopuffer.api#Row": { + "type": "structure", + "members": { + "id": { + "target": "com.turbopuffer.api#Id", + "traits": { + "smithy.api#required": {} + } + }, + "vector": { + "target": "com.turbopuffer.api#Vector" + } + }, + "traits": { + "smithy.api#documentation": "A single document, in a row-based format." + } + }, + "com.turbopuffer.api#Id": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#String" + }, + "Case2": { + "target": "smithy.api#Integer" + } + }, + "traits": { + "smithy.api#documentation": "An identifier for a document." + } + }, + "com.turbopuffer.api#Vector": { + "type": "union", + "members": { + "Case0": { + "target": "com.turbopuffer.api#VectorCase0List" + }, + "Case1": { + "target": "smithy.api#String" + } + }, + "traits": { + "smithy.api#documentation": "A vector embedding associated with a document." + } + }, + "com.turbopuffer.api#VectorCase0List": { + "type": "list", + "member": { + "target": "smithy.api#Double" + }, + "traits": { + "smithy.api#documentation": "A dense vector encoded as an array of floats." + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Row" + }, + "traits": { + "smithy.api#documentation": "The true nearest neighbors with their distances and vectors." + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItem": { + "type": "structure", + "members": { + "query_vector": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList", + "traits": { + "smithy.api#documentation": "The query vector used for this search.", + "smithy.api#required": {} + } + }, + "nearest_neighbors": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList", + "traits": { + "smithy.api#documentation": "The true nearest neighbors with their distances and vectors.", + "smithy.api#required": {} + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthItem" + }, + "traits": { + "smithy.api#documentation": "Ground truth data including query vectors and true nearest neighbors. Only included when include_ground_truth is true." + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecallResponse": { + "type": "structure", + "members": { + "avg_recall": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The average recall of the queries.", + "smithy.api#required": {} + } + }, + "avg_exhaustive_count": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The average number of documents retrieved by the exhaustive searches.", + "smithy.api#required": {} + } + }, + "avg_ann_count": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The average number of documents retrieved by the approximate nearest neighbor searches.", + "smithy.api#required": {} + } + }, + "ground_truth": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallResponseGroundTruthList", + "traits": { + "smithy.api#documentation": "Ground truth data including query vectors and true nearest neighbors. Only included when include_ground_truth is true." + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#CreateNamespaceDebugRecall": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallRequest" + }, + "output": { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecallResponse" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v1/namespaces/{namespace}/_debug/recall", + "code": 200 + }, + "smithy.api#documentation": "Evaluate recall." + } + }, + "com.turbopuffer.api#Columns": { + "type": "structure", + "members": { + "id": { + "target": "com.turbopuffer.api#ColumnsIdList", + "traits": { + "smithy.api#documentation": "The IDs of the documents.", + "smithy.api#required": {} + } + }, + "vector": { + "target": "com.turbopuffer.api#ColumnsVector" + } + }, + "traits": { + "smithy.api#documentation": "A list of documents in columnar format. Each key is a column name, mapped to an array of values for that column.\n" + } + }, + "com.turbopuffer.api#ColumnsIdList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Id" + }, + "traits": { + "smithy.api#documentation": "The IDs of the documents." + } + }, + "com.turbopuffer.api#ColumnsVectorCase0List": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Vector" + }, + "traits": { + "smithy.api#documentation": "The vector embeddings of the documents." + } + }, + "com.turbopuffer.api#ColumnsVector": { + "type": "union", + "members": { + "Case0": { + "target": "com.turbopuffer.api#ColumnsVectorCase0List" + }, + "Vector": { + "target": "com.turbopuffer.api#Vector" + } + }, + "traits": {} + }, + "com.turbopuffer.api#UpdateNamespaceRequestUpsertRowsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Row" + }, + "traits": {} + }, + "com.turbopuffer.api#UpdateNamespaceRequestPatchRowsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Row" + }, + "traits": {} + }, + "com.turbopuffer.api#UpdateNamespaceRequestDeletesList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Id" + }, + "traits": {} + }, + "com.turbopuffer.api#UpdateNamespaceRequestSchemaMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "com.turbopuffer.api#AttributeSchema" + }, + "traits": { + "smithy.api#documentation": "The schema of the attributes attached to the documents.\n" + } + }, + "com.turbopuffer.api#BranchFromNamespaceParams": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#String" + }, + "BranchFromNamespaceConfig": { + "target": "com.turbopuffer.api#BranchFromNamespaceConfig" + } + }, + "traits": {} + }, + "com.turbopuffer.api#BranchFromNamespaceConfig": { + "type": "structure", + "members": { + "source_namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The namespace to create an instant, copy-on-write clone of.", + "smithy.api#required": {} + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#CopyFromNamespaceParams": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#String" + }, + "CopyFromNamespaceConfig": { + "target": "com.turbopuffer.api#CopyFromNamespaceConfig" + } + }, + "traits": {} + }, + "com.turbopuffer.api#CopyFromNamespaceConfig": { + "type": "structure", + "members": { + "source_namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The namespace to copy documents from.", + "smithy.api#required": {} + } + }, + "source_api_key": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "(Optional) An API key for the organization containing the source namespace" + } + }, + "source_region": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "(Optional) The region of the source namespace." + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#PatchByFilter": { + "type": "structure", + "members": { + "patch": { + "target": "com.turbopuffer.api#PatchByFilterPatchMap", + "traits": { + "smithy.api#required": {} + } + }, + "filters": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "Filter by attributes. Same syntax as the query endpoint.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "The patch and filter specifying which documents to patch." + } + }, + "com.turbopuffer.api#PatchByFilterPatchMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": {} + }, + "com.turbopuffer.api#UpdateNamespaceRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "upsert_columns": { + "target": "com.turbopuffer.api#Columns" + }, + "upsert_rows": { + "target": "com.turbopuffer.api#UpdateNamespaceRequestUpsertRowsList" + }, + "patch_columns": { + "target": "com.turbopuffer.api#Columns" + }, + "patch_rows": { + "target": "com.turbopuffer.api#UpdateNamespaceRequestPatchRowsList" + }, + "deletes": { + "target": "com.turbopuffer.api#UpdateNamespaceRequestDeletesList" + }, + "upsert_condition": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "A condition evaluated against the current value of each document targeted by an upsert write. Only documents that pass the condition are upserted.\n" + } + }, + "patch_condition": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "A condition evaluated against the current value of each document targeted by a patch write. Only documents that pass the condition are patched.\n" + } + }, + "delete_condition": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "A condition evaluated against the current value of each document targeted by a delete write. Only documents that pass the condition are deleted.\n" + } + }, + "distance_metric": { + "target": "smithy.api#Document" + }, + "schema": { + "target": "com.turbopuffer.api#UpdateNamespaceRequestSchemaMap", + "traits": { + "smithy.api#documentation": "The schema of the attributes attached to the documents.\n" + } + }, + "branch_from_namespace": { + "target": "com.turbopuffer.api#BranchFromNamespaceParams" + }, + "copy_from_namespace": { + "target": "com.turbopuffer.api#CopyFromNamespaceParams" + }, + "delete_by_filter": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The filter specifying which documents to delete." + } + }, + "delete_by_filter_allow_partial": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Allow partial completion when filter matches too many documents." + } + }, + "patch_by_filter": { + "target": "com.turbopuffer.api#PatchByFilter" + }, + "patch_by_filter_allow_partial": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Allow partial completion when filter matches too many documents." + } + }, + "return_affected_ids": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "If true, return the IDs of affected rows (deleted, patched, upserted) in the response. For filtered and conditional writes, only IDs for writes that succeeded will be included.\n" + } + }, + "encryption": { + "target": "com.turbopuffer.api#Encryption" + }, + "sharding": { + "target": "com.turbopuffer.api#ShardingConfig" + }, + "disable_backpressure": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Disables write throttling (HTTP 429 responses) during high-volume ingestion.\n" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#WriteResult": { + "type": "structure", + "members": { + "status": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The status of the request.", + "smithy.api#required": {} + } + }, + "message": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "A message describing the result of the write request.", + "smithy.api#required": {} + } + }, + "rows_affected": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of rows affected by the write request.", + "smithy.api#required": {} + } + }, + "rows_upserted": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of rows upserted by the write request." + } + }, + "rows_patched": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of rows patched by the write request." + } + }, + "rows_deleted": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of rows deleted by the write request." + } + }, + "rows_remaining": { + "target": "smithy.api#Boolean", + "traits": { + "smithy.api#documentation": "Whether more documents match the filter for partial operations." + } + }, + "upserted_ids": { + "target": "com.turbopuffer.api#WriteResultUpsertedIdsList", + "traits": { + "smithy.api#documentation": "The IDs of documents that were upserted. Only included when `return_affected_ids` is true and at least one document was upserted.\n" + } + }, + "patched_ids": { + "target": "com.turbopuffer.api#WriteResultPatchedIdsList", + "traits": { + "smithy.api#documentation": "The IDs of documents that were patched. Only included when `return_affected_ids` is true and at least one document was patched.\n" + } + }, + "deleted_ids": { + "target": "com.turbopuffer.api#WriteResultDeletedIdsList", + "traits": { + "smithy.api#documentation": "The IDs of documents that were deleted. Only included when `return_affected_ids` is true and at least one document was deleted.\n" + } + }, + "billing": { + "target": "com.turbopuffer.api#WriteBilling", + "traits": { + "smithy.api#required": {} + } + }, + "performance": { + "target": "com.turbopuffer.api#WritePerformance" + } + }, + "traits": { + "smithy.api#documentation": "The response to a successful write request." + } + }, + "com.turbopuffer.api#WriteResultUpsertedIdsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Id" + }, + "traits": { + "smithy.api#documentation": "The IDs of documents that were upserted. Only included when `return_affected_ids` is true and at least one document was upserted.\n" + } + }, + "com.turbopuffer.api#WriteResultPatchedIdsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Id" + }, + "traits": { + "smithy.api#documentation": "The IDs of documents that were patched. Only included when `return_affected_ids` is true and at least one document was patched.\n" + } + }, + "com.turbopuffer.api#WriteResultDeletedIdsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Id" + }, + "traits": { + "smithy.api#documentation": "The IDs of documents that were deleted. Only included when `return_affected_ids` is true and at least one document was deleted.\n" + } + }, + "com.turbopuffer.api#WriteBilling": { + "type": "structure", + "members": { + "billable_logical_bytes_written": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of billable logical bytes written to the namespace.", + "smithy.api#required": {} + } + }, + "query": { + "target": "com.turbopuffer.api#QueryBilling" + } + }, + "traits": { + "smithy.api#documentation": "The billing information for a write request." + } + }, + "com.turbopuffer.api#QueryBilling": { + "type": "structure", + "members": { + "billable_logical_bytes_queried": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of billable logical bytes queried from the namespace.", + "smithy.api#required": {} + } + }, + "billable_logical_bytes_returned": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of billable logical bytes returned from the query.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "The billing information for a query." + } + }, + "com.turbopuffer.api#WritePerformance": { + "type": "structure", + "members": { + "server_total_ms": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Request time measured on the server, in milliseconds.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "The performance information for a write request." + } + }, + "com.turbopuffer.api#UpdateNamespace": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#UpdateNamespaceRequest" + }, + "output": { + "target": "com.turbopuffer.api#WriteResult" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}", + "code": 200 + }, + "smithy.api#documentation": "Create, update, or delete documents." + } + }, + "com.turbopuffer.api#DeleteNamespaceRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#DeleteNamespaceResponse": { + "type": "structure", + "members": { + "status": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The status of the request.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#DeleteNamespace": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#DeleteNamespaceRequest" + }, + "output": { + "target": "com.turbopuffer.api#DeleteNamespaceResponse" + }, + "traits": { + "smithy.api#http": { + "method": "DELETE", + "uri": "/v2/namespaces/{namespace}", + "code": 200 + }, + "smithy.api#documentation": "Delete namespace." + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestConsistency": { + "type": "structure", + "members": { + "level": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The query's consistency level." + } + } + }, + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "com.turbopuffer.api#IncludeAttributes": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Boolean" + }, + "Case1": { + "target": "com.turbopuffer.api#IncludeAttributesCase1List" + } + }, + "traits": { + "smithy.api#documentation": "Whether to include attributes in the response." + } + }, + "com.turbopuffer.api#IncludeAttributesCase1List": { + "type": "list", + "member": { + "target": "smithy.api#String" + }, + "traits": { + "smithy.api#documentation": "Include exactly the specified attributes in the response.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestExcludeAttributesList": { + "type": "list", + "member": { + "target": "smithy.api#String" + }, + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestAggregateByMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestGroupByList": { + "type": "list", + "member": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestComputeAttributesMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "com.turbopuffer.api#Limit": { + "type": "structure", + "members": { + "total": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Limits the total number of documents returned.", + "smithy.api#required": {} + } + }, + "per": { + "target": "com.turbopuffer.api#LimitPer", + "traits": { + "smithy.api#documentation": "Limits the number of documents with the same value for a set of attributes (the \"limit key\") that can appear in the results.\n" + } + } + }, + "traits": { + "smithy.api#documentation": "Limits the documents returned by a query." + } + }, + "com.turbopuffer.api#LimitPerAttributesList": { + "type": "list", + "member": { + "target": "smithy.api#String" + }, + "traits": { + "smithy.api#documentation": "The attributes to include in the limit key." + } + }, + "com.turbopuffer.api#LimitPer": { + "type": "structure", + "members": { + "attributes": { + "target": "com.turbopuffer.api#LimitPerAttributesList", + "traits": { + "smithy.api#documentation": "The attributes to include in the limit key.", + "smithy.api#required": {} + } + }, + "limit": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The maximum number of documents to return for each value of the limit key.\n", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "Limits the number of documents with the same value for a set of attributes (the \"limit key\") that can appear in the results.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestLimit": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Integer" + }, + "Limit": { + "target": "com.turbopuffer.api#Limit" + } + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceQueryRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "vector_encoding": { + "target": "smithy.api#Document" + }, + "consistency": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestConsistency", + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "rank_by": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "How to rank the documents in the namespace.\n" + } + }, + "top_k": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of results to return." + } + }, + "filters": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause.\n" + } + }, + "include_attributes": { + "target": "com.turbopuffer.api#IncludeAttributes" + }, + "exclude_attributes": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestExcludeAttributesList", + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "aggregate_by": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestAggregateByMap", + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "group_by": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestGroupByList", + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "compute_attributes": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestComputeAttributesMap", + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "distance_metric": { + "target": "smithy.api#Document" + }, + "limit": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestLimit" + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#CreateNamespaceQueryResponseAggregationsMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": {} + }, + "com.turbopuffer.api#AggregationGroup": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "A single aggregation group." + } + }, + "com.turbopuffer.api#CreateNamespaceQueryResponseAggregationGroupsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#AggregationGroup" + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceQueryResponseRowsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Row" + }, + "traits": {} + }, + "com.turbopuffer.api#QueryPerformance": { + "type": "structure", + "members": { + "cache_hit_ratio": { + "target": "smithy.api#Double", + "traits": { + "smithy.api#documentation": "The ratio of cache hits to total cache lookups.", + "smithy.api#required": {} + } + }, + "cache_temperature": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "A qualitative description of the cache hit ratio (`hot`, `warm`, or `cold`).", + "smithy.api#required": {} + } + }, + "server_total_ms": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Request time measured on the server, including time spent waiting for other queries to complete if the namespace was at its concurrency limit.\n", + "smithy.api#required": {} + } + }, + "query_execution_ms": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "Request time measured on the server, excluding time spent waiting due to the namespace concurrency limit.\n", + "smithy.api#required": {} + } + }, + "exhaustive_search_count": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of unindexed documents processed by the query.", + "smithy.api#required": {} + } + }, + "approx_namespace_size": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "the approximate number of documents in the namespace.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "The performance information for a query." + } + }, + "com.turbopuffer.api#CreateNamespaceQueryResponse": { + "type": "structure", + "members": { + "aggregations": { + "target": "com.turbopuffer.api#CreateNamespaceQueryResponseAggregationsMap" + }, + "aggregation_groups": { + "target": "com.turbopuffer.api#CreateNamespaceQueryResponseAggregationGroupsList" + }, + "rows": { + "target": "com.turbopuffer.api#CreateNamespaceQueryResponseRowsList" + }, + "performance": { + "target": "com.turbopuffer.api#QueryPerformance", + "traits": { + "smithy.api#required": {} + } + }, + "billing": { + "target": "com.turbopuffer.api#QueryBilling", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#CreateNamespaceQuery": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequest" + }, + "output": { + "target": "com.turbopuffer.api#CreateNamespaceQueryResponse" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}/query", + "code": 200 + }, + "smithy.api#documentation": "Query, filter, full-text search and vector search documents." + } + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestConsistency2": { + "type": "structure", + "members": { + "level": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The query's consistency level." + } + } + }, + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "com.turbopuffer.api#Query": { + "type": "structure", + "members": { + "rank_by": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "How to rank the documents in the namespace.\n" + } + }, + "top_k": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of results to return." + } + }, + "filters": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause.\n" + } + }, + "include_attributes": { + "target": "com.turbopuffer.api#IncludeAttributes" + }, + "exclude_attributes": { + "target": "com.turbopuffer.api#QueryExcludeAttributesList", + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "aggregate_by": { + "target": "com.turbopuffer.api#QueryAggregateByMap", + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "group_by": { + "target": "com.turbopuffer.api#QueryGroupByList", + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "compute_attributes": { + "target": "com.turbopuffer.api#QueryComputeAttributesMap", + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "distance_metric": { + "target": "smithy.api#Document" + }, + "limit": { + "target": "com.turbopuffer.api#QueryLimit" + } + }, + "traits": { + "smithy.api#documentation": "Query, filter, full-text search and vector search documents." + } + }, + "com.turbopuffer.api#QueryExcludeAttributesList": { + "type": "list", + "member": { + "target": "smithy.api#String" + }, + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "com.turbopuffer.api#QueryAggregateByMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "com.turbopuffer.api#QueryGroupByList": { + "type": "list", + "member": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "com.turbopuffer.api#QueryComputeAttributesMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "com.turbopuffer.api#QueryLimit": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Integer" + }, + "Limit": { + "target": "com.turbopuffer.api#Limit" + } + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceQueryRequestQueriesList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Query" + }, + "traits": {} + }, + "com.turbopuffer.api#RerankLimit": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Integer" + }, + "Case1": { + "target": "com.turbopuffer.api#RerankLimitCase1" + } + }, + "traits": {} + }, + "com.turbopuffer.api#RerankLimitCase1": { + "type": "structure", + "members": { + "total": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceQueryRequest2": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "vector_encoding": { + "target": "smithy.api#Document" + }, + "consistency": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestConsistency2", + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "queries": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequestQueriesList", + "traits": { + "smithy.api#required": {} + } + }, + "rerank_by": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "How to combine the rows returned by each sub-query into a single ranked list.\n" + } + }, + "limit": { + "target": "com.turbopuffer.api#RerankLimit", + "traits": { + "smithy.api#documentation": "Limits the total number of reranked documents returned." + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#MultiQueryResult": { + "type": "structure", + "members": { + "results": { + "target": "com.turbopuffer.api#MultiQueryResultResultsList", + "traits": { + "smithy.api#required": {} + } + }, + "performance": { + "target": "com.turbopuffer.api#QueryPerformance", + "traits": { + "smithy.api#required": {} + } + }, + "billing": { + "target": "com.turbopuffer.api#QueryBilling", + "traits": { + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "The result of a multi-query." + } + }, + "com.turbopuffer.api#SingleQueryResult": { + "type": "structure", + "members": { + "aggregations": { + "target": "com.turbopuffer.api#SingleQueryResultAggregationsMap" + }, + "aggregation_groups": { + "target": "com.turbopuffer.api#SingleQueryResultAggregationGroupsList" + }, + "rows": { + "target": "com.turbopuffer.api#SingleQueryResultRowsList" + } + }, + "traits": {} + }, + "com.turbopuffer.api#SingleQueryResultAggregationsMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": {} + }, + "com.turbopuffer.api#SingleQueryResultAggregationGroupsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#AggregationGroup" + }, + "traits": {} + }, + "com.turbopuffer.api#SingleQueryResultRowsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#Row" + }, + "traits": {} + }, + "com.turbopuffer.api#MultiQueryResultResultsList": { + "type": "list", + "member": { + "target": "com.turbopuffer.api#SingleQueryResult" + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceQuery2": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#CreateNamespaceQueryRequest2" + }, + "output": { + "target": "com.turbopuffer.api#MultiQueryResult" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}/query", + "code": 200 + }, + "smithy.api#documentation": "Issue multiple concurrent queries filter or search documents." + } + }, + "com.turbopuffer.api#UpdateNamespaceByNamespaceRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "source_namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The namespace to create an instant, copy-on-write clone of.", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#UpdateNamespaceByNamespace": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#UpdateNamespaceByNamespaceRequest" + }, + "output": { + "target": "com.turbopuffer.api#WriteResult" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}", + "code": 200 + }, + "smithy.api#documentation": "Creates an instant, copy-on-write clone of a namespace." + } + }, + "com.turbopuffer.api#UpdateNamespaceByNamespaceRequest2": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "source_namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The namespace to copy documents from.", + "smithy.api#required": {} + } + }, + "source_api_key": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "(Optional) An API key for the organization containing the source namespace" + } + }, + "source_region": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "(Optional) The region of the source namespace." + } + }, + "dest_encryption": { + "target": "com.turbopuffer.api#Encryption", + "traits": { + "smithy.api#documentation": "(Optional) The encryption configuration for the destination namespace.\n" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#UpdateNamespaceByNamespace2": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#UpdateNamespaceByNamespaceRequest2" + }, + "output": { + "target": "com.turbopuffer.api#WriteResult" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}", + "code": 200 + }, + "smithy.api#documentation": "Copy all documents from another namespace into this one." + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestConsistency": { + "type": "structure", + "members": { + "level": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "The query's consistency level." + } + } + }, + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestExcludeAttributesList": { + "type": "list", + "member": { + "target": "smithy.api#String" + }, + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestAggregateByMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestGroupByList": { + "type": "list", + "member": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestComputeAttributesMap": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#Document" + }, + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequestLimit": { + "type": "union", + "members": { + "Case0": { + "target": "smithy.api#Integer" + }, + "Limit": { + "target": "com.turbopuffer.api#Limit" + } + }, + "traits": {} + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryRequest": { + "type": "structure", + "members": { + "namespace": { + "target": "smithy.api#String", + "traits": { + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.api#documentation": "The name of the namespace." + } + }, + "vector_encoding": { + "target": "smithy.api#Document" + }, + "consistency": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestConsistency", + "traits": { + "smithy.api#documentation": "The consistency level for a query." + } + }, + "rank_by": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "How to rank the documents in the namespace.\n" + } + }, + "top_k": { + "target": "smithy.api#Integer", + "traits": { + "smithy.api#documentation": "The number of results to return." + } + }, + "filters": { + "target": "smithy.api#Document", + "traits": { + "smithy.api#documentation": "Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause.\n" + } + }, + "include_attributes": { + "target": "com.turbopuffer.api#IncludeAttributes" + }, + "exclude_attributes": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestExcludeAttributesList", + "traits": { + "smithy.api#documentation": "List of attribute names to exclude from the response. All other attributes will be included in the response.\n" + } + }, + "aggregate_by": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestAggregateByMap", + "traits": { + "smithy.api#documentation": "Aggregations to compute over all documents in the namespace that match the filters.\n" + } + }, + "group_by": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestGroupByList", + "traits": { + "smithy.api#documentation": "Groups documents by the specified attributes (the \"group key\") before computing aggregates. Aggregates are computed separately for each group.\n" + } + }, + "compute_attributes": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestComputeAttributesMap", + "traits": { + "smithy.api#documentation": "Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it.\n" + } + }, + "distance_metric": { + "target": "smithy.api#Document" + }, + "limit": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequestLimit" + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQueryResponse": { + "type": "structure", + "members": { + "plan_text": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "The textual representation of the query plan." + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.turbopuffer.api#CreateNamespaceExplainQuery": { + "type": "operation", + "input": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryRequest" + }, + "output": { + "target": "com.turbopuffer.api#CreateNamespaceExplainQueryResponse" + }, + "traits": { + "smithy.api#http": { + "method": "POST", + "uri": "/v2/namespaces/{namespace}/explain_query", + "code": 200 + }, + "smithy.api#documentation": "Explain a query plan." + } + }, + "com.turbopuffer.api#Turbopuffer": { + "type": "service", + "version": "0.0.1", + "operations": [ + { + "target": "com.turbopuffer.api#ListNamespaces" + }, + { + "target": "com.turbopuffer.api#GetNamespaceSchema" + }, + { + "target": "com.turbopuffer.api#CreateNamespaceSchema" + }, + { + "target": "com.turbopuffer.api#GetNamespaceMetadata" + }, + { + "target": "com.turbopuffer.api#UpdateNamespaceMetadata" + }, + { + "target": "com.turbopuffer.api#GetNamespaceHintCacheWarm" + }, + { + "target": "com.turbopuffer.api#CreateNamespaceDebugRecall" + }, + { + "target": "com.turbopuffer.api#UpdateNamespace" + }, + { + "target": "com.turbopuffer.api#DeleteNamespace" + }, + { + "target": "com.turbopuffer.api#CreateNamespaceQuery" + }, + { + "target": "com.turbopuffer.api#CreateNamespaceQuery2" + }, + { + "target": "com.turbopuffer.api#UpdateNamespaceByNamespace" + }, + { + "target": "com.turbopuffer.api#UpdateNamespaceByNamespace2" + }, + { + "target": "com.turbopuffer.api#CreateNamespaceExplainQuery" + } + ], + "traits": { + "smithy.api#title": "turbopuffer API", + "smithy.api#documentation": "turbopuffer is a fast search engine that combines vector and full-text search using object storage." + } + } + } +} diff --git a/packages/turbopuffer/package.json b/packages/turbopuffer/package.json new file mode 100644 index 000000000..f183c1114 --- /dev/null +++ b/packages/turbopuffer/package.json @@ -0,0 +1,85 @@ +{ + "name": "@distilled.cloud/turbopuffer", + "version": "1.0.0-rc.8", + "repository": { + "type": "git", + "url": "https://github.com/alchemy-run/distilled", + "directory": "packages/turbopuffer" + }, + "license": "Apache-2.0", + "type": "module", + "sideEffects": false, + "files": [ + "lib", + "src" + ], + "exports": { + ".": { + "types": "./lib/index.d.ts", + "bun": "./src/index.ts", + "worker": "./src/index.ts", + "default": "./lib/index.js" + }, + "./Credentials": { + "types": "./lib/credentials.d.ts", + "bun": "./src/credentials.ts", + "worker": "./src/credentials.ts", + "default": "./lib/credentials.js" + }, + "./Errors": { + "types": "./lib/errors.d.ts", + "bun": "./src/errors.ts", + "worker": "./src/errors.ts", + "default": "./lib/errors.js" + }, + "./Traits": { + "types": "./lib/traits.d.ts", + "bun": "./src/traits.ts", + "worker": "./src/traits.ts", + "default": "./lib/traits.js" + }, + "./Pagination": { + "types": "./lib/pagination.d.ts", + "bun": "./src/pagination.ts", + "worker": "./src/pagination.ts", + "default": "./lib/pagination.js" + }, + "./Protocol": { + "types": "./lib/protocol.d.ts", + "bun": "./src/protocol.ts", + "worker": "./src/protocol.ts", + "default": "./lib/protocol.js" + }, + "./Retry": { + "types": "./lib/retry.d.ts", + "bun": "./src/retry.ts", + "worker": "./src/retry.ts", + "default": "./lib/retry.js" + }, + "./*": { + "types": "./lib/services/*.d.ts", + "bun": "./src/services/*.ts", + "worker": "./src/services/*.ts", + "default": "./lib/services/*.js" + } + }, + "scripts": { + "build": "tsc -b", + "convert": "bun scripts/convert.ts", + "generate": "bun scripts/convert.ts && bun scripts/generate.ts", + "typecheck": "tsc -p tsconfig.json", + "specs:fetch": "git submodule update --force --init --depth=1 specs/spec-mirror-turbopuffer", + "specs:update": "git submodule update --remote --force --depth=1 specs/spec-mirror-turbopuffer" + }, + "dependencies": { + "@distilled.cloud/core": "workspace:*" + }, + "devDependencies": { + "@types/bun": "catalog:tooling", + "@types/node": "catalog:tooling", + "@effect/platform-bun": "catalog:effect" + }, + "peerDependencies": { + "effect": "catalog:effect" + } +} diff --git a/packages/turbopuffer/scripts/convert.ts b/packages/turbopuffer/scripts/convert.ts new file mode 100644 index 000000000..0b6a0a31b --- /dev/null +++ b/packages/turbopuffer/scripts/convert.ts @@ -0,0 +1,34 @@ +#!/usr/bin/env bun +/** + * convert — turn the turbopuffer OpenAPI spec into a Smithy 2.0 JSON model. + * + * Input: specs/spec-mirror-turbopuffer/specs/openapi.json (spec submodule) + * patches/*.patch.json (RFC-6902 patches to the OpenAPI document) + * Output: .generated-specs/turbopuffer.json + * + * The OpenAPI→Smithy converter lives in + * `@distilled.cloud/core/codegen/openapi`; this script is turbopuffer's + * pipeline config. `scripts/generate.ts` compiles the model into src/services. + */ +import * as path from "node:path"; +import { runOpenApiConvert } from "@distilled.cloud/core/codegen/openapi-cli"; + +await runOpenApiConvert({ + root: path.resolve(import.meta.dir, ".."), + specs: [ + { + name: "turbopuffer", + specPath: "specs/spec-mirror-turbopuffer/specs/openapi.json", + }, + ], + // OpenAPI-document patches (flat patches/*.patch.json). The smithy-model + // patch chain in generate.ts is disabled (`patchesDir: false`). + patchesDir: "patches", + options: { + namespace: "com.turbopuffer.api", + serviceName: "Turbopuffer", + skipDeprecated: true, + // hint_cache_warm returns 202 Accepted. + successStatuses: ["200", "201", "202", "204"], + }, +}); diff --git a/packages/turbopuffer/scripts/generate.ts b/packages/turbopuffer/scripts/generate.ts new file mode 100644 index 000000000..dd66438b9 --- /dev/null +++ b/packages/turbopuffer/scripts/generate.ts @@ -0,0 +1,93 @@ +#!/usr/bin/env bun +/** + * generate — turn the Smithy JSON model in .generated-specs into the + * turbopuffer Effect SDK. + * + * Input: .generated-specs/turbopuffer.json (written by scripts/convert.ts) + * Output: src/services/turbopuffer.ts + src/services/index.ts + * + * The smithy→SDK compiler and CLI pipeline live in + * `@distilled.cloud/core/codegen`; this script is turbopuffer's provider spec. + * turbopuffer keeps the wire's snake_case member names on the TS surface, so + * no member renaming or wire dictionaries appear here. + */ +import type { SdkSpec } from "@distilled.cloud/core/codegen/generator"; +import { runGeneratorCli } from "@distilled.cloud/core/codegen/cli"; + +const NULLABLE_TRAIT = "com.distilled.openapi#nullable"; +const ERROR_MATCHERS_TRAIT = "com.distilled.openapi#errorMatchers"; +const RAW_RESPONSE_TRAIT = "com.distilled.openapi#rawResponse"; +const SENSITIVE_TRAIT = "smithy.api#sensitive"; + +/** turbopuffer's provider spec for the shared smithy→SDK compiler. */ +const turbopufferSpec: SdkSpec = { + nullableTrait: NULLABLE_TRAIT, + errorMatchersTrait: ERROR_MATCHERS_TRAIT, + + extraBindings: [ + { + // Sole member of a synthesized wrapper for bare array/scalar response + // bodies; as the response's only member, the response IS the payload. + trait: RAW_RESPONSE_TRAIT, + binding: "rawResponse", + pipe: "T.RawResponse()", + rootPipe: "T.RawResponseRoot()", + }, + ], + + // Sensitive strings (API keys, encryption key names): the schema member + // carries T.SensitiveValue; the REST protocol delivers Redacted values + // and accepts string | Redacted on input. + memberTraitPipes: { + [SENSITIVE_TRAIT]: "T.SensitiveValue", + }, + memberTsType: (m) => + SENSITIVE_TRAIT in m.traits + ? `string | Redacted.Redacted${m.nullable ? " | null" : ""}` + : undefined, + + // Unions surface as TS type unions over an opaque schema — the REST + // protocol passes union content through verbatim (wire names ARE the TS + // names for turbopuffer), so no runtime case discrimination is needed. + union: ({ name, caseTargets, tsRef }) => [ + `export type ${name} = ${caseTargets.map(tsRef).join(" | ") || "unknown"};`, + `export const ${name} = /*@__PURE__*/ S.Unknown as any as S.Schema<${name}>;\n`, + ], + + // One pagination profile: cursor mode (inputToken `cursor`, outputToken + // `pagination.cursor`), traversed by core's paginateCursor. + paginationProfiles: { + cursor: { + strategy: "paginateCursor", + itemsFallback: "items", + }, + }, + + operationDecl: { + contextType: "TurbopufferOpContext", + commonErrorType: "TurbopufferOpError", + commonErrorClasses: ["UnknownTurbopufferError"], + protocol: "TurbopufferProtocol", + retry: "Retry.Retry", + }, + + sourceNote: ".generated-specs (specs/spec-mirror-turbopuffer)", + + // Sensitive member types reference Redacted; pull the import in when used. + postProcess: (code) => + code.includes("Redacted.Redacted<") + ? code.replace( + `import * as S from "@distilled.cloud/core/schema";\n`, + `import * as S from "@distilled.cloud/core/schema";\nimport * as Redacted from "effect/Redacted";\n`, + ) + : code, +}; + +runGeneratorCli({ + description: "Generate the turbopuffer Effect SDK from the Smithy model", + root: `${import.meta.dir}/..`, + // patches/ holds OpenAPI-document patches consumed by scripts/convert.ts; + // there is no smithy-model patch chain. + patchesDir: false, + spec: () => turbopufferSpec, +}); diff --git a/packages/turbopuffer/src/credentials.ts b/packages/turbopuffer/src/credentials.ts new file mode 100644 index 000000000..ac223ec53 --- /dev/null +++ b/packages/turbopuffer/src/credentials.ts @@ -0,0 +1,58 @@ +/** + * turbopuffer credentials — hand-written. + * + * API-compatible port of the distilled Neon credentials module: the + * `Credentials` service holds an *effect* that resolves the current + * credentials on every request (the protocol layer resolves it per request + * on the calling fiber). + */ +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import * as Redacted from "effect/Redacted"; +import { ConfigError } from "@distilled.cloud/core/errors"; + +/** Default public cluster used throughout turbopuffer's own docs. */ +export const DEFAULT_API_BASE_URL = "https://gcp-us-central1.turbopuffer.com"; + +export interface Config { + readonly apiKey: Redacted.Redacted; + readonly apiBaseUrl: string; +} + +export class Credentials extends Context.Service< + Credentials, + Effect.Effect +>()("TurbopufferCredentials") {} + +/** Layer from a plain API key + optional base URL. */ +export const fromApiKey = (config: { + readonly apiKey: string; + readonly apiBaseUrl?: string; +}): Layer.Layer => + Layer.succeed( + Credentials, + Effect.succeed({ + apiKey: Redacted.make(config.apiKey), + apiBaseUrl: config.apiBaseUrl ?? DEFAULT_API_BASE_URL, + }), + ); + +/** Reads TURBOPUFFER_API_KEY (required) and TURBOPUFFER_API_BASE_URL (optional). */ +export const CredentialsFromEnv: Layer.Layer = Layer.succeed( + Credentials, + Effect.gen(function* () { + const apiKey = process.env.TURBOPUFFER_API_KEY; + + if (!apiKey) { + return yield* new ConfigError({ + message: "TURBOPUFFER_API_KEY environment variable is required", + }); + } + + return { + apiKey: Redacted.make(apiKey), + apiBaseUrl: process.env.TURBOPUFFER_API_BASE_URL ?? DEFAULT_API_BASE_URL, + }; + }).pipe(Effect.orDie), +); diff --git a/packages/turbopuffer/src/errors.ts b/packages/turbopuffer/src/errors.ts new file mode 100644 index 000000000..22e6c8a1f --- /dev/null +++ b/packages/turbopuffer/src/errors.ts @@ -0,0 +1,50 @@ +/** + * turbopuffer-specific error types. + * + * Re-exports the common HTTP errors from core and adds the turbopuffer + * fallback errors. Note the generated service module additionally defines + * its own per-status matcher classes (BadRequest/NotFound/…) for the + * statuses each operation declares — those share `_tag`s with the core + * classes here, so `catchTag` works against either. + */ +export { + BadGateway, + BadRequest, + Conflict, + ConfigError, + Forbidden, + GatewayTimeout, + InternalServerError, + Locked, + NotFound, + ServiceUnavailable, + TooManyRequests, + Unauthorized, + UnprocessableEntity, + HTTP_STATUS_MAP, + DEFAULT_ERRORS, + API_ERRORS, +} from "@distilled.cloud/core/errors"; +export type { DefaultErrors } from "@distilled.cloud/core/errors"; + +import * as Schema from "effect/Schema"; +import * as Category from "@distilled.cloud/core/category"; + +/** Unknown turbopuffer error — returned when nothing else matches the failure. */ +export class UnknownTurbopufferError extends Schema.TaggedError()( + "UnknownTurbopufferError", + { + code: Schema.optional(Schema.String), + message: Schema.optional(Schema.String), + body: Schema.Unknown, + }, +).pipe(Category.withServerError) {} + +/** Schema parse error wrapper (kept for Neon-style surface parity). */ +export class TurbopufferParseError extends Schema.TaggedError()( + "TurbopufferParseError", + { + body: Schema.Unknown, + cause: Schema.Unknown, + }, +).pipe(Category.withParseError) {} diff --git a/packages/turbopuffer/src/index.ts b/packages/turbopuffer/src/index.ts new file mode 100644 index 000000000..7d12d80c6 --- /dev/null +++ b/packages/turbopuffer/src/index.ts @@ -0,0 +1,30 @@ +/** + * @distilled.cloud/turbopuffer — turbopuffer SDK for Effect. + * + * `./services` is generated by `scripts/generate.ts` from the Smithy model + * in `.generated-specs` (written by `scripts/convert.ts` from the OpenAPI + * spec). Everything else in this folder is hand-written. + * + * @example + * ```ts + * import * as Turbopuffer from "@distilled.cloud/turbopuffer"; + * + * const namespaces = yield* Turbopuffer.Services.turbopuffer.getV1Namespaces({}); + * ``` + */ +export * from "./credentials.ts"; +export * from "./errors.ts"; +export * as T from "./traits.ts"; +export { + TurbopufferProtocol, + type TurbopufferOpError, + type TurbopufferOpContext, +} from "./protocol.ts"; +export { paginateCursor } from "./pagination.ts"; +export * as Retry from "./retry.ts"; +export * as Services from "./services/index.ts"; +// Operations (and their request/response types) are importable straight off +// the package root. The service-local typed error classes shadow the +// same-named shared ones from ./errors.ts — the ops actually raise the +// service-local classes. +export * from "./services/turbopuffer.ts"; diff --git a/packages/turbopuffer/src/pagination.ts b/packages/turbopuffer/src/pagination.ts new file mode 100644 index 000000000..2b99e7e17 --- /dev/null +++ b/packages/turbopuffer/src/pagination.ts @@ -0,0 +1,8 @@ +/** + * turbopuffer pagination — hand-written. + * + * List-namespace operations are cursor-mode (`cursor` in, `next_cursor` + * out when the spec is annotated); generated operations pass core's + * {@link paginateCursor} strategy to `API.makePaginated`. + */ +export { paginateCursor } from "@distilled.cloud/core/pagination"; diff --git a/packages/turbopuffer/src/protocol.ts b/packages/turbopuffer/src/protocol.ts new file mode 100644 index 000000000..f61f99c06 --- /dev/null +++ b/packages/turbopuffer/src/protocol.ts @@ -0,0 +1,68 @@ +/** + * TurbopufferProtocol — hand-written. + * + * turbopuffer speaks plain bearer-authenticated JSON REST (no response + * envelope), so the whole protocol is one `makeRestProtocol` call from + * `core/protocol-rest`: + * + * request: credentials → `Authorization: Bearer ` + base URL + * (default https://gcp-us-central1.turbopuffer.com), resolved + * from the calling fiber on every request + * + * response: 2xx JSON is the payload (sensitive members delivered as + * `Redacted`); non-2xx `{ status: "error", error }` bodies map + * to the operation's typed error classes by status, then the + * shared HTTP-status classes, then {@link UnknownTurbopufferError}. + */ +import * as Effect from "effect/Effect"; +import type * as Layer from "effect/Layer"; +import * as Redacted from "effect/Redacted"; +import type * as HttpClient from "effect/unstable/http/HttpClient"; +import type * as HttpClientError from "effect/unstable/http/HttpClientError"; +import type * as API from "@distilled.cloud/core/api"; +import { makeRestProtocol } from "@distilled.cloud/core/protocol-rest"; +import type { API_ERRORS, ConfigError } from "@distilled.cloud/core/errors"; +import { Credentials, type Config } from "./credentials.ts"; +import { UnknownTurbopufferError } from "./errors.ts"; + +/** + * Error channel shared by every generated turbopuffer operation. Generated + * service files annotate operations with `API.OperationMethod` explicitly so the compiler never + * infers these back out of the schema generics. + */ +export type TurbopufferOpError = + | InstanceType<(typeof API_ERRORS)[number]> + | UnknownTurbopufferError + | ConfigError + | HttpClientError.HttpClientError; + +/** Context (requirements) shared by every generated turbopuffer operation. */ +export type TurbopufferOpContext = Credentials | HttpClient.HttpClient; + +export const TurbopufferProtocol: Layer.Layer = + makeRestProtocol({ + // The Credentials service holds an effect — resolving it here (per + // request, on the calling fiber) picks up context-provided credentials. + credentials: Effect.gen(function* () { + const resolve = yield* Credentials; + return yield* resolve; + }), + baseUrl: (creds) => creds.apiBaseUrl, + headers: (creds) => ({ + Authorization: `Bearer ${Redacted.value(creds.apiKey)}`, + }), + // turbopuffer's error body is `{ status: "error", error: string }` — the + // factory's default lenient envelope maps `error` → `message`. + unknownError: ({ code, message, body }) => + new UnknownTurbopufferError({ + code: + typeof code === "string" + ? code + : code !== undefined + ? String(code) + : undefined, + message, + body, + }), + }); diff --git a/packages/turbopuffer/src/retry.ts b/packages/turbopuffer/src/retry.ts new file mode 100644 index 000000000..0d37da293 --- /dev/null +++ b/packages/turbopuffer/src/retry.ts @@ -0,0 +1,56 @@ +/** + * turbopuffer retry configuration. + * + * Defines the per-SDK `Retry` Context.Service tag that generated operations + * wire into `API.make`. Callers can install a blanket retry policy at the + * layer level and have every turbopuffer API call below it pick it up: + * + * @example + * ```ts + * import * as Turbopuffer from "@distilled.cloud/turbopuffer"; + * + * myEffect.pipe(Turbopuffer.Retry.transient); + * Effect.provide(myEffect, Layer.succeed(Turbopuffer.Retry.Retry, customPolicy)); + * ``` + */ +import * as Context from "effect/Context"; +import * as Effect from "effect/Effect"; +import * as Layer from "effect/Layer"; +import { + type Policy, + throttlingFactory, + transientFactory, +} from "@distilled.cloud/core/retry"; + +export { + type Options, + type Factory, + type Policy, + makeDefault, + jittered, + capped, + throttlingOptions, + transientOptions, + throttlingFactory, + transientFactory, +} from "@distilled.cloud/core/retry"; + +/** Context tag for configuring retry behavior of turbopuffer API calls. */ +export class Retry extends Context.Service()( + "TurbopufferRetry", +) {} + +/** Provides a custom retry policy to every turbopuffer API call below it. */ +export const policy = (optionsOrFactory: Policy) => + Effect.provide(Layer.succeed(Retry, optionsOrFactory)); + +/** Disables all automatic retries. */ +export const none = Effect.provide( + Layer.succeed(Retry, { while: () => false }), +); + +/** Apply the throttling retry policy (retries throttling errors indefinitely). */ +export const throttling = policy(throttlingFactory); + +/** Apply the transient retry policy (retries all transient errors indefinitely). */ +export const transient = policy(transientFactory); diff --git a/packages/turbopuffer/src/services/index.ts b/packages/turbopuffer/src/services/index.ts new file mode 100644 index 000000000..2a193770d --- /dev/null +++ b/packages/turbopuffer/src/services/index.ts @@ -0,0 +1,2 @@ +// AUTO-GENERATED by scripts/generate.ts. Do not edit. +export * as turbopuffer from "./turbopuffer.ts"; diff --git a/packages/turbopuffer/src/services/turbopuffer.ts b/packages/turbopuffer/src/services/turbopuffer.ts new file mode 100644 index 000000000..3bc0820fe --- /dev/null +++ b/packages/turbopuffer/src/services/turbopuffer.ts @@ -0,0 +1,1695 @@ +// AUTO-GENERATED by scripts/generate.ts from .generated-specs (specs/spec-mirror-turbopuffer). Do not edit. +import * as S from "@distilled.cloud/core/schema"; +import * as API from "@distilled.cloud/core/api"; +import * as T from "../traits.ts"; +import { + TurbopufferProtocol, + type TurbopufferOpError, + type TurbopufferOpContext, +} from "../protocol.ts"; +import { UnknownTurbopufferError } from "../errors.ts"; +import * as Retry from "../retry.ts"; + +export type { TurbopufferOpError, TurbopufferOpContext }; + +export interface CreateNamespaceDebugRecallRequest { + /** The name of the namespace. */ + namespace: string; + /** The number of searches to run. */ + num?: number; + /** Search for `top_k` nearest neighbors. */ + top_k?: number; + /** Filter by attributes. Same syntax as the query endpoint. */ + filters?: unknown; + /** Include ground truth data (query vectors and true nearest neighbors) in the response. */ + include_ground_truth?: boolean; + /** The ranking function to evaluate recall for. If provided, `num` must be either null or 1. */ + rank_by?: unknown; +} +export const CreateNamespaceDebugRecallRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + num: S.optional(S.Number), + top_k: S.optional(S.Number), + filters: S.optional(S.Unknown), + include_ground_truth: S.optional(S.Boolean), + rank_by: S.optional(S.Unknown), + }).pipe( + T.Http({ + method: "POST", + uri: "/v1/namespaces/{namespace}/_debug/recall", + code: 200, + }), + ), +).annotate({ + identifier: "CreateNamespaceDebugRecallRequest", +}) as any as S.Schema; + +/** The query vector used for this search. */ +export type CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList = + Array; +export const CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList = + /*@__PURE__*/ S.Array( + S.Number, + ) as any as S.Schema; + +/** An identifier for a document. */ +export type Id = string | number; +export const Id = /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** A dense vector encoded as an array of floats. */ +export type VectorCase0List = Array; +export const VectorCase0List = /*@__PURE__*/ S.Array( + S.Number, +) as any as S.Schema; + +/** A vector embedding associated with a document. */ +export type Vector = VectorCase0List | string; +export const Vector = /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** A single document, in a row-based format. */ +export interface Row { + id: Id; + vector?: Vector; +} +export const Row = /*@__PURE__*/ S.suspend(() => + S.Struct({ + id: Id, + vector: S.optional(Vector), + }), +).annotate({ identifier: "Row" }) as any as S.Schema; + +/** The true nearest neighbors with their distances and vectors. */ +export type CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList = + Array; +export const CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList = + /*@__PURE__*/ S.Array( + Row, + ) as any as S.Schema; + +export interface CreateNamespaceDebugRecallResponseGroundTruthItem { + /** The query vector used for this search. */ + query_vector: CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList; + /** The true nearest neighbors with their distances and vectors. */ + nearest_neighbors: CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList; +} +export const CreateNamespaceDebugRecallResponseGroundTruthItem = + /*@__PURE__*/ S.suspend(() => + S.Struct({ + query_vector: + CreateNamespaceDebugRecallResponseGroundTruthItemQueryVectorList, + nearest_neighbors: + CreateNamespaceDebugRecallResponseGroundTruthItemNearestNeighborsList, + }), + ).annotate({ + identifier: "CreateNamespaceDebugRecallResponseGroundTruthItem", + }) as any as S.Schema; + +/** Ground truth data including query vectors and true nearest neighbors. Only included when include_ground_truth is true. */ +export type CreateNamespaceDebugRecallResponseGroundTruthList = + Array; +export const CreateNamespaceDebugRecallResponseGroundTruthList = + /*@__PURE__*/ S.Array( + CreateNamespaceDebugRecallResponseGroundTruthItem, + ) as any as S.Schema; + +export interface CreateNamespaceDebugRecallResponse { + /** The average recall of the queries. */ + avg_recall: number; + /** The average number of documents retrieved by the exhaustive searches. */ + avg_exhaustive_count: number; + /** The average number of documents retrieved by the approximate nearest neighbor searches. */ + avg_ann_count: number; + /** Ground truth data including query vectors and true nearest neighbors. Only included when include_ground_truth is true. */ + ground_truth?: CreateNamespaceDebugRecallResponseGroundTruthList; +} +export const CreateNamespaceDebugRecallResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + avg_recall: S.Number, + avg_exhaustive_count: S.Number, + avg_ann_count: S.Number, + ground_truth: S.optional(CreateNamespaceDebugRecallResponseGroundTruthList), + }), +).annotate({ + identifier: "CreateNamespaceDebugRecallResponse", +}) as any as S.Schema; + +/** The consistency level for a query. */ +export interface CreateNamespaceExplainQueryRequestConsistency { + /** The query's consistency level. */ + level?: unknown; +} +export const CreateNamespaceExplainQueryRequestConsistency = + /*@__PURE__*/ S.suspend(() => + S.Struct({ + level: S.optional(S.Unknown), + }), + ).annotate({ + identifier: "CreateNamespaceExplainQueryRequestConsistency", + }) as any as S.Schema; + +/** Include exactly the specified attributes in the response. */ +export type IncludeAttributesCase1List = Array; +export const IncludeAttributesCase1List = /*@__PURE__*/ S.Array( + S.String, +) as any as S.Schema; + +/** Whether to include attributes in the response. */ +export type IncludeAttributes = boolean | IncludeAttributesCase1List; +export const IncludeAttributes = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** List of attribute names to exclude from the response. All other attributes will be included in the response. */ +export type CreateNamespaceExplainQueryRequestExcludeAttributesList = + Array; +export const CreateNamespaceExplainQueryRequestExcludeAttributesList = + /*@__PURE__*/ S.Array( + S.String, + ) as any as S.Schema; + +/** Aggregations to compute over all documents in the namespace that match the filters. */ +export type CreateNamespaceExplainQueryRequestAggregateByMap = { + [key: string]: unknown | undefined; +}; +export const CreateNamespaceExplainQueryRequestAggregateByMap = + /*@__PURE__*/ S.Record( + S.String, + S.Unknown, + ) as any as S.Schema; + +/** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ +export type CreateNamespaceExplainQueryRequestGroupByList = Array; +export const CreateNamespaceExplainQueryRequestGroupByList = + /*@__PURE__*/ S.Array( + S.Unknown, + ) as any as S.Schema; + +/** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ +export type CreateNamespaceExplainQueryRequestComputeAttributesMap = { + [key: string]: unknown | undefined; +}; +export const CreateNamespaceExplainQueryRequestComputeAttributesMap = + /*@__PURE__*/ S.Record( + S.String, + S.Unknown, + ) as any as S.Schema; + +/** The attributes to include in the limit key. */ +export type LimitPerAttributesList = Array; +export const LimitPerAttributesList = /*@__PURE__*/ S.Array( + S.String, +) as any as S.Schema; + +/** Limits the number of documents with the same value for a set of attributes (the "limit key") that can appear in the results. */ +export interface LimitPer { + /** The attributes to include in the limit key. */ + attributes: LimitPerAttributesList; + /** The maximum number of documents to return for each value of the limit key. */ + limit: number; +} +export const LimitPer = /*@__PURE__*/ S.suspend(() => + S.Struct({ + attributes: LimitPerAttributesList, + limit: S.Number, + }), +).annotate({ identifier: "LimitPer" }) as any as S.Schema; + +/** Limits the documents returned by a query. */ +export interface Limit { + /** Limits the total number of documents returned. */ + total: number; + /** Limits the number of documents with the same value for a set of attributes (the "limit key") that can appear in the results. */ + per?: LimitPer; +} +export const Limit = /*@__PURE__*/ S.suspend(() => + S.Struct({ + total: S.Number, + per: S.optional(LimitPer), + }), +).annotate({ identifier: "Limit" }) as any as S.Schema; + +export type CreateNamespaceExplainQueryRequestLimit = number | Limit; +export const CreateNamespaceExplainQueryRequestLimit = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface CreateNamespaceExplainQueryRequest { + /** The name of the namespace. */ + namespace: string; + vector_encoding?: unknown; + /** The consistency level for a query. */ + consistency?: CreateNamespaceExplainQueryRequestConsistency; + /** How to rank the documents in the namespace. */ + rank_by?: unknown; + /** The number of results to return. */ + top_k?: number; + /** Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause. */ + filters?: unknown; + include_attributes?: IncludeAttributes; + /** List of attribute names to exclude from the response. All other attributes will be included in the response. */ + exclude_attributes?: CreateNamespaceExplainQueryRequestExcludeAttributesList; + /** Aggregations to compute over all documents in the namespace that match the filters. */ + aggregate_by?: CreateNamespaceExplainQueryRequestAggregateByMap; + /** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ + group_by?: CreateNamespaceExplainQueryRequestGroupByList; + /** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ + compute_attributes?: CreateNamespaceExplainQueryRequestComputeAttributesMap; + distance_metric?: unknown; + limit?: CreateNamespaceExplainQueryRequestLimit; +} +export const CreateNamespaceExplainQueryRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + vector_encoding: S.optional(S.Unknown), + consistency: S.optional(CreateNamespaceExplainQueryRequestConsistency), + rank_by: S.optional(S.Unknown), + top_k: S.optional(S.Number), + filters: S.optional(S.Unknown), + include_attributes: S.optional(IncludeAttributes), + exclude_attributes: S.optional( + CreateNamespaceExplainQueryRequestExcludeAttributesList, + ), + aggregate_by: S.optional(CreateNamespaceExplainQueryRequestAggregateByMap), + group_by: S.optional(CreateNamespaceExplainQueryRequestGroupByList), + compute_attributes: S.optional( + CreateNamespaceExplainQueryRequestComputeAttributesMap, + ), + distance_metric: S.optional(S.Unknown), + limit: S.optional(CreateNamespaceExplainQueryRequestLimit), + }).pipe( + T.Http({ + method: "POST", + uri: "/v2/namespaces/{namespace}/explain_query", + code: 200, + }), + ), +).annotate({ + identifier: "CreateNamespaceExplainQueryRequest", +}) as any as S.Schema; + +export interface CreateNamespaceExplainQueryResponse { + /** The textual representation of the query plan. */ + plan_text?: string; +} +export const CreateNamespaceExplainQueryResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + plan_text: S.optional(S.String), + }), +).annotate({ + identifier: "CreateNamespaceExplainQueryResponse", +}) as any as S.Schema; + +/** The consistency level for a query. */ +export type CreateNamespaceQueryRequestConsistency = + CreateNamespaceExplainQueryRequestConsistency; +export const CreateNamespaceQueryRequestConsistency = + CreateNamespaceExplainQueryRequestConsistency; + +/** List of attribute names to exclude from the response. All other attributes will be included in the response. */ +export type CreateNamespaceQueryRequestExcludeAttributesList = Array; +export const CreateNamespaceQueryRequestExcludeAttributesList = + /*@__PURE__*/ S.Array( + S.String, + ) as any as S.Schema; + +/** Aggregations to compute over all documents in the namespace that match the filters. */ +export type CreateNamespaceQueryRequestAggregateByMap = { + [key: string]: unknown | undefined; +}; +export const CreateNamespaceQueryRequestAggregateByMap = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +/** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ +export type CreateNamespaceQueryRequestGroupByList = Array; +export const CreateNamespaceQueryRequestGroupByList = /*@__PURE__*/ S.Array( + S.Unknown, +) as any as S.Schema; + +/** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ +export type CreateNamespaceQueryRequestComputeAttributesMap = { + [key: string]: unknown | undefined; +}; +export const CreateNamespaceQueryRequestComputeAttributesMap = + /*@__PURE__*/ S.Record( + S.String, + S.Unknown, + ) as any as S.Schema; + +export type CreateNamespaceQueryRequestLimit = number | Limit; +export const CreateNamespaceQueryRequestLimit = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface CreateNamespaceQueryRequest { + /** The name of the namespace. */ + namespace: string; + vector_encoding?: unknown; + /** The consistency level for a query. */ + consistency?: CreateNamespaceExplainQueryRequestConsistency; + /** How to rank the documents in the namespace. */ + rank_by?: unknown; + /** The number of results to return. */ + top_k?: number; + /** Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause. */ + filters?: unknown; + include_attributes?: IncludeAttributes; + /** List of attribute names to exclude from the response. All other attributes will be included in the response. */ + exclude_attributes?: CreateNamespaceQueryRequestExcludeAttributesList; + /** Aggregations to compute over all documents in the namespace that match the filters. */ + aggregate_by?: CreateNamespaceQueryRequestAggregateByMap; + /** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ + group_by?: CreateNamespaceQueryRequestGroupByList; + /** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ + compute_attributes?: CreateNamespaceQueryRequestComputeAttributesMap; + distance_metric?: unknown; + limit?: CreateNamespaceQueryRequestLimit; +} +export const CreateNamespaceQueryRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + vector_encoding: S.optional(S.Unknown), + consistency: S.optional(CreateNamespaceExplainQueryRequestConsistency), + rank_by: S.optional(S.Unknown), + top_k: S.optional(S.Number), + filters: S.optional(S.Unknown), + include_attributes: S.optional(IncludeAttributes), + exclude_attributes: S.optional( + CreateNamespaceQueryRequestExcludeAttributesList, + ), + aggregate_by: S.optional(CreateNamespaceQueryRequestAggregateByMap), + group_by: S.optional(CreateNamespaceQueryRequestGroupByList), + compute_attributes: S.optional( + CreateNamespaceQueryRequestComputeAttributesMap, + ), + distance_metric: S.optional(S.Unknown), + limit: S.optional(CreateNamespaceQueryRequestLimit), + }).pipe( + T.Http({ + method: "POST", + uri: "/v2/namespaces/{namespace}/query", + code: 200, + }), + ), +).annotate({ + identifier: "CreateNamespaceQueryRequest", +}) as any as S.Schema; + +export type CreateNamespaceQueryResponseAggregationsMap = { + [key: string]: unknown | undefined; +}; +export const CreateNamespaceQueryResponseAggregationsMap = + /*@__PURE__*/ S.Record( + S.String, + S.Unknown, + ) as any as S.Schema; + +/** A single aggregation group. */ +export type AggregationGroup = { [key: string]: unknown | undefined }; +export const AggregationGroup = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +export type CreateNamespaceQueryResponseAggregationGroupsList = + Array; +export const CreateNamespaceQueryResponseAggregationGroupsList = + /*@__PURE__*/ S.Array( + AggregationGroup, + ) as any as S.Schema; + +export type CreateNamespaceQueryResponseRowsList = Array; +export const CreateNamespaceQueryResponseRowsList = /*@__PURE__*/ S.Array( + Row, +) as any as S.Schema; + +/** The performance information for a query. */ +export interface QueryPerformance { + /** The ratio of cache hits to total cache lookups. */ + cache_hit_ratio: number; + /** A qualitative description of the cache hit ratio (`hot`, `warm`, or `cold`). */ + cache_temperature: string; + /** Request time measured on the server, including time spent waiting for other queries to complete if the namespace was at its concurrency limit. */ + server_total_ms: number; + /** Request time measured on the server, excluding time spent waiting due to the namespace concurrency limit. */ + query_execution_ms: number; + /** The number of unindexed documents processed by the query. */ + exhaustive_search_count: number; + /** the approximate number of documents in the namespace. */ + approx_namespace_size: number; +} +export const QueryPerformance = /*@__PURE__*/ S.suspend(() => + S.Struct({ + cache_hit_ratio: S.Number, + cache_temperature: S.String, + server_total_ms: S.Number, + query_execution_ms: S.Number, + exhaustive_search_count: S.Number, + approx_namespace_size: S.Number, + }), +).annotate({ + identifier: "QueryPerformance", +}) as any as S.Schema; + +/** The billing information for a query. */ +export interface QueryBilling { + /** The number of billable logical bytes queried from the namespace. */ + billable_logical_bytes_queried: number; + /** The number of billable logical bytes returned from the query. */ + billable_logical_bytes_returned: number; +} +export const QueryBilling = /*@__PURE__*/ S.suspend(() => + S.Struct({ + billable_logical_bytes_queried: S.Number, + billable_logical_bytes_returned: S.Number, + }), +).annotate({ identifier: "QueryBilling" }) as any as S.Schema; + +export interface CreateNamespaceQueryResponse { + aggregations?: CreateNamespaceQueryResponseAggregationsMap; + aggregation_groups?: CreateNamespaceQueryResponseAggregationGroupsList; + rows?: CreateNamespaceQueryResponseRowsList; + performance: QueryPerformance; + billing: QueryBilling; +} +export const CreateNamespaceQueryResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + aggregations: S.optional(CreateNamespaceQueryResponseAggregationsMap), + aggregation_groups: S.optional( + CreateNamespaceQueryResponseAggregationGroupsList, + ), + rows: S.optional(CreateNamespaceQueryResponseRowsList), + performance: QueryPerformance, + billing: QueryBilling, + }), +).annotate({ + identifier: "CreateNamespaceQueryResponse", +}) as any as S.Schema; + +/** The consistency level for a query. */ +export type CreateNamespaceQueryRequestConsistency2 = + CreateNamespaceExplainQueryRequestConsistency; +export const CreateNamespaceQueryRequestConsistency2 = + CreateNamespaceExplainQueryRequestConsistency; + +/** List of attribute names to exclude from the response. All other attributes will be included in the response. */ +export type QueryExcludeAttributesList = Array; +export const QueryExcludeAttributesList = /*@__PURE__*/ S.Array( + S.String, +) as any as S.Schema; + +/** Aggregations to compute over all documents in the namespace that match the filters. */ +export type QueryAggregateByMap = { [key: string]: unknown | undefined }; +export const QueryAggregateByMap = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +/** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ +export type QueryGroupByList = Array; +export const QueryGroupByList = /*@__PURE__*/ S.Array( + S.Unknown, +) as any as S.Schema; + +/** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ +export type QueryComputeAttributesMap = { [key: string]: unknown | undefined }; +export const QueryComputeAttributesMap = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +export type QueryLimit = number | Limit; +export const QueryLimit = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** Query, filter, full-text search and vector search documents. */ +export interface Query { + /** How to rank the documents in the namespace. */ + rank_by?: unknown; + /** The number of results to return. */ + top_k?: number; + /** Exact filters for attributes to refine search results for. Think of it as a SQL WHERE clause. */ + filters?: unknown; + include_attributes?: IncludeAttributes; + /** List of attribute names to exclude from the response. All other attributes will be included in the response. */ + exclude_attributes?: QueryExcludeAttributesList; + /** Aggregations to compute over all documents in the namespace that match the filters. */ + aggregate_by?: QueryAggregateByMap; + /** Groups documents by the specified attributes (the "group key") before computing aggregates. Aggregates are computed separately for each group. */ + group_by?: QueryGroupByList; + /** Computes additional values on documents returned by a query. Each key is the name of the computed attribute; each value is an expression describing how to compute it. */ + compute_attributes?: QueryComputeAttributesMap; + distance_metric?: unknown; + limit?: QueryLimit; +} +export const Query = /*@__PURE__*/ S.suspend(() => + S.Struct({ + rank_by: S.optional(S.Unknown), + top_k: S.optional(S.Number), + filters: S.optional(S.Unknown), + include_attributes: S.optional(IncludeAttributes), + exclude_attributes: S.optional(QueryExcludeAttributesList), + aggregate_by: S.optional(QueryAggregateByMap), + group_by: S.optional(QueryGroupByList), + compute_attributes: S.optional(QueryComputeAttributesMap), + distance_metric: S.optional(S.Unknown), + limit: S.optional(QueryLimit), + }), +).annotate({ identifier: "Query" }) as any as S.Schema; + +export type CreateNamespaceQueryRequestQueriesList = Array; +export const CreateNamespaceQueryRequestQueriesList = /*@__PURE__*/ S.Array( + Query, +) as any as S.Schema; + +export interface RerankLimitCase1 { + total: number; +} +export const RerankLimitCase1 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + total: S.Number, + }), +).annotate({ + identifier: "RerankLimitCase1", +}) as any as S.Schema; + +export type RerankLimit = number | RerankLimitCase1; +export const RerankLimit = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface CreateNamespaceQueryRequest2 { + /** The name of the namespace. */ + namespace: string; + vector_encoding?: unknown; + /** The consistency level for a query. */ + consistency?: CreateNamespaceExplainQueryRequestConsistency; + queries: CreateNamespaceQueryRequestQueriesList; + /** How to combine the rows returned by each sub-query into a single ranked list. */ + rerank_by?: unknown; + /** Limits the total number of reranked documents returned. */ + limit?: RerankLimit; +} +export const CreateNamespaceQueryRequest2 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + vector_encoding: S.optional(S.Unknown), + consistency: S.optional(CreateNamespaceExplainQueryRequestConsistency), + queries: CreateNamespaceQueryRequestQueriesList, + rerank_by: S.optional(S.Unknown), + limit: S.optional(RerankLimit), + }).pipe( + T.Http({ + method: "POST", + uri: "/v2/namespaces/{namespace}/query", + code: 200, + }), + ), +).annotate({ + identifier: "CreateNamespaceQueryRequest2", +}) as any as S.Schema; + +export type SingleQueryResultAggregationsMap = { + [key: string]: unknown | undefined; +}; +export const SingleQueryResultAggregationsMap = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +export type SingleQueryResultAggregationGroupsList = Array; +export const SingleQueryResultAggregationGroupsList = /*@__PURE__*/ S.Array( + AggregationGroup, +) as any as S.Schema; + +export type SingleQueryResultRowsList = Array; +export const SingleQueryResultRowsList = /*@__PURE__*/ S.Array( + Row, +) as any as S.Schema; + +export interface SingleQueryResult { + aggregations?: SingleQueryResultAggregationsMap; + aggregation_groups?: SingleQueryResultAggregationGroupsList; + rows?: SingleQueryResultRowsList; +} +export const SingleQueryResult = /*@__PURE__*/ S.suspend(() => + S.Struct({ + aggregations: S.optional(SingleQueryResultAggregationsMap), + aggregation_groups: S.optional(SingleQueryResultAggregationGroupsList), + rows: S.optional(SingleQueryResultRowsList), + }), +).annotate({ + identifier: "SingleQueryResult", +}) as any as S.Schema; + +export type MultiQueryResultResultsList = Array; +export const MultiQueryResultResultsList = /*@__PURE__*/ S.Array( + SingleQueryResult, +) as any as S.Schema; + +/** The result of a multi-query. */ +export interface MultiQueryResult { + results: MultiQueryResultResultsList; + performance: QueryPerformance; + billing: QueryBilling; +} +export const MultiQueryResult = /*@__PURE__*/ S.suspend(() => + S.Struct({ + results: MultiQueryResultResultsList, + performance: QueryPerformance, + billing: QueryBilling, + }), +).annotate({ + identifier: "MultiQueryResult", +}) as any as S.Schema; + +/** Configuration options for full-text search. */ +export interface FullTextSearchConfig { + /** The `k1` term saturation parameter for BM25. Defaults to `1.2`. */ + k1?: number; + /** The `b` document length normalization parameter for BM25. Defaults to `0.75`. */ + b?: number; + language?: unknown; + /** Language-specific stemming for the text. Defaults to `false` (i.e., do not stem). */ + stemming?: boolean; + /** Removes common words from the text based on language. Defaults to `true` (i.e. remove common words). */ + remove_stopwords?: boolean; + /** Whether to convert each non-ASCII character in a token to its ASCII equivalent, if one exists (e.g., à -> a). Defaults to `false` (i.e., no folding). */ + ascii_folding?: boolean; + /** Whether searching is case-sensitive. Defaults to `false` (i.e. case-insensitive). */ + case_sensitive?: boolean; + /** Maximum length of a token in bytes. Tokens larger than this value during tokenization will be filtered out. Has to be between `1` and `254` (inclusive). Defaults to `39`. */ + max_token_length?: number; + tokenizer?: unknown; +} +export const FullTextSearchConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + k1: S.optional(S.Number), + b: S.optional(S.Number), + language: S.optional(S.Unknown), + stemming: S.optional(S.Boolean), + remove_stopwords: S.optional(S.Boolean), + ascii_folding: S.optional(S.Boolean), + case_sensitive: S.optional(S.Boolean), + max_token_length: S.optional(S.Number), + tokenizer: S.optional(S.Unknown), + }), +).annotate({ + identifier: "FullTextSearchConfig", +}) as any as S.Schema; + +/** Whether this attribute can be used as part of a BM25 full-text search. Requires the `string` or `[]string` type, and by default, BM25-enabled attributes are not filterable. You can override this by setting `filterable: true`. */ +export type FullTextSearch = boolean | FullTextSearchConfig; +export const FullTextSearch = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** Configuration options for ANN (Approximate Nearest Neighbor) indexing. */ +export interface AnnConfig { + distance_metric?: unknown; + /** Opt in to late-interaction (MUVERA) indexing. Only valid on fixed-dim `[][N]f32` vector array attributes, and is required to enable an ANN index on such attributes. Defaults to `false`. */ + late_interaction?: boolean; +} +export const AnnConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + distance_metric: S.optional(S.Unknown), + late_interaction: S.optional(S.Boolean), + }), +).annotate({ identifier: "AnnConfig" }) as any as S.Schema; + +/** Whether to create an approximate nearest neighbor index for the attribute. Can be a boolean or a detailed configuration object. */ +export type Ann = boolean | AnnConfig; +export const Ann = /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** Whether to create a sparse kNN index for the attribute. Requires the `{}f16` type. */ +export interface SparseKnn { + distance_metric: unknown; +} +export const SparseKnn = /*@__PURE__*/ S.suspend(() => + S.Struct({ + distance_metric: S.Unknown, + }), +).annotate({ identifier: "SparseKnn" }) as any as S.Schema; + +/** Configuration options for automatic embedding. */ +export interface AttributeEmbedConfig { + /** The name of an existing vector attribute to store embeddings in. If omitted, turbopuffer will generate a computed vector attribute named `$embed_`. */ + attribute?: string; + /** The model to use for embedding. See our documentation for a list of models supported in each region. */ + model: string; + /** The dimensionality to embed at. If not set, will pick the default for this model. If you're storing embeddings in an existing attribute, this can be omitted, and may not be set to a value other than the dimensions of that attribute. */ + dims?: number; +} +export const AttributeEmbedConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + attribute: S.optional(S.String), + model: S.String, + dims: S.optional(S.Number), + }), +).annotate({ + identifier: "AttributeEmbedConfig", +}) as any as S.Schema; + +/** Whether to automatically embed this string attribute into a vector attribute. Can be a model name, a detailed configuration object, or `null` to remove an existing embedding configuration. */ +export type AttributeEmbed = string | AttributeEmbedConfig; +export const AttributeEmbed = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** Detailed configuration for an attribute attached to a document. */ +export interface AttributeSchemaConfig { + type: string; + /** Whether or not the attributes can be used in filters. */ + filterable?: boolean; + /** Whether to enable Regex filters on this attribute. */ + regex?: boolean; + /** Whether to enable Glob filters on this attribute. */ + glob?: boolean; + /** Whether to enable Fuzzy filters on this attribute. */ + fuzzy?: boolean; + full_text_search?: FullTextSearch; + ann?: Ann; + sparse_knn?: SparseKnn; + embed?: AttributeEmbed | null; +} +export const AttributeSchemaConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + type: S.String, + filterable: S.optional(S.Boolean), + regex: S.optional(S.Boolean), + glob: S.optional(S.Boolean), + fuzzy: S.optional(S.Boolean), + full_text_search: S.optional(FullTextSearch), + ann: S.optional(Ann), + sparse_knn: S.optional(SparseKnn), + embed: S.optional(S.NullOr(AttributeEmbed)), + }), +).annotate({ + identifier: "AttributeSchemaConfig", +}) as any as S.Schema; + +/** The schema for an attribute attached to a document. */ +export type AttributeSchema = string | AttributeSchemaConfig; +export const AttributeSchema = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** The desired schema for the namespace. */ +export type CreateNamespaceSchemaRequestBodyMap = { + [key: string]: AttributeSchema | undefined; +}; +export const CreateNamespaceSchemaRequestBodyMap = /*@__PURE__*/ S.Record( + S.String, + AttributeSchema, +) as any as S.Schema; + +export interface CreateNamespaceSchemaRequest { + /** The name of the namespace. */ + namespace: string; + body?: CreateNamespaceSchemaRequestBodyMap; +} +export const CreateNamespaceSchemaRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + body: S.optional(CreateNamespaceSchemaRequestBodyMap.pipe(T.HttpBody())), + }).pipe( + T.Http({ + method: "POST", + uri: "/v1/namespaces/{namespace}/schema", + code: 200, + }), + ), +).annotate({ + identifier: "CreateNamespaceSchemaRequest", +}) as any as S.Schema; + +/** The updated schema for the namespace. */ +export type CreateNamespaceSchemaResponseBodyMap = { + [key: string]: AttributeSchemaConfig | undefined; +}; +export const CreateNamespaceSchemaResponseBodyMap = /*@__PURE__*/ S.Record( + S.String, + AttributeSchemaConfig, +) as any as S.Schema; + +export type CreateNamespaceSchemaResponse = + CreateNamespaceSchemaResponseBodyMap; +export const CreateNamespaceSchemaResponse = /*@__PURE__*/ S.suspend(() => + CreateNamespaceSchemaResponseBodyMap.pipe(T.RawResponseRoot()), +).annotate({ + identifier: "CreateNamespaceSchemaResponse", +}) as any as S.Schema; + +export interface DeleteNamespaceRequest { + /** The name of the namespace. */ + namespace: string; +} +export const DeleteNamespaceRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + }).pipe( + T.Http({ method: "DELETE", uri: "/v2/namespaces/{namespace}", code: 200 }), + ), +).annotate({ + identifier: "DeleteNamespaceRequest", +}) as any as S.Schema; + +export interface DeleteNamespaceResponse { + /** The status of the request. */ + status: unknown; +} +export const DeleteNamespaceResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + status: S.Unknown, + }), +).annotate({ + identifier: "DeleteNamespaceResponse", +}) as any as S.Schema; + +export interface GetNamespaceHintCacheWarmRequest { + /** The name of the namespace. */ + namespace: string; +} +export const GetNamespaceHintCacheWarmRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + }).pipe( + T.Http({ + method: "GET", + uri: "/v1/namespaces/{namespace}/hint_cache_warm", + code: 200, + }), + ), +).annotate({ + identifier: "GetNamespaceHintCacheWarmRequest", +}) as any as S.Schema; + +export interface GetNamespaceHintCacheWarmResponse { + /** The status of the request. */ + status: unknown; + message?: string; +} +export const GetNamespaceHintCacheWarmResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + status: S.Unknown, + message: S.optional(S.String), + }), +).annotate({ + identifier: "GetNamespaceHintCacheWarmResponse", +}) as any as S.Schema; + +export interface GetNamespaceMetadataRequest { + /** The name of the namespace. */ + namespace: string; +} +export const GetNamespaceMetadataRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + }).pipe( + T.Http({ + method: "GET", + uri: "/v2/namespaces/{namespace}/metadata", + code: 200, + }), + ), +).annotate({ + identifier: "GetNamespaceMetadataRequest", +}) as any as S.Schema; + +/** The schema of the namespace. */ +export type NamespaceMetadataSchemaMap = { + [key: string]: AttributeSchemaConfig | undefined; +}; +export const NamespaceMetadataSchemaMap = /*@__PURE__*/ S.Record( + S.String, + AttributeSchemaConfig, +) as any as S.Schema; + +/** Encrypt the namespace with a customer-managed encryption key (CMEK). */ +export interface EncryptionCase0 { + mode: unknown; + /** The identifier of the CMEK key to use for encryption. For GCP, the fully-qualified resource name of the key. For AWS, the ARN of the key. */ + key_name: string; +} +export const EncryptionCase0 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + mode: S.Unknown, + key_name: S.String, + }), +).annotate({ + identifier: "EncryptionCase0", +}) as any as S.Schema; + +/** Use the default server-side encryption (SSE). */ +export interface EncryptionCase1 { + mode: unknown; +} +export const EncryptionCase1 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + mode: S.Unknown, + }), +).annotate({ + identifier: "EncryptionCase1", +}) as any as S.Schema; + +/** The encryption configuration for a namespace. */ +export type Encryption = EncryptionCase0 | EncryptionCase1; +export const Encryption = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface NamespaceMetadataIndexCase0 { + status: unknown; +} +export const NamespaceMetadataIndexCase0 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + status: S.Unknown, + }), +).annotate({ + identifier: "NamespaceMetadataIndexCase0", +}) as any as S.Schema; + +export interface NamespaceMetadataIndexCase1 { + status: unknown; + /** The number of bytes in the namespace that are in the write-ahead log but have not yet been indexed. */ + unindexed_bytes: number; +} +export const NamespaceMetadataIndexCase1 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + status: S.Unknown, + unindexed_bytes: S.Number, + }), +).annotate({ + identifier: "NamespaceMetadataIndexCase1", +}) as any as S.Schema; + +export type NamespaceMetadataIndex = + | NamespaceMetadataIndexCase0 + | NamespaceMetadataIndexCase1; +export const NamespaceMetadataIndex = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** Operational status for a pinned namespace. */ +export interface PinningStatus { + /** The timestamp of the latest pinning status snapshot. */ + updated_at: string; + /** The number of replicas that are warm and serving traffic. */ + ready_replicas: number; + /** Aggregate utilization for the pinned namespace, reported as a value between 0.0 and 1.0. */ + utilization: number; +} +export const PinningStatus = /*@__PURE__*/ S.suspend(() => + S.Struct({ + updated_at: S.String, + ready_replicas: S.Number, + utilization: S.Number, + }), +).annotate({ identifier: "PinningStatus" }) as any as S.Schema; + +/** Configuration for namespace pinning, along with the current status of the pinned namespace. */ +export interface PinningConfigResponse { + /** The number of read replicas to provision. Defaults to 1 if not specified. */ + replicas?: number; + status?: PinningStatus; +} +export const PinningConfigResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + replicas: S.optional(S.Number), + status: S.optional(PinningStatus), + }), +).annotate({ + identifier: "PinningConfigResponse", +}) as any as S.Schema; + +/** Configuration for namespace sharding, which partitions a namespace's documents across multiple internal shards to scale indexing and query throughput beyond a single machine. Sharding can only be configured on a namespace's inaugural write, and cannot be added to or changed on an existing namespace. */ +export interface ShardingConfig { + /** The number of shards to partition the namespace into. */ + num_shards: number; +} +export const ShardingConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + num_shards: S.Number, + }), +).annotate({ identifier: "ShardingConfig" }) as any as S.Schema; + +/** Metadata about a namespace. */ +export interface NamespaceMetadata { + /** The schema of the namespace. */ + schema: NamespaceMetadataSchemaMap; + /** The approximate number of rows in the namespace. */ + approx_row_count: number; + /** The approximate number of logical bytes in the namespace. */ + approx_logical_bytes: number; + /** The timestamp when the namespace was created. */ + created_at: string; + /** The timestamp when the namespace was last modified by a write operation. */ + updated_at: string; + encryption: Encryption; + index: NamespaceMetadataIndex; + pinning?: PinningConfigResponse; + sharding?: ShardingConfig; +} +export const NamespaceMetadata = /*@__PURE__*/ S.suspend(() => + S.Struct({ + schema: NamespaceMetadataSchemaMap, + approx_row_count: S.Number, + approx_logical_bytes: S.Number, + created_at: S.String, + updated_at: S.String, + encryption: Encryption, + index: NamespaceMetadataIndex, + pinning: S.optional(PinningConfigResponse), + sharding: S.optional(ShardingConfig), + }), +).annotate({ + identifier: "NamespaceMetadata", +}) as any as S.Schema; + +export interface GetNamespaceSchemaRequest { + /** The name of the namespace. */ + namespace: string; +} +export const GetNamespaceSchemaRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + }).pipe( + T.Http({ + method: "GET", + uri: "/v1/namespaces/{namespace}/schema", + code: 200, + }), + ), +).annotate({ + identifier: "GetNamespaceSchemaRequest", +}) as any as S.Schema; + +/** The response to a successful namespace schema request. */ +export type GetNamespaceSchemaResponseBodyMap = { + [key: string]: AttributeSchemaConfig | undefined; +}; +export const GetNamespaceSchemaResponseBodyMap = /*@__PURE__*/ S.Record( + S.String, + AttributeSchemaConfig, +) as any as S.Schema; + +export type GetNamespaceSchemaResponse = GetNamespaceSchemaResponseBodyMap; +export const GetNamespaceSchemaResponse = /*@__PURE__*/ S.suspend(() => + GetNamespaceSchemaResponseBodyMap.pipe(T.RawResponseRoot()), +).annotate({ + identifier: "GetNamespaceSchemaResponse", +}) as any as S.Schema; + +export interface ListNamespacesRequest { + /** Retrieve the next page of results. */ + cursor?: string; + /** Retrieve only the namespaces that match the prefix. */ + prefix?: string; + /** Limit the number of results per page. */ + page_size?: number; +} +export const ListNamespacesRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + cursor: S.optional(S.String.pipe(T.Query())), + prefix: S.optional(S.String.pipe(T.Query())), + page_size: S.optional(S.Number.pipe(T.Query())), + }).pipe(T.Http({ method: "GET", uri: "/v1/namespaces", code: 200 })), +).annotate({ + identifier: "ListNamespacesRequest", +}) as any as S.Schema; + +/** A summary of a namespace. */ +export interface NamespaceSummary { + /** The namespace ID. */ + id: string; +} +export const NamespaceSummary = /*@__PURE__*/ S.suspend(() => + S.Struct({ + id: S.String, + }), +).annotate({ + identifier: "NamespaceSummary", +}) as any as S.Schema; + +/** The list of namespaces. */ +export type ListNamespacesResponseNamespacesList = Array; +export const ListNamespacesResponseNamespacesList = /*@__PURE__*/ S.Array( + NamespaceSummary, +) as any as S.Schema; + +export interface ListNamespacesResponse { + /** The list of namespaces. */ + namespaces?: ListNamespacesResponseNamespacesList; + /** The cursor to use to retrieve the next page of results. */ + next_cursor?: string; +} +export const ListNamespacesResponse = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespaces: S.optional(ListNamespacesResponseNamespacesList), + next_cursor: S.optional(S.String), + }), +).annotate({ + identifier: "ListNamespacesResponse", +}) as any as S.Schema; + +/** The IDs of the documents. */ +export type ColumnsIdList = Array; +export const ColumnsIdList = /*@__PURE__*/ S.Array( + Id, +) as any as S.Schema; + +/** The vector embeddings of the documents. */ +export type ColumnsVectorCase0List = Array; +export const ColumnsVectorCase0List = /*@__PURE__*/ S.Array( + Vector, +) as any as S.Schema; + +export type ColumnsVector = ColumnsVectorCase0List | Vector; +export const ColumnsVector = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +/** A list of documents in columnar format. Each key is a column name, mapped to an array of values for that column. */ +export interface Columns { + /** The IDs of the documents. */ + id: ColumnsIdList; + vector?: ColumnsVector; +} +export const Columns = /*@__PURE__*/ S.suspend(() => + S.Struct({ + id: ColumnsIdList, + vector: S.optional(ColumnsVector), + }), +).annotate({ identifier: "Columns" }) as any as S.Schema; + +export type UpdateNamespaceRequestUpsertRowsList = Array; +export const UpdateNamespaceRequestUpsertRowsList = /*@__PURE__*/ S.Array( + Row, +) as any as S.Schema; + +export type UpdateNamespaceRequestPatchRowsList = Array; +export const UpdateNamespaceRequestPatchRowsList = /*@__PURE__*/ S.Array( + Row, +) as any as S.Schema; + +export type UpdateNamespaceRequestDeletesList = Array; +export const UpdateNamespaceRequestDeletesList = /*@__PURE__*/ S.Array( + Id, +) as any as S.Schema; + +/** The schema of the attributes attached to the documents. */ +export type UpdateNamespaceRequestSchemaMap = { + [key: string]: AttributeSchema | undefined; +}; +export const UpdateNamespaceRequestSchemaMap = /*@__PURE__*/ S.Record( + S.String, + AttributeSchema, +) as any as S.Schema; + +export interface BranchFromNamespaceConfig { + /** The namespace to create an instant, copy-on-write clone of. */ + source_namespace: string; +} +export const BranchFromNamespaceConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + source_namespace: S.String, + }), +).annotate({ + identifier: "BranchFromNamespaceConfig", +}) as any as S.Schema; + +export type BranchFromNamespaceParams = string | BranchFromNamespaceConfig; +export const BranchFromNamespaceParams = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface CopyFromNamespaceConfig { + /** The namespace to copy documents from. */ + source_namespace: string; + /** (Optional) An API key for the organization containing the source namespace */ + source_api_key?: string; + /** (Optional) The region of the source namespace. */ + source_region?: string; +} +export const CopyFromNamespaceConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + source_namespace: S.String, + source_api_key: S.optional(S.String), + source_region: S.optional(S.String), + }), +).annotate({ + identifier: "CopyFromNamespaceConfig", +}) as any as S.Schema; + +export type CopyFromNamespaceParams = string | CopyFromNamespaceConfig; +export const CopyFromNamespaceParams = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export type PatchByFilterPatchMap = { [key: string]: unknown | undefined }; +export const PatchByFilterPatchMap = /*@__PURE__*/ S.Record( + S.String, + S.Unknown, +) as any as S.Schema; + +/** The patch and filter specifying which documents to patch. */ +export interface PatchByFilter { + patch: PatchByFilterPatchMap; + /** Filter by attributes. Same syntax as the query endpoint. */ + filters: unknown; +} +export const PatchByFilter = /*@__PURE__*/ S.suspend(() => + S.Struct({ + patch: PatchByFilterPatchMap, + filters: S.Unknown, + }), +).annotate({ identifier: "PatchByFilter" }) as any as S.Schema; + +export interface UpdateNamespaceRequest { + /** The name of the namespace. */ + namespace: string; + upsert_columns?: Columns; + upsert_rows?: UpdateNamespaceRequestUpsertRowsList; + patch_columns?: Columns; + patch_rows?: UpdateNamespaceRequestPatchRowsList; + deletes?: UpdateNamespaceRequestDeletesList; + /** A condition evaluated against the current value of each document targeted by an upsert write. Only documents that pass the condition are upserted. */ + upsert_condition?: unknown; + /** A condition evaluated against the current value of each document targeted by a patch write. Only documents that pass the condition are patched. */ + patch_condition?: unknown; + /** A condition evaluated against the current value of each document targeted by a delete write. Only documents that pass the condition are deleted. */ + delete_condition?: unknown; + distance_metric?: unknown; + /** The schema of the attributes attached to the documents. */ + schema?: UpdateNamespaceRequestSchemaMap; + branch_from_namespace?: BranchFromNamespaceParams; + copy_from_namespace?: CopyFromNamespaceParams; + /** The filter specifying which documents to delete. */ + delete_by_filter?: unknown; + /** Allow partial completion when filter matches too many documents. */ + delete_by_filter_allow_partial?: boolean; + patch_by_filter?: PatchByFilter; + /** Allow partial completion when filter matches too many documents. */ + patch_by_filter_allow_partial?: boolean; + /** If true, return the IDs of affected rows (deleted, patched, upserted) in the response. For filtered and conditional writes, only IDs for writes that succeeded will be included. */ + return_affected_ids?: boolean; + encryption?: Encryption; + sharding?: ShardingConfig; + /** Disables write throttling (HTTP 429 responses) during high-volume ingestion. */ + disable_backpressure?: boolean; +} +export const UpdateNamespaceRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + upsert_columns: S.optional(Columns), + upsert_rows: S.optional(UpdateNamespaceRequestUpsertRowsList), + patch_columns: S.optional(Columns), + patch_rows: S.optional(UpdateNamespaceRequestPatchRowsList), + deletes: S.optional(UpdateNamespaceRequestDeletesList), + upsert_condition: S.optional(S.Unknown), + patch_condition: S.optional(S.Unknown), + delete_condition: S.optional(S.Unknown), + distance_metric: S.optional(S.Unknown), + schema: S.optional(UpdateNamespaceRequestSchemaMap), + branch_from_namespace: S.optional(BranchFromNamespaceParams), + copy_from_namespace: S.optional(CopyFromNamespaceParams), + delete_by_filter: S.optional(S.Unknown), + delete_by_filter_allow_partial: S.optional(S.Boolean), + patch_by_filter: S.optional(PatchByFilter), + patch_by_filter_allow_partial: S.optional(S.Boolean), + return_affected_ids: S.optional(S.Boolean), + encryption: S.optional(Encryption), + sharding: S.optional(ShardingConfig), + disable_backpressure: S.optional(S.Boolean), + }).pipe( + T.Http({ method: "POST", uri: "/v2/namespaces/{namespace}", code: 200 }), + ), +).annotate({ + identifier: "UpdateNamespaceRequest", +}) as any as S.Schema; + +/** The IDs of documents that were upserted. Only included when `return_affected_ids` is true and at least one document was upserted. */ +export type WriteResultUpsertedIdsList = Array; +export const WriteResultUpsertedIdsList = /*@__PURE__*/ S.Array( + Id, +) as any as S.Schema; + +/** The IDs of documents that were patched. Only included when `return_affected_ids` is true and at least one document was patched. */ +export type WriteResultPatchedIdsList = Array; +export const WriteResultPatchedIdsList = /*@__PURE__*/ S.Array( + Id, +) as any as S.Schema; + +/** The IDs of documents that were deleted. Only included when `return_affected_ids` is true and at least one document was deleted. */ +export type WriteResultDeletedIdsList = Array; +export const WriteResultDeletedIdsList = /*@__PURE__*/ S.Array( + Id, +) as any as S.Schema; + +/** The billing information for a write request. */ +export interface WriteBilling { + /** The number of billable logical bytes written to the namespace. */ + billable_logical_bytes_written: number; + query?: QueryBilling; +} +export const WriteBilling = /*@__PURE__*/ S.suspend(() => + S.Struct({ + billable_logical_bytes_written: S.Number, + query: S.optional(QueryBilling), + }), +).annotate({ identifier: "WriteBilling" }) as any as S.Schema; + +/** The performance information for a write request. */ +export interface WritePerformance { + /** Request time measured on the server, in milliseconds. */ + server_total_ms: number; +} +export const WritePerformance = /*@__PURE__*/ S.suspend(() => + S.Struct({ + server_total_ms: S.Number, + }), +).annotate({ + identifier: "WritePerformance", +}) as any as S.Schema; + +/** The response to a successful write request. */ +export interface WriteResult { + /** The status of the request. */ + status: unknown; + /** A message describing the result of the write request. */ + message: string; + /** The number of rows affected by the write request. */ + rows_affected: number; + /** The number of rows upserted by the write request. */ + rows_upserted?: number; + /** The number of rows patched by the write request. */ + rows_patched?: number; + /** The number of rows deleted by the write request. */ + rows_deleted?: number; + /** Whether more documents match the filter for partial operations. */ + rows_remaining?: boolean; + /** The IDs of documents that were upserted. Only included when `return_affected_ids` is true and at least one document was upserted. */ + upserted_ids?: WriteResultUpsertedIdsList; + /** The IDs of documents that were patched. Only included when `return_affected_ids` is true and at least one document was patched. */ + patched_ids?: WriteResultPatchedIdsList; + /** The IDs of documents that were deleted. Only included when `return_affected_ids` is true and at least one document was deleted. */ + deleted_ids?: WriteResultDeletedIdsList; + billing: WriteBilling; + performance?: WritePerformance; +} +export const WriteResult = /*@__PURE__*/ S.suspend(() => + S.Struct({ + status: S.Unknown, + message: S.String, + rows_affected: S.Number, + rows_upserted: S.optional(S.Number), + rows_patched: S.optional(S.Number), + rows_deleted: S.optional(S.Number), + rows_remaining: S.optional(S.Boolean), + upserted_ids: S.optional(WriteResultUpsertedIdsList), + patched_ids: S.optional(WriteResultPatchedIdsList), + deleted_ids: S.optional(WriteResultDeletedIdsList), + billing: WriteBilling, + performance: S.optional(WritePerformance), + }), +).annotate({ identifier: "WriteResult" }) as any as S.Schema; + +export interface UpdateNamespaceByNamespaceRequest { + /** The name of the namespace. */ + namespace: string; + /** The namespace to create an instant, copy-on-write clone of. */ + source_namespace: string; +} +export const UpdateNamespaceByNamespaceRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + source_namespace: S.String, + }).pipe( + T.Http({ method: "POST", uri: "/v2/namespaces/{namespace}", code: 200 }), + ), +).annotate({ + identifier: "UpdateNamespaceByNamespaceRequest", +}) as any as S.Schema; + +export interface UpdateNamespaceByNamespaceRequest2 { + /** The name of the namespace. */ + namespace: string; + /** The namespace to copy documents from. */ + source_namespace: string; + /** (Optional) An API key for the organization containing the source namespace */ + source_api_key?: string; + /** (Optional) The region of the source namespace. */ + source_region?: string; + /** (Optional) The encryption configuration for the destination namespace. */ + dest_encryption?: Encryption; +} +export const UpdateNamespaceByNamespaceRequest2 = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + source_namespace: S.String, + source_api_key: S.optional(S.String), + source_region: S.optional(S.String), + dest_encryption: S.optional(Encryption), + }).pipe( + T.Http({ method: "POST", uri: "/v2/namespaces/{namespace}", code: 200 }), + ), +).annotate({ + identifier: "UpdateNamespaceByNamespaceRequest2", +}) as any as S.Schema; + +/** Configuration for namespace pinning. */ +export interface PinningConfig { + /** The number of read replicas to provision. Defaults to 1 if not specified. */ + replicas?: number; +} +export const PinningConfig = /*@__PURE__*/ S.suspend(() => + S.Struct({ + replicas: S.optional(S.Number), + }), +).annotate({ identifier: "PinningConfig" }) as any as S.Schema; + +/** Configuration for namespace pinning. - Missing field: no change to pinning configuration - `null` or `false`: explicitly remove pinning - `true`: enable pinning with default configuration - Object: set pinning configuration */ +export type UpdateNamespaceMetadataRequestPinning = boolean | PinningConfig; +export const UpdateNamespaceMetadataRequestPinning = + /*@__PURE__*/ S.Unknown as any as S.Schema; + +export interface UpdateNamespaceMetadataRequest { + /** The name of the namespace. */ + namespace: string; + /** Configuration for namespace pinning. - Missing field: no change to pinning configuration - `null` or `false`: explicitly remove pinning - `true`: enable pinning with default configuration - Object: set pinning configuration */ + pinning?: UpdateNamespaceMetadataRequestPinning | null; +} +export const UpdateNamespaceMetadataRequest = /*@__PURE__*/ S.suspend(() => + S.Struct({ + namespace: S.String.pipe(T.Label()), + pinning: S.optional(S.NullOr(UpdateNamespaceMetadataRequestPinning)), + }).pipe( + T.Http({ + method: "PATCH", + uri: "/v1/namespaces/{namespace}/metadata", + code: 200, + }), + ), +).annotate({ + identifier: "UpdateNamespaceMetadataRequest", +}) as any as S.Schema; + +export type CreateNamespaceDebugRecallError = TurbopufferOpError; +/** Evaluate recall. */ +export const createNamespaceDebugRecall: API.OperationMethod< + CreateNamespaceDebugRecallRequest, + CreateNamespaceDebugRecallResponse, + CreateNamespaceDebugRecallError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: CreateNamespaceDebugRecallRequest, + output: CreateNamespaceDebugRecallResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type CreateNamespaceExplainQueryError = TurbopufferOpError; +/** Explain a query plan. */ +export const createNamespaceExplainQuery: API.OperationMethod< + CreateNamespaceExplainQueryRequest, + CreateNamespaceExplainQueryResponse, + CreateNamespaceExplainQueryError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: CreateNamespaceExplainQueryRequest, + output: CreateNamespaceExplainQueryResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type CreateNamespaceQueryError = TurbopufferOpError; +/** Query, filter, full-text search and vector search documents. */ +export const createNamespaceQuery: API.OperationMethod< + CreateNamespaceQueryRequest, + CreateNamespaceQueryResponse, + CreateNamespaceQueryError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: CreateNamespaceQueryRequest, + output: CreateNamespaceQueryResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type CreateNamespaceQuery2Error = TurbopufferOpError; +/** Issue multiple concurrent queries filter or search documents. */ +export const createNamespaceQuery2: API.OperationMethod< + CreateNamespaceQueryRequest2, + MultiQueryResult, + CreateNamespaceQuery2Error, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: CreateNamespaceQueryRequest2, + output: MultiQueryResult, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type CreateNamespaceSchemaError = TurbopufferOpError; +/** Update namespace schema. */ +export const createNamespaceSchema: API.OperationMethod< + CreateNamespaceSchemaRequest, + CreateNamespaceSchemaResponse, + CreateNamespaceSchemaError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: CreateNamespaceSchemaRequest, + output: CreateNamespaceSchemaResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type DeleteNamespaceError = TurbopufferOpError; +/** Delete namespace. */ +export const deleteNamespace: API.OperationMethod< + DeleteNamespaceRequest, + DeleteNamespaceResponse, + DeleteNamespaceError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: DeleteNamespaceRequest, + output: DeleteNamespaceResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type GetNamespaceHintCacheWarmError = TurbopufferOpError; +/** Signal turbopuffer to prepare for low-latency requests. */ +export const getNamespaceHintCacheWarm: API.OperationMethod< + GetNamespaceHintCacheWarmRequest, + GetNamespaceHintCacheWarmResponse, + GetNamespaceHintCacheWarmError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: GetNamespaceHintCacheWarmRequest, + output: GetNamespaceHintCacheWarmResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type GetNamespaceMetadataError = TurbopufferOpError; +/** Get metadata about a namespace. */ +export const getNamespaceMetadata: API.OperationMethod< + GetNamespaceMetadataRequest, + NamespaceMetadata, + GetNamespaceMetadataError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: GetNamespaceMetadataRequest, + output: NamespaceMetadata, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type GetNamespaceSchemaError = TurbopufferOpError; +/** Get namespace schema. */ +export const getNamespaceSchema: API.OperationMethod< + GetNamespaceSchemaRequest, + GetNamespaceSchemaResponse, + GetNamespaceSchemaError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: GetNamespaceSchemaRequest, + output: GetNamespaceSchemaResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type ListNamespacesError = TurbopufferOpError; +/** List namespaces. */ +export const listNamespaces: API.OperationMethod< + ListNamespacesRequest, + ListNamespacesResponse, + ListNamespacesError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: ListNamespacesRequest, + output: ListNamespacesResponse, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type UpdateNamespaceError = TurbopufferOpError; +/** Create, update, or delete documents. */ +export const updateNamespace: API.OperationMethod< + UpdateNamespaceRequest, + WriteResult, + UpdateNamespaceError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: UpdateNamespaceRequest, + output: WriteResult, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type UpdateNamespaceByNamespaceError = TurbopufferOpError; +/** Creates an instant, copy-on-write clone of a namespace. */ +export const updateNamespaceByNamespace: API.OperationMethod< + UpdateNamespaceByNamespaceRequest, + WriteResult, + UpdateNamespaceByNamespaceError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: UpdateNamespaceByNamespaceRequest, + output: WriteResult, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type UpdateNamespaceByNamespace2Error = TurbopufferOpError; +/** Copy all documents from another namespace into this one. */ +export const updateNamespaceByNamespace2: API.OperationMethod< + UpdateNamespaceByNamespaceRequest2, + WriteResult, + UpdateNamespaceByNamespace2Error, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: UpdateNamespaceByNamespaceRequest2, + output: WriteResult, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); + +export type UpdateNamespaceMetadataError = TurbopufferOpError; +/** Update metadata configuration for a namespace. */ +export const updateNamespaceMetadata: API.OperationMethod< + UpdateNamespaceMetadataRequest, + NamespaceMetadata, + UpdateNamespaceMetadataError, + TurbopufferOpContext +> = /*@__PURE__*/ API.make(() => ({ + input: UpdateNamespaceMetadataRequest, + output: NamespaceMetadata, + errors: [UnknownTurbopufferError], + protocol: TurbopufferProtocol, + retry: Retry.Retry, +})); diff --git a/packages/turbopuffer/src/traits.ts b/packages/turbopuffer/src/traits.ts new file mode 100644 index 000000000..1713bd256 --- /dev/null +++ b/packages/turbopuffer/src/traits.ts @@ -0,0 +1,44 @@ +/** + * turbopuffer SDK trait surface — hand-written. + * + * Re-exports the generic protocol traits from core (so generated operations + * import everything from one place). turbopuffer has no envelope of its own; + * the REST-protocol traits (SensitiveValue / RawResponse) come from + * `core/protocol-rest`. + */ +export { + Body, + Header, + Query, + Label, + Http, + ResponseCode, + HttpBody, + FormDataFile, + KeyDictionary, + UnionCases, + applyErrorMatchers, + getErrorMatchers, + type HttpTrait, + type ErrorMatcher, + bodySymbol, + headerSymbol, + querySymbol, + labelSymbol, + httpSymbol, + responseCodeSymbol, + httpBodySymbol, + formDataFileSymbol, + keyDictionarySymbol, + unionCasesSymbol, + errorMatchersSymbol, +} from "@distilled.cloud/core/trait"; + +export { + SensitiveValue, + RawResponse, + RawResponseRoot, + sensitiveValueSymbol, + rawResponseSymbol, + rawResponseRootSymbol, +} from "@distilled.cloud/core/protocol-rest"; diff --git a/packages/turbopuffer/tsconfig.json b/packages/turbopuffer/tsconfig.json new file mode 100644 index 000000000..56b16e575 --- /dev/null +++ b/packages/turbopuffer/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "composite": true, + "noEmit": false, + "outDir": "./lib", + "rootDir": "./src", + "paths": { + "@distilled.cloud/core/*": ["../core/src/*"] + } + }, + "references": [{ "path": "../core" }] +} diff --git a/packages/turbopuffer/tsconfig.scripts.json b/packages/turbopuffer/tsconfig.scripts.json new file mode 100644 index 000000000..be37c3474 --- /dev/null +++ b/packages/turbopuffer/tsconfig.scripts.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["scripts/**/*.ts"], + "compilerOptions": { + "composite": true, + "noEmit": false, + "emitDeclarationOnly": true, + "outDir": "./.scripts-types", + "rootDir": "./scripts", + "tsBuildInfoFile": "./.scripts-types/tsconfig.scripts.tsbuildinfo", + // Resolve @distilled.cloud/core/* to src (the bun condition), matching + // how the scripts actually run under bun. + "rewriteRelativeImportExtensions": false, + "customConditions": ["bun"] + }, + "references": [{ "path": "../core" }] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c479dbd8..e10873774 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1301,6 +1301,25 @@ importers: specifier: catalog:tooling version: 26.4.1 + packages/turbopuffer: + dependencies: + '@distilled.cloud/core': + specifier: workspace:* + version: link:../core + effect: + specifier: catalog:effect + version: 4.0.0-rc.112 + devDependencies: + '@effect/platform-bun': + specifier: catalog:effect + version: 4.0.0-rc.112(effect@4.0.0-rc.112) + '@types/bun': + specifier: catalog:tooling + version: 1.4.1 + '@types/node': + specifier: catalog:tooling + version: 26.4.1 + packages/turso: dependencies: '@distilled.cloud/core': diff --git a/stacks/distilled-submodules/SpecRepos.ts b/stacks/distilled-submodules/SpecRepos.ts index c3a6e5c0a..ad22da326 100644 --- a/stacks/distilled-submodules/SpecRepos.ts +++ b/stacks/distilled-submodules/SpecRepos.ts @@ -110,6 +110,7 @@ export const SPEC_REPOS: readonly SpecRepo[] = [ { package: "surrealdb" }, { package: "temporal" }, { package: "trigger-dev" }, + { package: "turbopuffer" }, { package: "turso" }, { package: "typesense" }, { package: "vercel" }, diff --git a/stacks/distilled-submodules/spec-repos/turbopuffer/fetch-specs.ts b/stacks/distilled-submodules/spec-repos/turbopuffer/fetch-specs.ts new file mode 100644 index 000000000..e879bd60d --- /dev/null +++ b/stacks/distilled-submodules/spec-repos/turbopuffer/fetch-specs.ts @@ -0,0 +1,158 @@ +#!/usr/bin/env bun +/** + * Mirrors the turbopuffer OpenAPI spec and a snapshot of vendor docs into + * ../specs/. + * + * Only the 1 file the distilled turbopuffer generator actually reads is + * downloaded, straight from raw.githubusercontent.com — the upstream + * repository is never cloned, so the mirror stays exactly as large as the + * spec itself. Vendor docs pages are snapshotted next to it so convert/ + * generate never crawl turbopuffer.com at convert time. + * + * Usage: + * bun run fetch-specs.ts + * + * Written to: + * ../specs/openapi.json + * ../specs/docs/llms.txt + * ../specs/docs/*.md + */ + +import { mkdirSync } from "fs"; +import { dirname } from "path"; + +/** Upstream repository, as `/`. */ +const REPO = "turbopuffer/turbopuffer-openapi"; +/** Branch (or tag/commit) to mirror. Linked from turbopuffer.com docs. */ +const REF = "next"; +/** Path of the OpenAPI document within {@link REPO}. */ +const SPEC_PATH = "openapi.yml"; + +const SPECS_DIR = "../specs"; +const OUTPUT_PATH = `${SPECS_DIR}/openapi.json`; +const DOCS_DIR = `${SPECS_DIR}/docs`; +const USER_AGENT = "distilled.cloud-turbopuffer-spec-mirror"; +const DOCS_LLMS_URL = "https://turbopuffer.com/llms.txt"; + +/** + * First-party API docs snapshotted at fetch time. Markdown is served at the + * same paths as the HTML pages (Mintlify). + */ +const DOCS: { url: string; output: string }[] = [ + { + url: "https://turbopuffer.com/docs/api-overview.md", + output: "api-overview.md", + }, + { url: "https://turbopuffer.com/docs/write.md", output: "write.md" }, + { url: "https://turbopuffer.com/docs/query.md", output: "query.md" }, + { url: "https://turbopuffer.com/docs/metadata.md", output: "metadata.md" }, + { + url: "https://turbopuffer.com/docs/namespaces.md", + output: "namespaces.md", + }, + { + url: "https://turbopuffer.com/docs/delete-namespace.md", + output: "delete-namespace.md", + }, + { url: "https://turbopuffer.com/docs/recall.md", output: "recall.md" }, + { + url: "https://turbopuffer.com/docs/warm-cache.md", + output: "warm-cache.md", + }, + { url: "https://turbopuffer.com/docs/export.md", output: "export.md" }, + { url: "https://turbopuffer.com/docs/regions.md", output: "regions.md" }, +]; + +mkdirSync(SPECS_DIR, { recursive: true }); +mkdirSync(DOCS_DIR, { recursive: true }); + +/** + * The raw URL for a path in {@link REPO}. Each segment is encoded + * individually so paths containing characters like `(` survive the round + * trip while the separators do not. + */ +const rawUrl = (path: string) => + `https://raw.githubusercontent.com/${REPO}/${REF}/${path + .split("/") + .map(encodeURIComponent) + .join("/")}`; + +const fetchText = async (url: string, accept: string): Promise => { + const response = await fetch(url, { + headers: { + accept, + "user-agent": USER_AGENT, + }, + }); + if (!response.ok) { + throw new Error( + `Failed to fetch ${url}: ${response.status} ${response.statusText}`, + ); + } + return response; +}; + +const writeFile = async (path: string, body: string): Promise => { + mkdirSync(dirname(path), { recursive: true }); + await Bun.write(path, body.endsWith("\n") ? body : `${body}\n`); +}; + +async function main() { + const specUrl = rawUrl(SPEC_PATH); + console.log(`Fetching OpenAPI spec from ${specUrl}...`); + + const yamlText = await ( + await fetchText(specUrl, "text/yaml, text/plain") + ).text(); + const spec = Bun.YAML.parse(yamlText) as Record; + + // Fail here rather than three steps later in the generator: a login page or + // a gutted response is still valid YAML/JSON, but it is not an OpenAPI + // document. + if (typeof spec.openapi !== "string" || spec.paths === undefined) { + throw new Error( + `${specUrl} returned YAML without \`openapi\`/\`paths\` — not an OpenAPI document`, + ); + } + + console.log(`Writing spec to ${OUTPUT_PATH}...`); + // Convert YAML → JSON in the mirror so convert.ts can use JSON.parse. + // 2-space indent + trailing newline so a whitespace-only change upstream + // produces no diff. + await Bun.write(OUTPUT_PATH, JSON.stringify(spec, null, 2) + "\n"); + console.log( + `Done! OpenAPI ${spec.openapi} — ${Object.keys(spec.paths as object).length} paths`, + ); + + console.log(`Fetching vendor docs index from ${DOCS_LLMS_URL}...`); + const llms = await (await fetchText(DOCS_LLMS_URL, "text/plain")).text(); + if (!llms.includes("/docs/api-overview") && !llms.includes("turbopuffer")) { + throw new Error( + `${DOCS_LLMS_URL} did not mention the turbopuffer API — not the vendor docs index`, + ); + } + await writeFile(`${DOCS_DIR}/llms.txt`, llms); + + for (const doc of DOCS) { + console.log(`Fetching ${doc.url}...`); + const text = await ( + await fetchText( + doc.url, + "text/markdown, text/plain;q=0.9, text/html;q=0.5, */*;q=0.1", + ) + ).text(); + if (text.trim().length === 0) { + throw new Error(`${doc.url} returned an empty document`); + } + const outputPath = `${DOCS_DIR}/${doc.output}`; + console.log(`Writing ${outputPath}...`); + await writeFile(outputPath, text); + } + + console.log("Done!"); +} + +main().catch((err) => { + console.error("Fatal error:", err); + process.exit(1); +}); diff --git a/stacks/distilled-submodules/spec-repos/turbopuffer/package.json b/stacks/distilled-submodules/spec-repos/turbopuffer/package.json new file mode 100644 index 000000000..0f715737f --- /dev/null +++ b/stacks/distilled-submodules/spec-repos/turbopuffer/package.json @@ -0,0 +1,27 @@ +{ + "name": "turbopuffer-spec", + "private": true, + "type": "module", + "scripts": { + "fetch-specs": "bun run fetch-specs.ts", + "tsc": "tsc --noEmit", + "lint": "oxlint .", + "fmt": "oxfmt --write .", + "fmt:check": "oxfmt --check .", + "check": "bun run tsc && bun run lint && bun run fmt:check" + }, + "workspaces": { + "catalog": { + "@typescript/native-preview": "latest", + "oxfmt": "0.21.0", + "oxlint": "1.36.0" + } + }, + "dependencies": { + "@typescript/native-preview": "catalog:" + }, + "devDependencies": { + "oxfmt": "catalog:", + "oxlint": "catalog:" + } +} diff --git a/stacks/distilled-submodules/spec-repos/turbopuffer/readme.md b/stacks/distilled-submodules/spec-repos/turbopuffer/readme.md new file mode 100644 index 000000000..128cf0d30 --- /dev/null +++ b/stacks/distilled-submodules/spec-repos/turbopuffer/readme.md @@ -0,0 +1,35 @@ +# spec-mirror-turbopuffer + +A git mirror of the turbopuffer [OpenAPI spec](https://github.com/turbopuffer/turbopuffer-openapi), reduced to exactly the file the +[`@distilled.cloud/turbopuffer`](https://github.com/alchemy-run/distilled) generator reads: + +- `specs/openapi.json` — `openapi.yml` from the `next` branch, converted to JSON + +Vendor API docs from [turbopuffer.com/docs](https://turbopuffer.com/docs/overview) are snapshotted alongside the spec so convert/generate never crawl live pages. + +Nothing else from `turbopuffer/turbopuffer-openapi` is mirrored, so this repository stays small +enough to use as a git submodule — the upstream repository is never cloned. + +The mirror is updated every 24 hours by +[`.github/workflows/update-specs.yml`](./.github/workflows/update-specs.yml). + +## Usage as a submodule + +```sh +git submodule add https://github.com/distilled-mirror/spec-mirror-turbopuffer.git +``` + +## Updating specs + +From `.meta/`: + +```sh +bun install +bun run fetch-specs +``` + +--- + +This repository is managed by the `distilled-submodules` Alchemy stack in +[alchemy-run/distilled](https://github.com/alchemy-run/distilled) (`stacks/distilled-submodules`). +Its scaffolding is generated — edit it there, not here. diff --git a/tsconfig.json b/tsconfig.json index c9a59a925..f9bdd8d68 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -405,6 +405,12 @@ }, { "path": "./packages/trigger-dev/tsconfig.scripts.json" + }, + { + "path": "./packages/turbopuffer/tsconfig.json" + }, + { + "path": "./packages/turbopuffer/tsconfig.scripts.json" } ] }