Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,397 changes: 1,205 additions & 1,192 deletions api/api.gen.go

Large diffs are not rendered by default.

2,325 changes: 1,169 additions & 1,156 deletions api/client/go/client.gen.go

Large diffs are not rendered by default.

24 changes: 18 additions & 6 deletions api/client/javascript/src/client/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5450,21 +5450,27 @@ export interface components {
readonly archivedAt?: Date
/**
* The unique key of the feature
* @description A key is a unique string that is used to identify a resource.
* @description The unique key of the feature
* Useful to reference the feature in external systems.
* For example, your database ID.
*/
key: string
/** The human-readable name of the feature */
/**
* The human-readable name of the feature
* @description The human-readable name of the feature
*/
name: string
/**
* Optional metadata
* @description Optional metadata
* @example {
* "key": "value"
* }
*/
metadata?: components['schemas']['Metadata']
/**
* Meter slug
* @description A key is a unique string that is used to identify a resource.
* @description The meter that the feature is associated with and and based on which usage is calculated.
* @example tokens_total
*/
meterSlug?: string
Comment on lines 5450 to 5476
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Confirm source-of-truth (generated vs. hand-edited).

If this file is generated from OpenAPI/TypeSpec, ensure these doc changes originate in the spec and the client was re-generated; otherwise they’ll be overwritten on the next generation. Also confirm other language clients were regenerated to keep docs in sync.

Run:


🏁 Script executed:

#!/bin/bash
# Verify spec changes and regen consistency

# 1) ExternalKey constraints present (e.g., maxLength: 256) and no leftover key regex
rg -nC2 -e 'ExternalKey' -e 'maxLength:\s*256' -e 'pattern:' api/openapi*.yaml

# 2) No lingering meterKey in specs or clients
rg -nC2 -e '\bmeterKey\b' api/ spec/ packages/ clients/ -g '!**/node_modules/**'

# 3) JS zod validators reflect widened key (256) and no regex
rg -nC2 -e 'z\.\s*string\(\).*max\(\s*256' -e 'regex\(' api/client/javascript/src/zod

# 4) Other clients regenerated (adjust paths if different)
fd -H -t f -g 'schemas.*' api/client | sed -n '1,200p'

Length of output: 278130


Action required — spec/client mismatch: OpenAPI widened ExternalKey to 256 but JS validators still enforce old regex/64‑char constraints

api/openapi.yaml contains ULIDOrExternalKey / ExternalKey with minLength:1 maxLength:256 (e.g. the ULIDOrExternalKey component and the feature "key"), but api/client/javascript/src/zod/index.ts still has .regex() checks and 64‑length constraints and api/client/javascript/src/client/schemas.ts (lines 5450–5476) looks like generated docs that will be overwritten. Regenerate the JavaScript client (and any other language clients), or put the doc/constraint changes into the OpenAPI spec and then regenerate; confirm whether schemas.ts is generated or hand‑edited.

🤖 Prompt for AI Agents
In api/client/javascript/src/client/schemas.ts around lines 5450 to 5476, the
OpenAPI spec widened ULIDOrExternalKey/ExternalKey to minLength:1 maxLength:256
but the generated JS client still enforces the old 64‑char regex/length
constraints (and the docs in schemas.ts appear generated and will be
overwritten). Fix by regenerating the JavaScript client from the updated OpenAPI
spec so schemas.ts and api/client/javascript/src/zod/index.ts reflect the new
1–256 length and remove the old regex checks; if any zod validators were
hand‑edited instead of generated, revert them to generation or update the
OpenAPI component definitions and then regenerate all language
clients-consumers, and confirm whether schemas.ts is generated (if not, update
the source generator/templates) before committing.

Expand Down Expand Up @@ -5493,21 +5499,27 @@ export interface components {
FeatureCreateInputs: {
/**
* The unique key of the feature
* @description A key is a unique string that is used to identify a resource.
* @description The unique key of the feature
* Useful to reference the feature in external systems.
* For example, your database ID.
*/
key: string
/** The human-readable name of the feature */
/**
* The human-readable name of the feature
* @description The human-readable name of the feature
*/
name: string
/**
* Optional metadata
* @description Optional metadata
* @example {
* "key": "value"
* }
*/
metadata?: components['schemas']['Metadata']
/**
* Meter slug
* @description A key is a unique string that is used to identify a resource.
* @description The meter that the feature is associated with and and based on which usage is calculated.
* @example tokens_total
*/
meterSlug?: string
Expand Down
18 changes: 8 additions & 10 deletions api/client/javascript/src/zod/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7903,11 +7903,7 @@ Only meters with SUM and COUNT aggregation are supported for features.
Features cannot be updated later, only archived.
* @summary Create feature
*/
export const createFeatureBodyKeyMax = 64

export const createFeatureBodyKeyRegExp = new RegExp(
'^[a-z0-9]+(?:_[a-z0-9]+)*$'
)
export const createFeatureBodyKeyMax = 256
export const createFeatureBodyMeterSlugMax = 64

export const createFeatureBodyMeterSlugRegExp = new RegExp(
Expand All @@ -7920,16 +7916,16 @@ export const createFeatureBody = zod
.string()
.min(1)
.max(createFeatureBodyKeyMax)
.regex(createFeatureBodyKeyRegExp)
.describe(
'A key is a unique string that is used to identify a resource.'
'The unique key of the feature\nUseful to reference the feature in external systems.\nFor example, your database ID.'
),
metadata: zod
.record(zod.string(), zod.coerce.string())
.describe(
'Set of key-value pairs.\nMetadata can be used to store additional information about a resource.'
)
.optional(),
.optional()
.describe('Optional metadata'),
meterGroupByFilters: zod
.record(zod.string(), zod.coerce.string())
.optional()
Expand All @@ -7943,9 +7939,11 @@ export const createFeatureBody = zod
.regex(createFeatureBodyMeterSlugRegExp)
.optional()
.describe(
'A key is a unique string that is used to identify a resource.'
'The meter that the feature is associated with and and based on which usage is calculated.'
),
name: zod.coerce.string(),
name: zod.coerce
.string()
.describe('The human-readable name of the feature'),
})
.describe(
'Represents a feature that can be enabled or disabled for a plan.\nUsed both for product catalog and entitlements.'
Expand Down
24 changes: 16 additions & 8 deletions api/openapi.cloud.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16629,16 +16629,20 @@ components:
key:
type: string
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
maxLength: 256
description: |-
The unique key of the feature
Useful to reference the feature in external systems.
For example, your database ID.
title: The unique key of the feature
name:
type: string
description: The human-readable name of the feature
title: The human-readable name of the feature
metadata:
allOf:
- $ref: '#/components/schemas/Metadata'
description: Optional metadata
title: Optional metadata
Comment on lines +16632 to 16646
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

External feature key: change looks good; please verify backend/storage and SDK impacts.

Removing the pattern and increasing maxLength to 256 aligns with using an external key. Please verify:

  • DB column sizes, indexes, and unique constraints can handle 256 (and any chars).
  • Server-side validators/DTOs no longer enforce the old snake_case regex.
  • Generated SDKs/docs don’t rely on the old pattern text.

Run this to find lingering 64-char limits or the old regex:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Find 64-length constraints
rg -n -C2 -g '!**/dist/**' -g '!**/build/**' -P '\b(maxLength|varchar|VARCHAR|length)\s*[:( ]\s*64\b'
# Find old snake_case pattern
rg -n -C2 -g '!**/dist/**' -g '!**/build/**' '^[ ]*pattern:\s*\^\[a-z0-9\]\+\(\?:_\[a-z0-9\]\+\)\*\$' api
# Find custom validations mentioning 64 or snake_case
rg -n -C2 -P '\b(64|snake[_ -]?case|slug)\b' --type go --type ts --type tsx --type rs --type py

Length of output: 148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo "Top-level files:"
ls -la | sed -n '1,200p' || true

echo "Git branch (if available):"
git rev-parse --abbrev-ref HEAD 2>/dev/null || true

echo
echo "Show snippet of api/openapi.cloud.yaml (if exists):"
if [ -f api/openapi.cloud.yaml ]; then
  sed -n '16620,16650p' api/openapi.cloud.yaml || true
else
  echo "api/openapi.cloud.yaml not found at that path; searching for openapi*.yaml files..."
  rg -n --hidden --no-ignore-vcs -S 'openapi.*\.ya?ml' || true
fi

echo
echo "Searching for common 64-length constraints (SQL, YAML, code) across repo:"
rg -n --no-ignore-vcs -S -P 'varchar\s*\(\s*64\s*\)|VARCHAR\s*\(\s*64\s*\)|character varying\s*\(?64\)?|\b(maxLength|max_length|maxlength|length)\b[^0-9\n]*\b64\b' || true

echo
echo "Searching for the snake_case regex or YAML 'pattern:' lines that might enforce it:"
rg -n --no-ignore-vcs -S -P '\^\[a-z0-9\]\+(\?:_\[a-z0-9\]\+)*\$|pattern:\s*\^' || true

echo
echo "Searching for mentions of 'snake_case', 'slug', or related validator terms in common source files:"
rg -n --no-ignore-vcs -S -P '\b(snake[_ -]?case|slug|slugify|slug_)\b' --type-add 'code:*.{go,ts,tsx,rs,py,java,kt,sql,yaml,yml,json}' --type code || true

Length of output: 70551


Action required — backend, validators and SDKs must be updated after increasing feature key to 256

Change is present in api/openapi.cloud.yaml (key maxLength: 256) but verification shows many remaining 64-char constraints and snake_case patterns; update everything end-to-end. Key findings and next steps:

  • Specs: many "maxLength: 64" and "pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$" entries remain in api/openapi.yaml and api/openapi.cloud.yaml; api/spec/src/types.tsp contains @maxlength(64). Update schema/type definitions where they apply to key/slug.
  • DB/migrations: migrations reference "slug" (tools/migrate/migrations/20250305025807_add_meter_table.up.sql and 20250306040407_resource_meter.*). Confirm the actual DB column type/length and any unique/index definitions can accept 256 characters and adjust migrations/indexes if needed.
  • Server code: runtime still uses and validates "slug" (e.g., openmeter/meter/meter.go, openmeter/meter/service.go, openmeter/productcatalog/*). Update DTOs/validators and mapstructure/json tags/logic that enforce 64/snake_case.
  • Generated clients & docs: api/client/* (javascript zod, go gen, python) still reference slug and old constraints — regenerate clients and update docs to reflect maxLength=256 and removed pattern.
  • Required actions: replace remaining spec constraints and types.tsp entries, adjust DB/migration/indexes if necessary, update server validators/struct tags, re-generate SDKs, run migrations and full test suite. If backward compatibility is needed, add a compatibility path that accepts both old slug format and the new external key.

example:
key: value
Expand All @@ -16647,7 +16651,7 @@ components:
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
description: The meter that the feature is associated with and and based on which usage is calculated.
title: Meter slug
example: tokens_total
Comment on lines 16651 to 16656
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo and tighten phrasing in meterSlug description.

“and and” is a typo. Suggest clearer wording.

Apply:

-          description: The meter that the feature is associated with and and based on which usage is calculated.
+          description: The meter associated with the feature and used to calculate usage.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
description: The meter that the feature is associated with and and based on which usage is calculated.
title: Meter slug
example: tokens_total
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: The meter associated with the feature and used to calculate usage.
title: Meter slug
example: tokens_total
🤖 Prompt for AI Agents
In api/openapi.cloud.yaml around lines 16651 to 16656, the description for
meterSlug contains a typo ("and and") and is worded awkwardly; update the
description to remove the duplicate word and tighten the phrasing to something
concise and clear such as: "The meter associated with the feature, used to
calculate usage." Replace the existing description line with the corrected text.

meterGroupByFilters:
Expand Down Expand Up @@ -16681,16 +16685,20 @@ components:
key:
type: string
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
maxLength: 256
description: |-
The unique key of the feature
Useful to reference the feature in external systems.
For example, your database ID.
title: The unique key of the feature
name:
type: string
description: The human-readable name of the feature
title: The human-readable name of the feature
metadata:
allOf:
- $ref: '#/components/schemas/Metadata'
description: Optional metadata
title: Optional metadata
example:
key: value
Expand All @@ -16699,7 +16707,7 @@ components:
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
description: The meter that the feature is associated with and and based on which usage is calculated.
title: Meter slug
example: tokens_total
meterGroupByFilters:
Expand Down
24 changes: 16 additions & 8 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17001,16 +17001,20 @@ components:
key:
type: string
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
maxLength: 256
description: |-
The unique key of the feature
Useful to reference the feature in external systems.
For example, your database ID.
title: The unique key of the feature
name:
type: string
description: The human-readable name of the feature
title: The human-readable name of the feature
metadata:
allOf:
- $ref: '#/components/schemas/Metadata'
description: Optional metadata
title: Optional metadata
example:
key: value
Expand All @@ -17019,7 +17023,7 @@ components:
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
description: The meter that the feature is associated with and and based on which usage is calculated.
title: Meter slug
example: tokens_total
meterGroupByFilters:
Expand Down Expand Up @@ -17053,16 +17057,20 @@ components:
key:
type: string
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
maxLength: 256
description: |-
The unique key of the feature
Useful to reference the feature in external systems.
For example, your database ID.
title: The unique key of the feature
name:
type: string
description: The human-readable name of the feature
title: The human-readable name of the feature
metadata:
allOf:
- $ref: '#/components/schemas/Metadata'
description: Optional metadata
title: Optional metadata
example:
key: value
Expand All @@ -17071,7 +17079,7 @@ components:
minLength: 1
maxLength: 64
pattern: ^[a-z0-9]+(?:_[a-z0-9]+)*$
description: A key is a unique string that is used to identify a resource.
description: The meter that the feature is associated with and and based on which usage is calculated.
title: Meter slug
example: tokens_total
meterGroupByFilters:
Expand Down
27 changes: 18 additions & 9 deletions api/spec/src/entitlements/feature.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,33 @@ interface Features {
*/
@friendlyName("FeatureCreateInputs")
model FeatureCreateInputs {
/**
* The unique key of the feature
* Useful to reference the feature in external systems.
* For example, your database ID.
*/
@summary("The unique key of the feature")
key: Key;
key: ExternalKey;

/**
* The human-readable name of the feature
*/
@summary("The human-readable name of the feature")
name: string;

/**
* Optional metadata
*/
@summary("Optional metadata")
@example(#{ key: "value" })
metadata?: Metadata;

// /**
// * The meter that the feature is associated with and and based on which usage is calculated.
// * The meter selected must have SUM or COUNT aggregation.
// */
// @summary("Meter key")
// @example("tokens_total")
// meterKey?: Key;

/**
* The meter that the feature is associated with and and based on which usage is calculated.
* @summary("Meter key")
* @example("tokens_total")
* meterKey?: Key;
*/
@summary("Meter slug")
@example("tokens_total")
meterSlug?: Key;
Expand Down
Loading