fumadocs-openapi 10.3.18 → 10.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/css/generated/shared.css +64 -17
  2. package/dist/i18n.d.ts +100 -0
  3. package/dist/i18n.d.ts.map +1 -0
  4. package/dist/i18n.js +113 -0
  5. package/dist/i18n.js.map +1 -0
  6. package/dist/playground/client.d.ts +1 -1
  7. package/dist/playground/client.d.ts.map +1 -1
  8. package/dist/playground/client.js +40 -30
  9. package/dist/playground/client.js.map +1 -1
  10. package/dist/playground/components/inputs.js +16 -12
  11. package/dist/playground/components/inputs.js.map +1 -1
  12. package/dist/playground/components/oauth-dialog.js +45 -44
  13. package/dist/playground/components/oauth-dialog.js.map +1 -1
  14. package/dist/playground/components/server-select.js +7 -4
  15. package/dist/playground/components/server-select.js.map +1 -1
  16. package/dist/playground/status-info.js +18 -11
  17. package/dist/playground/status-info.js.map +1 -1
  18. package/dist/requests/generators/index.d.ts +1 -1
  19. package/dist/requests/generators/index.js +2 -2
  20. package/dist/requests/generators/index.js.map +1 -1
  21. package/dist/types.d.ts +3 -1
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/ui/base.d.ts +9 -8
  24. package/dist/ui/base.d.ts.map +1 -1
  25. package/dist/ui/base.js +13 -7
  26. package/dist/ui/base.js.map +1 -1
  27. package/dist/ui/client/i18n.js +19 -0
  28. package/dist/ui/client/i18n.js.map +1 -0
  29. package/dist/ui/components/codeblock.d.ts +15 -0
  30. package/dist/ui/components/codeblock.d.ts.map +1 -0
  31. package/dist/ui/components/codeblock.js +27 -0
  32. package/dist/ui/components/codeblock.js.map +1 -0
  33. package/dist/ui/components/dialog.js +17 -13
  34. package/dist/ui/components/dialog.js.map +1 -1
  35. package/dist/ui/full.client.js +6 -7
  36. package/dist/ui/full.client.js.map +1 -1
  37. package/dist/ui/full.d.ts.map +1 -1
  38. package/dist/ui/full.js +8 -4
  39. package/dist/ui/full.js.map +1 -1
  40. package/dist/ui/operation/client.js +7 -8
  41. package/dist/ui/operation/client.js.map +1 -1
  42. package/dist/ui/operation/index.js +46 -23
  43. package/dist/ui/operation/index.js.map +1 -1
  44. package/dist/ui/operation/request-tabs.d.ts.map +1 -1
  45. package/dist/ui/operation/request-tabs.js +9 -8
  46. package/dist/ui/operation/request-tabs.js.map +1 -1
  47. package/dist/ui/operation/response-tabs.d.ts +1 -1
  48. package/dist/ui/operation/response-tabs.d.ts.map +1 -1
  49. package/dist/ui/operation/response-tabs.js +13 -12
  50. package/dist/ui/operation/response-tabs.js.map +1 -1
  51. package/dist/ui/operation/usage-tabs/client.js +4 -5
  52. package/dist/ui/operation/usage-tabs/client.js.map +1 -1
  53. package/dist/ui/schema/client.d.ts.map +1 -1
  54. package/dist/ui/schema/client.js +32 -21
  55. package/dist/ui/schema/client.js.map +1 -1
  56. package/dist/ui/schema/index.d.ts +1 -1
  57. package/dist/ui/schema/index.d.ts.map +1 -1
  58. package/dist/ui/schema/index.js +11 -10
  59. package/dist/ui/schema/index.js.map +1 -1
  60. package/dist/utils/process-document.d.ts +1 -1
  61. package/dist/utils/process-document.js +19 -15
  62. package/dist/utils/process-document.js.map +1 -1
  63. package/package.json +19 -12
@@ -1 +1 @@
1
- {"version":3,"file":"inputs.js","names":[],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronRight, Plus, Trash2, X } from 'lucide-react';\nimport { FieldKey, useArray, useDataEngine, useFieldValue, useObject } from '@fumari/stf';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags } from '@/utils/schema-to-string';\nimport {\n anyFields,\n useFieldInfo,\n useSchemaUtils,\n useSchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { cva } from 'class-variance-authority';\n\nconst fieldLabelVariants = cva('w-full inline-flex items-center gap-0.5');\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: FieldKey;\n} & ComponentProps<'div'>) {\n const { generateDefault } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const schemaPropKeys = field.properties ? Object.keys(field.properties) : [];\n const {\n patternProperties = {},\n additionalProperties,\n 'x-playground-lazy': isLazy = schemaPropKeys.length > 100,\n } = field;\n const isDynamic = Object.keys(patternProperties).length > 0 || additionalProperties;\n\n const [nextName, setNextName] = useState('');\n const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {\n lazy: isLazy,\n defaultValue: () => generateDefault(field) as object,\n properties: field.properties ?? {},\n fallback: additionalProperties,\n patternProperties: patternProperties,\n });\n\n const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];\n\n return (\n <div\n {...props}\n className={cn(\n 'grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last',\n props.className,\n )}\n >\n {isLazy && hiddenProperties.length > 0 && (\n <Select value=\"\" onValueChange={onAppend}>\n <SelectTrigger className=\"col-span-full\">\n <SelectValue placeholder=\"Show Property\" />\n </SelectTrigger>\n <SelectContent>\n {hiddenProperties.map((key) => (\n <SelectItem key={key} value={key}>\n {key}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n\n {properties.map((child) => {\n let toolbar: ReactNode = null;\n if (child.kind === 'pattern' || child.kind === 'fallback') {\n toolbar = (\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n onDelete(child.key);\n }}\n >\n <Trash2 />\n </button>\n );\n }\n\n return (\n <FieldSet\n key={child.key}\n name={child.key}\n field={child.info}\n fieldName={child.field}\n isRequired={field.required?.includes(child.key)}\n toolbar={toolbar}\n />\n );\n })}\n {isDynamic && (\n <div className=\"flex gap-2 order-last col-span-full\">\n <Input\n value={nextName}\n placeholder=\"Enter Property Name\"\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n setNextName('');\n onAppend(nextName);\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={() => {\n onAppend(nextName);\n setNextName('');\n }}\n >\n New\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: FieldKey }) {\n const engine = useDataEngine();\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n engine.update(fieldName, JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: FieldKey;\n}) {\n const [value, setValue] = useFieldValue(fieldName);\n const id = stringifyFieldKey(fieldName);\n if (field.type === 'null') return;\n\n if (field.type === 'string' && field.format === 'binary') {\n return (\n <>\n <label\n htmlFor={id}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">Selected</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">Upload</span>\n )}\n </label>\n <input\n id={id}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files || e.target.files.length === 0) return;\n setValue(e.target.files.item(0));\n }}\n hidden\n />\n </>\n );\n }\n\n if (field.enum && field.enum.length > 0) {\n const idx = field.enum.indexOf(value);\n\n return (\n <Select\n value={idx === -1 && isRequired ? '' : String(idx)}\n onValueChange={(v) => setValue(field.enum![Number(v)])}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue placeholder=\"Select\" />\n </SelectTrigger>\n <SelectContent>\n {field.enum.map((item, i) => (\n <SelectItem key={i} value={String(i)}>\n {typeof item === 'string' ? item : JSON.stringify(item, null, 2)}\n </SelectItem>\n ))}\n {!isRequired && <SelectItem value=\"-1\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => setValue(value === 'undefined' ? undefined : value === 'true')}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">Unset</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n return (\n <Input\n id={id}\n placeholder=\"Enter value\"\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={String(value ?? '')}\n onChange={(e) => {\n if (isNumber) {\n setValue(Number.isNaN(e.target.valueAsNumber) ? undefined : e.target.valueAsNumber);\n } else if (!isNumber) {\n setValue(e.target.value);\n }\n }}\n />\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: FieldKey;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const { generateDefault, schemaToString } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field, depth);\n const id = stringifyFieldKey(fieldName);\n const dataEngine = useDataEngine();\n const [isDefined] = useFieldValue(fieldName, {\n compute(currentValue) {\n return currentValue !== undefined;\n },\n });\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (collapsible && !isDefined && show) setShow(false);\n\n function renderLabelTrigger(schema = field) {\n if (!collapsible) return renderLabelName();\n\n return (\n <button\n type=\"button\"\n className={cn(labelVariants(), 'inline-flex items-center gap-1 font-mono me-auto')}\n onClick={() => {\n dataEngine.init(fieldName, generateDefault(schema));\n setShow((prev) => !prev);\n }}\n >\n <ChevronRight className={cn('size-3.5 text-fd-muted-foreground', show && 'rotate-90')} />\n {name}\n {isRequired && <span className=\"text-red-400/80\">*</span>}\n </button>\n );\n }\n\n function renderLabelName() {\n return (\n <span className={cn(labelVariants(), 'font-mono me-auto')}>\n {name}\n {isRequired && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n }\n\n function renderUnsetButton() {\n return (\n <button\n type=\"button\"\n onClick={() => dataEngine.delete(fieldName)}\n className=\"text-fd-muted-foreground hover:text-fd-accent-foreground\"\n >\n <X className=\"size-3.5\" />\n </button>\n );\n }\n\n if (info.unionField && field[info.unionField] && field[info.unionField]!.length > 0) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n collapsible={collapsible}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n collapsible={collapsible}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (field.type === 'object') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger(field)}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ObjectInput\n field={field}\n fieldName={fieldName}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <label className={fieldLabelVariants()} htmlFor={id}>\n {renderLabelName()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </label>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items: itemSchema,\n ...props\n}: {\n fieldName: FieldKey;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.at(-1) ?? '';\n const { generateDefault } = useSchemaUtils();\n const { items, insertItem, removeItem } = useArray(fieldName);\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {items.map((item) => (\n <FieldSet\n key={item.index}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{item.index}]\n </span>\n }\n field={itemSchema}\n isRequired\n fieldName={item.field}\n toolbar={\n <button\n type=\"button\"\n aria-label=\"Remove Item\"\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => removeItem(item.index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n insertItem(generateDefault(itemSchema));\n }}\n >\n <Plus className=\"size-4\" />\n New Item\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inputs.js","names":[],"sources":["../../../src/playground/components/inputs.tsx"],"sourcesContent":["'use client';\nimport { type ComponentProps, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { ChevronRight, Plus, Trash2, X } from 'lucide-react';\nimport { FieldKey, useArray, useDataEngine, useFieldValue, useObject } from '@fumari/stf';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { FormatFlags } from '@/utils/schema-to-string';\nimport {\n anyFields,\n useFieldInfo,\n useSchemaUtils,\n useSchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport type { ParsedSchema } from '@/utils/schema';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { cva } from 'class-variance-authority';\nimport { useTranslations } from '@/ui/client/i18n';\n\nconst fieldLabelVariants = cva('w-full inline-flex items-center gap-0.5');\n\nfunction FieldLabelType(props: ComponentProps<'code'>) {\n return (\n <code {...props} className={cn('text-xs text-fd-muted-foreground', props.className)}>\n {props.children}\n </code>\n );\n}\n\nexport function ObjectInput({\n field: _field,\n fieldName,\n ...props\n}: {\n field: Exclude<ParsedSchema, boolean>;\n fieldName: FieldKey;\n} & ComponentProps<'div'>) {\n const { generateDefault } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const schemaPropKeys = field.properties ? Object.keys(field.properties) : [];\n const {\n patternProperties = {},\n additionalProperties,\n 'x-playground-lazy': isLazy = schemaPropKeys.length > 100,\n } = field;\n const isDynamic = Object.keys(patternProperties).length > 0 || additionalProperties;\n\n const [nextName, setNextName] = useState('');\n const { properties, onAppend, onDelete, _objectKeys } = useObject(fieldName, {\n lazy: isLazy,\n defaultValue: () => generateDefault(field) as object,\n properties: field.properties ?? {},\n fallback: additionalProperties,\n patternProperties: patternProperties,\n });\n\n const hiddenProperties = isLazy ? schemaPropKeys.filter((key) => !_objectKeys.includes(key)) : [];\n const t = useTranslations();\n\n return (\n <div\n {...props}\n className={cn(\n 'grid grid-cols-1 gap-4 @md:grid-cols-2 *:data-[collapsible=true]:order-last',\n props.className,\n )}\n >\n {isLazy && hiddenProperties.length > 0 && (\n <Select value=\"\" onValueChange={onAppend}>\n <SelectTrigger className=\"col-span-full\">\n <SelectValue placeholder={t.playgroundShowProperty} />\n </SelectTrigger>\n <SelectContent>\n {hiddenProperties.map((key) => (\n <SelectItem key={key} value={key}>\n {key}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n\n {properties.map((child) => {\n let toolbar: ReactNode = null;\n if (child.kind === 'pattern' || child.kind === 'fallback') {\n toolbar = (\n <button\n type=\"button\"\n aria-label={t.playgroundRemoveItem}\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => {\n onDelete(child.key);\n }}\n >\n <Trash2 />\n </button>\n );\n }\n\n return (\n <FieldSet\n key={child.key}\n name={child.key}\n field={child.info}\n fieldName={child.field}\n isRequired={field.required?.includes(child.key)}\n toolbar={toolbar}\n />\n );\n })}\n {isDynamic && (\n <div className=\"flex gap-2 order-last col-span-full\">\n <Input\n value={nextName}\n placeholder={t.playgroundPropertyPlaceholder}\n onChange={(e) => setNextName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n setNextName('');\n onAppend(nextName);\n e.preventDefault();\n }\n }}\n />\n <button\n type=\"button\"\n className={cn(buttonVariants({ color: 'secondary', size: 'sm' }), 'px-4')}\n onClick={() => {\n onAppend(nextName);\n setNextName('');\n }}\n >\n {t.playgroundNewProperty}\n </button>\n </div>\n )}\n </div>\n );\n}\n\nexport function JsonInput({ fieldName }: { fieldName: FieldKey }) {\n const engine = useDataEngine();\n const [error, setError] = useState<string | null>(null);\n const [value, setValue] = useState(() => JSON.stringify(engine.init(fieldName, {}), null, 2));\n\n return (\n <div className=\"flex flex-col bg-fd-secondary text-fd-secondary-foreground overflow-hidden border rounded-lg\">\n <textarea\n value={value}\n className=\"p-2 h-[240px] text-sm font-mono resize-none focus-visible:outline-none\"\n onChange={(v) => {\n setValue(v.target.value);\n try {\n engine.update(fieldName, JSON.parse(v.target.value));\n setError(null);\n } catch (e) {\n if (e instanceof Error) setError(e.message);\n }\n }}\n />\n <p className=\"p-2 text-xs font-mono border-t text-red-400 empty:hidden\">{error}</p>\n </div>\n );\n}\n\nexport function FieldInput({\n field,\n fieldName,\n isRequired,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n field: Exclude<ParsedSchema, boolean>;\n isRequired?: boolean;\n fieldName: FieldKey;\n}) {\n const [value, setValue] = useFieldValue(fieldName);\n const id = stringifyFieldKey(fieldName);\n const t = useTranslations();\n if (field.type === 'null') return;\n\n if (field.type === 'string' && field.format === 'binary') {\n return (\n <>\n <label\n htmlFor={id}\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'w-full h-9 gap-2 truncate',\n }),\n )}\n >\n {value instanceof File ? (\n <>\n <span className=\"text-fd-muted-foreground text-xs\">{t.playgroundSelected}</span>\n <span className=\"truncate w-0 flex-1 text-end\">{value.name}</span>\n </>\n ) : (\n <span className=\"text-fd-muted-foreground\">{t.playgroundInputUpload}</span>\n )}\n </label>\n <input\n id={id}\n type=\"file\"\n multiple={false}\n onChange={(e) => {\n if (!e.target.files || e.target.files.length === 0) return;\n setValue(e.target.files.item(0));\n }}\n hidden\n />\n </>\n );\n }\n\n if (field.enum && field.enum.length > 0) {\n const idx = field.enum.indexOf(value);\n\n return (\n <Select\n value={idx === -1 && isRequired ? '' : String(idx)}\n onValueChange={(v) => setValue(field.enum![Number(v)])}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue placeholder={t.playgroundSelectPlaceholder} />\n </SelectTrigger>\n <SelectContent>\n {field.enum.map((item, i) => (\n <SelectItem key={i} value={String(i)}>\n {typeof item === 'string' ? item : JSON.stringify(item, null, 2)}\n </SelectItem>\n ))}\n {!isRequired && <SelectItem value=\"-1\">{t.playgroundInputUnset}</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n if (field.type === 'boolean') {\n return (\n <Select\n value={String(value)}\n onValueChange={(value) => setValue(value === 'undefined' ? undefined : value === 'true')}\n >\n <SelectTrigger id={id} {...props}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"true\">True</SelectItem>\n <SelectItem value=\"false\">False</SelectItem>\n {!isRequired && <SelectItem value=\"undefined\">{t.playgroundInputUnset}</SelectItem>}\n </SelectContent>\n </Select>\n );\n }\n\n const isNumber = field.type === 'integer' || field.type === 'number';\n return (\n <Input\n id={id}\n placeholder={t.inputPlaceholder}\n type={isNumber ? 'number' : 'text'}\n step={field.type === 'integer' ? 1 : undefined}\n value={String(value ?? '')}\n onChange={(e) => {\n if (isNumber) {\n setValue(Number.isNaN(e.target.valueAsNumber) ? undefined : e.target.valueAsNumber);\n } else if (!isNumber) {\n setValue(e.target.value);\n }\n }}\n />\n );\n}\n\nexport function FieldSet({\n field: _field,\n fieldName,\n toolbar,\n name,\n isRequired,\n depth = 0,\n slotType,\n collapsible = true,\n ...props\n}: HTMLAttributes<HTMLElement> & {\n isRequired?: boolean;\n name?: ReactNode;\n field: ParsedSchema;\n fieldName: FieldKey;\n depth?: number;\n\n slotType?: ReactNode;\n toolbar?: ReactNode;\n collapsible?: boolean;\n}) {\n const { readOnly, writeOnly } = useSchemaScope();\n const { generateDefault, schemaToString } = useSchemaUtils();\n const field = useResolvedSchema(_field);\n const [show, setShow] = useState(!collapsible);\n const { info, updateInfo } = useFieldInfo(fieldName, field, depth);\n const id = stringifyFieldKey(fieldName);\n const dataEngine = useDataEngine();\n const [isDefined] = useFieldValue(fieldName, {\n compute(currentValue) {\n return currentValue !== undefined;\n },\n });\n\n if (_field === false) return;\n if (field.readOnly && !readOnly) return;\n if (field.writeOnly && !writeOnly) return;\n\n if (collapsible && !isDefined && show) setShow(false);\n\n function renderLabelTrigger(schema = field) {\n if (!collapsible) return renderLabelName();\n\n return (\n <button\n type=\"button\"\n className={cn(labelVariants(), 'inline-flex items-center gap-1 font-mono me-auto')}\n onClick={() => {\n dataEngine.init(fieldName, generateDefault(schema));\n setShow((prev) => !prev);\n }}\n >\n <ChevronRight className={cn('size-3.5 text-fd-muted-foreground', show && 'rotate-90')} />\n {name}\n {isRequired && <span className=\"text-red-400/80\">*</span>}\n </button>\n );\n }\n\n function renderLabelName() {\n return (\n <span className={cn(labelVariants(), 'font-mono me-auto')}>\n {name}\n {isRequired && <span className=\"text-red-400/80 mx-1\">*</span>}\n </span>\n );\n }\n\n function renderUnsetButton() {\n return (\n <button\n type=\"button\"\n onClick={() => dataEngine.delete(fieldName)}\n className=\"text-fd-muted-foreground hover:text-fd-accent-foreground\"\n >\n <X className=\"size-3.5\" />\n </button>\n );\n }\n\n if (info.unionField && field[info.unionField] && field[info.unionField]!.length > 0) {\n const union = field[info.unionField]!;\n const showSelect = union.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={union[info.oneOf]}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n collapsible={collapsible}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.oneOf}\n onChange={(e) => {\n updateInfo({\n oneOf: Number(e.target.value),\n });\n }}\n >\n {union.map((item, i) => (\n <option key={i} value={i} className=\"bg-fd-popover text-fd-popover-foreground\">\n {schemaToString(item, FormatFlags.UseAlias)}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (Array.isArray(field.type)) {\n const showSelect = field.type.length > 1;\n\n return (\n <FieldSet\n {...props}\n name={name}\n fieldName={fieldName}\n isRequired={isRequired}\n field={{\n ...field,\n type: info.selectedType,\n }}\n collapsible={collapsible}\n depth={depth + 1}\n slotType={showSelect ? false : slotType}\n toolbar={\n <>\n {showSelect && (\n <select\n className=\"text-xs font-mono\"\n value={info.selectedType}\n onChange={(e) => {\n updateInfo({\n selectedType: e.target.value,\n });\n }}\n >\n {field.type.map((item) => (\n <option\n key={item}\n value={item}\n className=\"bg-fd-popover text-fd-popover-foreground\"\n >\n {item}\n </option>\n ))}\n </select>\n )}\n {toolbar}\n </>\n }\n />\n );\n }\n\n if (field.type === 'object') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full @container', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger(field)}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ObjectInput\n field={field}\n fieldName={fieldName}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n if (field.type === 'array') {\n return (\n <fieldset\n {...props}\n data-collapsible={collapsible}\n className={cn('flex flex-col gap-1.5 col-span-full', props.className)}\n >\n <div className={fieldLabelVariants()}>\n {renderLabelTrigger()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </div>\n {show && (\n <ArrayInput\n fieldName={fieldName}\n items={field.items ?? anyFields}\n className=\"rounded-lg border border-fd-primary/20 bg-fd-background/50 p-2 shadow-sm\"\n />\n )}\n </fieldset>\n );\n }\n\n return (\n <fieldset {...props} className={cn('flex flex-col gap-1.5', props.className)}>\n <label className={fieldLabelVariants()} htmlFor={id}>\n {renderLabelName()}\n {slotType ?? <FieldLabelType>{schemaToString(field)}</FieldLabelType>}\n {toolbar}\n {!isRequired && isDefined && renderUnsetButton()}\n </label>\n <FieldInput field={field} fieldName={fieldName} isRequired={isRequired} />\n </fieldset>\n );\n}\n\nfunction ArrayInput({\n fieldName,\n items: itemSchema,\n ...props\n}: {\n fieldName: FieldKey;\n items: ParsedSchema;\n} & ComponentProps<'div'>) {\n const name = fieldName.at(-1) ?? '';\n const { generateDefault } = useSchemaUtils();\n const { items, insertItem, removeItem } = useArray(fieldName);\n const t = useTranslations();\n\n return (\n <div {...props} className={cn('flex flex-col gap-2', props.className)}>\n {items.map((item) => (\n <FieldSet\n key={item.index}\n name={\n <span className=\"text-fd-muted-foreground\">\n {name}[{item.index}]\n </span>\n }\n field={itemSchema}\n isRequired\n fieldName={item.field}\n toolbar={\n <button\n type=\"button\"\n aria-label={t.playgroundRemoveItem}\n className={cn(\n buttonVariants({\n color: 'outline',\n size: 'icon-xs',\n }),\n )}\n onClick={() => removeItem(item.index)}\n >\n <Trash2 />\n </button>\n }\n />\n ))}\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n className: 'gap-1.5 py-2',\n size: 'sm',\n }),\n )}\n onClick={() => {\n insertItem(generateDefault(itemSchema));\n }}\n >\n <Plus className=\"size-4\" />\n {t.playgroundNewItem}\n </button>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -2,44 +2,45 @@ import { cn } from "../../utils/cn.js";
2
2
  import { useQuery } from "../../utils/use-query.js";
3
3
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
4
4
  import { Input, labelVariants } from "../../ui/components/input.js";
5
+ import { useTranslations } from "../../ui/client/i18n.js";
5
6
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
6
- import { useEffect, useState } from "react";
7
+ import { useEffect, useMemo, useState } from "react";
7
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
9
  import { buttonVariants } from "fumadocs-ui/components/ui/button";
9
10
  import { useForm } from "react-hook-form";
10
11
  //#region src/playground/components/oauth-dialog.tsx
11
- const FlowTypes = {
12
- password: {
13
- name: "Resource Owner Password Flow",
14
- description: "Authenticate using username and password.",
15
- supported: true
16
- },
17
- clientCredentials: {
18
- name: "Client Credentials",
19
- description: "Intended for the server-to-server authentication.",
20
- supported: true
21
- },
22
- authorizationCode: {
23
- name: "Authorization code",
24
- description: "Authenticate with 3rd party services",
25
- supported: true
26
- },
27
- implicit: {
28
- name: "Implicit",
29
- description: "Retrieve the access token directly.",
30
- supported: true
31
- },
32
- deviceAuthorization: {
33
- name: "Device Authorization",
34
- description: "Authenticate with device.",
35
- supported: false
36
- }
37
- };
38
12
  function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
39
13
  const [type, setType] = useState(() => {
40
14
  return Object.keys(scheme.flows)[0];
41
15
  });
42
- const { supported } = FlowTypes[type];
16
+ const t = useTranslations();
17
+ const allFlows = useMemo(() => ({
18
+ password: {
19
+ name: t.resourceOwnerPassword,
20
+ description: t.resourceOwnerPasswordDesc,
21
+ supported: true
22
+ },
23
+ clientCredentials: {
24
+ name: t.clientCredentials,
25
+ description: t.clientCredentialsDesc,
26
+ supported: true
27
+ },
28
+ authorizationCode: {
29
+ name: t.authorizationCode,
30
+ description: t.authorizationCodeDesc,
31
+ supported: true
32
+ },
33
+ implicit: {
34
+ name: t.implicit,
35
+ description: t.implicitDesc,
36
+ supported: true
37
+ },
38
+ deviceAuthorization: {
39
+ name: t.deviceAuthorization,
40
+ description: t.deviceAuthorizationDesc,
41
+ supported: false
42
+ }
43
+ }), [t]);
43
44
  const form = useForm({ defaultValues: {
44
45
  clientId: "",
45
46
  clientSecret: "",
@@ -164,7 +165,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
164
165
  return /* @__PURE__ */ jsxs(Dialog, {
165
166
  open,
166
167
  onOpenChange: setOpen,
167
- children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Authorization" }), /* @__PURE__ */ jsx(DialogDescription, { children: "Obtain the access token for API." })] }), /* @__PURE__ */ jsxs("form", {
168
+ children: [children, /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.authorization }), /* @__PURE__ */ jsx(DialogDescription, { children: t.obtainAccessToken })] }), /* @__PURE__ */ jsxs("form", {
168
169
  className: "flex flex-col gap-6",
169
170
  onSubmit: (e) => {
170
171
  onSubmit(e);
@@ -175,7 +176,7 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
175
176
  value: type,
176
177
  onValueChange: setType,
177
178
  children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(scheme.flows).map((key) => {
178
- const { name, description } = FlowTypes[key];
179
+ const { name, description } = allFlows[key];
179
180
  return /* @__PURE__ */ jsxs(SelectItem, {
180
181
  value: key,
181
182
  children: [/* @__PURE__ */ jsx("p", {
@@ -194,15 +195,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
194
195
  /* @__PURE__ */ jsx("label", {
195
196
  htmlFor: "client_id",
196
197
  className: cn(labelVariants()),
197
- children: "Client ID"
198
+ children: t.clientId
198
199
  }),
199
200
  /* @__PURE__ */ jsx("p", {
200
201
  className: "text-fd-muted-foreground text-sm",
201
- children: "The client ID of your OAuth application."
202
+ children: t.clientIdHint
202
203
  }),
203
204
  /* @__PURE__ */ jsx(Input, {
204
205
  id: "client_id",
205
- placeholder: "Enter value",
206
+ placeholder: t.inputPlaceholder,
206
207
  type: "text",
207
208
  autoComplete: "off",
208
209
  disabled: isLoading,
@@ -216,15 +217,15 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
216
217
  /* @__PURE__ */ jsx("label", {
217
218
  htmlFor: "client_secret",
218
219
  className: cn(labelVariants()),
219
- children: "Client Secret"
220
+ children: t.clientSecret
220
221
  }),
221
222
  /* @__PURE__ */ jsx("p", {
222
223
  className: "text-fd-muted-foreground text-sm",
223
- children: "The client secret of your OAuth application."
224
+ children: t.clientSecretHint
224
225
  }),
225
226
  /* @__PURE__ */ jsx(Input, {
226
227
  id: "client_secret",
227
- placeholder: "Enter value",
228
+ placeholder: t.inputPlaceholder,
228
229
  type: "password",
229
230
  autoComplete: "off",
230
231
  disabled: isLoading,
@@ -237,10 +238,10 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
237
238
  children: [/* @__PURE__ */ jsx("label", {
238
239
  htmlFor: "username",
239
240
  className: cn(labelVariants()),
240
- children: "Username"
241
+ children: t.usernameField
241
242
  }), /* @__PURE__ */ jsx(Input, {
242
243
  id: "username",
243
- placeholder: "Enter value",
244
+ placeholder: t.inputPlaceholder,
244
245
  type: "text",
245
246
  disabled: isLoading,
246
247
  autoComplete: "off",
@@ -251,27 +252,27 @@ function OauthDialog({ scheme, scopes, setToken, children, open, setOpen }) {
251
252
  children: [/* @__PURE__ */ jsx("label", {
252
253
  htmlFor: "password",
253
254
  className: cn(labelVariants()),
254
- children: "Client Secret"
255
+ children: t.clientSecret
255
256
  }), /* @__PURE__ */ jsx(Input, {
256
257
  id: "password",
257
- placeholder: "Enter value",
258
+ placeholder: t.inputPlaceholder,
258
259
  type: "password",
259
260
  autoComplete: "off",
260
261
  disabled: isLoading,
261
262
  ...form.register("password", { required: true })
262
263
  })]
263
264
  })] }),
264
- supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
265
+ allFlows[type].supported ? /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("p", {
265
266
  className: "text-red-400 font-medium text-sm",
266
267
  children: String(error)
267
268
  }) : null, /* @__PURE__ */ jsx("button", {
268
269
  type: "submit",
269
270
  disabled: isLoading,
270
271
  className: cn(buttonVariants({ color: "primary" })),
271
- children: authCodeCallback.isLoading ? "Fetching token..." : "Submit"
272
+ children: authCodeCallback.isLoading ? t.fetchingToken : t.submit
272
273
  })] }) : /* @__PURE__ */ jsx("p", {
273
274
  className: "text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border",
274
- children: "Unsupported"
275
+ children: t.unsupported
275
276
  })
276
277
  ]
277
278
  })] })]
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\nconst FlowTypes = {\n password: {\n name: 'Resource Owner Password Flow',\n description: 'Authenticate using username and password.',\n supported: true,\n },\n clientCredentials: {\n name: 'Client Credentials',\n description: 'Intended for the server-to-server authentication.',\n supported: true,\n },\n authorizationCode: {\n name: 'Authorization code',\n description: 'Authenticate with 3rd party services',\n supported: true,\n },\n implicit: {\n name: 'Implicit',\n description: 'Retrieve the access token directly.',\n supported: true,\n },\n deviceAuthorization: {\n name: 'Device Authorization',\n description: 'Authenticate with device.',\n supported: false,\n },\n} as const;\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const { supported } = FlowTypes[type];\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Authorization</DialogTitle>\n <DialogDescription>Obtain the access token for API.</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = FlowTypes[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n Client ID\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client ID of your OAuth application.\n </p>\n <Input\n id=\"client_id\"\n placeholder=\"Enter value\"\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">\n The client secret of your OAuth application.\n </p>\n <Input\n id=\"client_secret\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n Username\n </label>\n <Input\n id=\"username\"\n placeholder=\"Enter value\"\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n Client Secret\n </label>\n <Input\n id=\"password\"\n placeholder=\"Enter value\"\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? 'Fetching token...' : 'Submit'}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n Unsupported\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
1
+ {"version":3,"file":"oauth-dialog.js","names":[],"sources":["../../../src/playground/components/oauth-dialog.tsx"],"sourcesContent":["import {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { useForm } from 'react-hook-form';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useQuery } from '@/utils/use-query';\nimport { type ReactNode, useEffect, useMemo, useState } from 'react';\nimport { cn } from '@/utils/cn';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport type { OAuth2SecurityScheme } from '@/types';\nimport { useTranslations } from '@/ui/client/i18n';\n\ntype FlowType = keyof NonNullable<OAuth2SecurityScheme['flows']>;\n\nexport interface AuthDialogProps {\n scheme: OAuth2SecurityScheme;\n scopes: string[];\n\n open: boolean;\n setOpen: (v: boolean) => void;\n setToken: (token: string) => void;\n children: ReactNode;\n}\n\ninterface FormValues {\n clientId: string;\n clientSecret: string;\n username: string;\n password: string;\n}\n\ninterface AuthCodeState {\n redirect_uri: string;\n client_id: string;\n client_secret: string;\n}\n\ninterface ImplicitState {\n redirect_uri: string;\n client_id: string;\n}\n\ninterface FlowInfo {\n name: ReactNode;\n description: ReactNode;\n supported: boolean;\n}\n\nexport function OauthDialog({\n scheme,\n scopes,\n setToken,\n children,\n open,\n setOpen,\n}: AuthDialogProps) {\n const [type, setType] = useState(() => {\n return Object.keys(scheme.flows!)[0] as FlowType;\n });\n const t = useTranslations();\n const allFlows: Record<FlowType, FlowInfo> = useMemo(\n () => ({\n password: {\n name: t.resourceOwnerPassword,\n description: t.resourceOwnerPasswordDesc,\n supported: true,\n },\n clientCredentials: {\n name: t.clientCredentials,\n description: t.clientCredentialsDesc,\n supported: true,\n },\n authorizationCode: {\n name: t.authorizationCode,\n description: t.authorizationCodeDesc,\n supported: true,\n },\n implicit: {\n name: t.implicit,\n description: t.implicitDesc,\n supported: true,\n },\n deviceAuthorization: {\n name: t.deviceAuthorization,\n description: t.deviceAuthorizationDesc,\n supported: false,\n },\n }),\n [t],\n );\n\n const form = useForm<FormValues>({\n defaultValues: {\n clientId: '',\n clientSecret: '',\n username: '',\n password: '',\n },\n });\n\n const authCodeCallback = useQuery(async (code: string, state: AuthCodeState) => {\n const value = scheme.flows!.authorizationCode!;\n\n const res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n // note: `state` could be invalid, but server will check it\n redirect_uri: state.redirect_uri,\n client_id: state.client_id,\n client_secret: state.client_secret,\n }),\n });\n\n if (!res.ok) throw new Error(await res.text());\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n });\n\n useEffect(() => {\n if (scheme.flows!.authorizationCode) {\n const params = new URLSearchParams(window.location.search);\n const state = params.get('state');\n const code = params.get('code');\n\n if (state && code) {\n const parsedState = JSON.parse(state) as AuthCodeState;\n setOpen(true);\n\n form.setValue('clientId', parsedState.client_id);\n form.setValue('clientSecret', parsedState.client_secret);\n authCodeCallback.start(code, parsedState);\n window.history.replaceState(null, '', window.location.pathname);\n return;\n }\n }\n\n if (scheme.flows!.implicit && window.location.hash.length > 1) {\n const params = new URLSearchParams(window.location.hash.slice(1));\n const state = params.get('state');\n const token = params.get('access_token');\n const type = params.get('token_type') ?? 'Bearer';\n\n if (state && token) {\n const parsedState = JSON.parse(state) as ImplicitState;\n\n form.setValue('clientId', parsedState.client_id);\n setToken(`${type} ${token}`);\n window.history.replaceState(null, '', window.location.pathname);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- first page load only\n }, []);\n\n const authorize = useQuery(async (values: FormValues) => {\n if (type === 'implicit') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'token');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n redirect_uri: window.location.href,\n } satisfies ImplicitState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n if (type === 'authorizationCode') {\n const value = scheme.flows![type]!;\n\n const params = new URLSearchParams();\n params.set('response_type', 'code');\n params.set('client_id', values.clientId);\n params.set('redirect_uri', window.location.href);\n params.set('scope', scopes.join('+'));\n params.set(\n 'state',\n JSON.stringify({\n client_id: values.clientId,\n client_secret: values.clientSecret,\n redirect_uri: window.location.href,\n } satisfies AuthCodeState),\n );\n\n window.location.replace(`${value.authorizationUrl}?${params.toString()}`);\n return;\n }\n\n let res;\n if (type === 'password') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'password',\n username: values.username,\n password: values.password,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (type === 'clientCredentials') {\n const value = scheme.flows![type]!;\n\n res = await fetch(value.tokenUrl!, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: values.clientId,\n client_secret: values.clientSecret,\n scope: scopes.join('+'),\n }),\n });\n }\n\n if (res) {\n if (!res.ok) throw new Error(await res.text());\n\n const { access_token, token_type = 'Bearer' } = (await res.json()) as {\n access_token: string;\n token_type?: string;\n };\n\n setToken(`${token_type} ${access_token}`);\n setOpen(false);\n }\n });\n\n const onSubmit = form.handleSubmit((values) => {\n return authorize.start(values);\n });\n\n const isLoading = authorize.isLoading || authCodeCallback.isLoading;\n const error = authCodeCallback.error ?? authorize.error;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n {children}\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.authorization}</DialogTitle>\n <DialogDescription>{t.obtainAccessToken}</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-6\"\n onSubmit={(e) => {\n void onSubmit(e);\n e.stopPropagation();\n }}\n >\n <Select value={type} onValueChange={setType as (s: string) => void}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(scheme.flows!).map((key) => {\n const { name, description } = allFlows[key as FlowType];\n\n return (\n <SelectItem key={key} value={key}>\n <p className=\"font-medium\">{name}</p>\n <p className=\"text-fd-muted-foreground\">{description}</p>\n </SelectItem>\n );\n })}\n </SelectContent>\n </Select>\n\n {(type === 'authorizationCode' ||\n type === 'clientCredentials' ||\n type === 'implicit') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_id\" className={cn(labelVariants())}>\n {t.clientId}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientIdHint}</p>\n <Input\n id=\"client_id\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientId', { required: true })}\n />\n </fieldset>\n )}\n {(type === 'authorizationCode' || type === 'clientCredentials') && (\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"client_secret\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <p className=\"text-fd-muted-foreground text-sm\">{t.clientSecretHint}</p>\n <Input\n id=\"client_secret\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('clientSecret', { required: true })}\n />\n </fieldset>\n )}\n {type === 'password' && (\n <>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"username\" className={cn(labelVariants())}>\n {t.usernameField}\n </label>\n <Input\n id=\"username\"\n placeholder={t.inputPlaceholder}\n type=\"text\"\n disabled={isLoading}\n autoComplete=\"off\"\n {...form.register('username', { required: true })}\n />\n </fieldset>\n <fieldset className=\"flex flex-col gap-1.5\">\n <label htmlFor=\"password\" className={cn(labelVariants())}>\n {t.clientSecret}\n </label>\n <Input\n id=\"password\"\n placeholder={t.inputPlaceholder}\n type=\"password\"\n autoComplete=\"off\"\n disabled={isLoading}\n {...form.register('password', { required: true })}\n />\n </fieldset>\n </>\n )}\n {allFlows[type].supported ? (\n <>\n {error ? <p className=\"text-red-400 font-medium text-sm\">{String(error)}</p> : null}\n <button\n type=\"submit\"\n disabled={isLoading}\n className={cn(\n buttonVariants({\n color: 'primary',\n }),\n )}\n >\n {authCodeCallback.isLoading ? t.fetchingToken : t.submit}\n </button>\n </>\n ) : (\n <p className=\"text-fd-muted-foreground bg-fd-muted p-2 rounded-lg border\">\n {t.unsupported}\n </p>\n )}\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport const OauthDialogTrigger = DialogTrigger;\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ import { useServerContext, useServerSelectContext } from "../../ui/contexts/api.
4
4
  import { cn } from "../../utils/cn.js";
5
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/components/select.js";
6
6
  import { Input, labelVariants } from "../../ui/components/input.js";
7
+ import { useTranslations } from "../../ui/client/i18n.js";
7
8
  import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../ui/components/dialog.js";
8
9
  import { useEffect, useRef, useState } from "react";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -15,6 +16,7 @@ function ServerSelect(props) {
15
16
  const { server, setServer, setServerVariables } = useServerSelectContext();
16
17
  const [open, setOpen] = useState(false);
17
18
  const [isMounted, setIsMounted] = useState(false);
19
+ const t = useTranslations();
18
20
  useEffect(() => {
19
21
  setIsMounted(true);
20
22
  }, []);
@@ -29,16 +31,16 @@ function ServerSelect(props) {
29
31
  children: [
30
32
  /* @__PURE__ */ jsx("span", {
31
33
  className: "px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm",
32
- children: server?.name ?? "Server URL"
34
+ children: server?.name ?? t.serverUrl
33
35
  }),
34
36
  /* @__PURE__ */ jsx("code", {
35
37
  className: "truncate min-w-0 flex-1",
36
- children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : "loading..."
38
+ children: isMounted ? withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin) : t.loading
37
39
  }),
38
40
  /* @__PURE__ */ jsx(EditIcon, { className: "size-4" })
39
41
  ]
40
42
  }), /* @__PURE__ */ jsxs(DialogContent, { children: [
41
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Server URL" }), /* @__PURE__ */ jsx(DialogDescription, { children: "The base URL of your API endpoint." })] }),
43
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: t.serverUrl }), /* @__PURE__ */ jsx(DialogDescription, { children: t.serverUrlDescription })] }),
42
44
  /* @__PURE__ */ jsxs(Select, {
43
45
  value: server?.url,
44
46
  onValueChange: setServer,
@@ -99,6 +101,7 @@ function ServerSelectContent({ defaultValues, onChange, schema }) {
99
101
  });
100
102
  }
101
103
  function Field({ fieldName, variable }) {
104
+ const t = useTranslations();
102
105
  const [value, setValue] = useFieldValue([fieldName], { compute(currentValue) {
103
106
  return typeof currentValue === "string" ? currentValue : void 0;
104
107
  } });
@@ -117,7 +120,7 @@ function Field({ fieldName, variable }) {
117
120
  id: fieldName,
118
121
  value,
119
122
  onChange: (e) => setValue(e.target.value),
120
- placeholder: "Enter Value"
123
+ placeholder: t.serverUrlFieldPlaceholder
121
124
  });
122
125
  }
123
126
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ?? 'Server URL'}\n </span>\n <code className=\"truncate min-w-0 flex-1\">\n {isMounted\n ? withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n )\n : 'loading...'}\n </code>\n <EditIcon className=\"size-4\" />\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Server URL</DialogTitle>\n <DialogDescription>The base URL of your API endpoint.</DialogDescription>\n </DialogHeader>\n <Select value={server?.url} onValueChange={setServer}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {servers.map((item) => (\n <SelectItem key={item.url} value={item.url!}>\n <code className=\"text-[0.8125rem]\">{item.url}</code>\n <p className=\"text-fd-muted-foreground\">{item.description}</p>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {server?.variables && serverSchema?.variables && (\n <ServerSelectContent\n key={server.url}\n defaultValues={server.variables}\n schema={serverSchema.variables}\n onChange={setServerVariables}\n />\n )}\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ServerSelectContent({\n defaultValues,\n onChange,\n schema,\n}: {\n defaultValues: Record<string, string>;\n onChange: (values: Record<string, string>) => void;\n schema: Record<string, NoReference<ServerVariableObject>>;\n}) {\n const stf = useStf({\n defaultValues: () => structuredClone(defaultValues),\n });\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n\n timerRef.current = window.setTimeout(\n () => onChange(stf.dataEngine.getData() as Record<string, string>),\n 500,\n );\n },\n });\n\n return (\n <StfProvider value={stf}>\n <div className=\"flex flex-col gap-4\">\n {Object.entries(schema).map(([key, variable]) => {\n return (\n <fieldset key={key} className=\"flex flex-col gap-1\">\n <label className={cn(labelVariants())} htmlFor={key}>\n {key}\n </label>\n <p className=\"text-xs text-fd-muted-foreground empty:hidden\">\n {variable.description}\n </p>\n <Field fieldName={key} variable={variable} />\n </fieldset>\n );\n })}\n </div>\n </StfProvider>\n );\n}\n\nfunction Field({\n fieldName,\n variable,\n}: {\n variable: NoReference<ServerVariableObject>;\n fieldName: string;\n}) {\n const [value, setValue] = useFieldValue([fieldName], {\n compute(currentValue) {\n return typeof currentValue === 'string' ? currentValue : undefined;\n },\n });\n\n if (variable.enum) {\n return (\n <Select value={value} onValueChange={setValue}>\n <SelectTrigger id={fieldName}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {variable.enum.map((value) => (\n <SelectItem key={value} value={String(value)}>\n {value}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n }\n\n return (\n <Input\n id={fieldName}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Enter Value\"\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server-select.js","names":[],"sources":["../../../src/playground/components/server-select.tsx"],"sourcesContent":["'use client';\nimport { useServerContext, useServerSelectContext } from '@/ui/contexts/api';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { Input, labelVariants } from '@/ui/components/input';\nimport { useEffect, useState, useRef, type ComponentProps } from 'react';\nimport { cn } from '@/utils/cn';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from '@/ui/components/dialog';\nimport { resolveServerUrl, withBase } from '@/utils/url';\nimport type { ServerVariableObject } from '@/types';\nimport type { NoReference } from '@/utils/schema';\nimport { StfProvider, useFieldValue, useListener, useStf } from '@fumari/stf';\nimport { EditIcon } from 'lucide-react';\nimport { useTranslations } from '@/ui/client/i18n';\n\nexport default function ServerSelect(props: ComponentProps<typeof DialogTrigger>) {\n const { servers } = useServerContext();\n const { server, setServer, setServerVariables } = useServerSelectContext();\n const [open, setOpen] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const t = useTranslations();\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n if (servers.length <= 0) return;\n const serverSchema = server ? servers.find((obj) => obj.url === server.url) : null;\n\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger\n {...props}\n className={cn(\n 'flex items-center gap-2 text-sm text-start px-3 py-2 bg-fd-muted text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground',\n props.className,\n )}\n >\n <span className=\"px-2 py-0.5 -ms-2 font-medium rounded-lg border bg-fd-secondary text-fd-secondary-foreground shadow-sm\">\n {server?.name ?? t.serverUrl}\n </span>\n <code className=\"truncate min-w-0 flex-1\">\n {isMounted\n ? withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n )\n : t.loading}\n </code>\n <EditIcon className=\"size-4\" />\n </DialogTrigger>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>{t.serverUrl}</DialogTitle>\n <DialogDescription>{t.serverUrlDescription}</DialogDescription>\n </DialogHeader>\n <Select value={server?.url} onValueChange={setServer}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {servers.map((item) => (\n <SelectItem key={item.url} value={item.url!}>\n <code className=\"text-[0.8125rem]\">{item.url}</code>\n <p className=\"text-fd-muted-foreground\">{item.description}</p>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {server?.variables && serverSchema?.variables && (\n <ServerSelectContent\n key={server.url}\n defaultValues={server.variables}\n schema={serverSchema.variables}\n onChange={setServerVariables}\n />\n )}\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ServerSelectContent({\n defaultValues,\n onChange,\n schema,\n}: {\n defaultValues: Record<string, string>;\n onChange: (values: Record<string, string>) => void;\n schema: Record<string, NoReference<ServerVariableObject>>;\n}) {\n const stf = useStf({\n defaultValues: () => structuredClone(defaultValues),\n });\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n\n timerRef.current = window.setTimeout(\n () => onChange(stf.dataEngine.getData() as Record<string, string>),\n 500,\n );\n },\n });\n\n return (\n <StfProvider value={stf}>\n <div className=\"flex flex-col gap-4\">\n {Object.entries(schema).map(([key, variable]) => {\n return (\n <fieldset key={key} className=\"flex flex-col gap-1\">\n <label className={cn(labelVariants())} htmlFor={key}>\n {key}\n </label>\n <p className=\"text-xs text-fd-muted-foreground empty:hidden\">\n {variable.description}\n </p>\n <Field fieldName={key} variable={variable} />\n </fieldset>\n );\n })}\n </div>\n </StfProvider>\n );\n}\n\nfunction Field({\n fieldName,\n variable,\n}: {\n variable: NoReference<ServerVariableObject>;\n fieldName: string;\n}) {\n const t = useTranslations();\n const [value, setValue] = useFieldValue([fieldName], {\n compute(currentValue) {\n return typeof currentValue === 'string' ? currentValue : undefined;\n },\n });\n\n if (variable.enum) {\n return (\n <Select value={value} onValueChange={setValue}>\n <SelectTrigger id={fieldName}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {variable.enum.map((value) => (\n <SelectItem key={value} value={String(value)}>\n {value}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n }\n\n return (\n <Input\n id={fieldName}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder={t.serverUrlFieldPlaceholder}\n />\n );\n}\n"],"mappings":"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"}
@@ -1,46 +1,53 @@
1
1
  import { CircleCheck, CircleX } from "lucide-react";
2
2
  //#region src/playground/status-info.tsx
3
- const statusMap = {
3
+ const statusKeys = {
4
4
  400: {
5
- description: "Bad Request",
5
+ key: "statusBadRequest",
6
6
  color: "text-red-500",
7
7
  icon: CircleX
8
8
  },
9
9
  401: {
10
- description: "Unauthorized",
10
+ key: "statusUnauthorized",
11
11
  color: "text-red-500",
12
12
  icon: CircleX
13
13
  },
14
14
  403: {
15
- description: "Forbidden",
15
+ key: "statusForbidden",
16
16
  color: "text-red-500",
17
17
  icon: CircleX
18
18
  },
19
19
  404: {
20
- description: "Not Found",
20
+ key: "statusNotFound",
21
21
  color: "text-fd-muted-foreground",
22
22
  icon: CircleX
23
23
  },
24
24
  500: {
25
- description: "Internal Server Error",
25
+ key: "statusInternalServerError",
26
26
  color: "text-red-500",
27
27
  icon: CircleX
28
28
  }
29
29
  };
30
- function getStatusInfo(status) {
31
- if (status in statusMap) return statusMap[status];
30
+ function getStatusInfo(status, t) {
31
+ if (status in statusKeys) {
32
+ const { key, color, icon } = statusKeys[status];
33
+ return {
34
+ description: t[key],
35
+ color,
36
+ icon
37
+ };
38
+ }
32
39
  if (status >= 200 && status < 300) return {
33
- description: "Successful",
40
+ description: t.statusSuccessful,
34
41
  color: "text-green-500",
35
42
  icon: CircleCheck
36
43
  };
37
44
  if (status >= 400) return {
38
- description: "Error",
45
+ description: t.statusError,
39
46
  color: "text-red-500",
40
47
  icon: CircleX
41
48
  };
42
49
  return {
43
- description: "No Description",
50
+ description: t.statusNoDescription,
44
51
  color: "text-fd-muted-foreground",
45
52
  icon: CircleX
46
53
  };
@@ -1 +1 @@
1
- {"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst statusMap: Record<number, StatusInfo> = {\n 400: { description: 'Bad Request', color: 'text-red-500', icon: CircleX },\n 401: {\n description: 'Unauthorized',\n color: 'text-red-500',\n icon: CircleX,\n },\n 403: { description: 'Forbidden', color: 'text-red-500', icon: CircleX },\n 404: {\n description: 'Not Found',\n color: 'text-fd-muted-foreground',\n icon: CircleX,\n },\n 500: {\n description: 'Internal Server Error',\n color: 'text-red-500',\n icon: CircleX,\n },\n};\n\nexport function getStatusInfo(status: number): StatusInfo {\n if (status in statusMap) {\n return statusMap[status];\n }\n\n if (status >= 200 && status < 300) {\n return {\n description: 'Successful',\n color: 'text-green-500',\n icon: CircleCheck,\n };\n }\n\n if (status >= 400) {\n return { description: 'Error', color: 'text-red-500', icon: CircleX };\n }\n\n return {\n description: 'No Description',\n color: 'text-fd-muted-foreground',\n icon: CircleX,\n };\n}\n"],"mappings":";;AAQA,MAAM,YAAwC;CAC5C,KAAK;EAAE,aAAa;EAAe,OAAO;EAAgB,MAAM;EAAS;CACzE,KAAK;EACH,aAAa;EACb,OAAO;EACP,MAAM;EACP;CACD,KAAK;EAAE,aAAa;EAAa,OAAO;EAAgB,MAAM;EAAS;CACvE,KAAK;EACH,aAAa;EACb,OAAO;EACP,MAAM;EACP;CACD,KAAK;EACH,aAAa;EACb,OAAO;EACP,MAAM;EACP;CACF;AAED,SAAgB,cAAc,QAA4B;AACxD,KAAI,UAAU,UACZ,QAAO,UAAU;AAGnB,KAAI,UAAU,OAAO,SAAS,IAC5B,QAAO;EACL,aAAa;EACb,OAAO;EACP,MAAM;EACP;AAGH,KAAI,UAAU,IACZ,QAAO;EAAE,aAAa;EAAS,OAAO;EAAgB,MAAM;EAAS;AAGvE,QAAO;EACL,aAAa;EACb,OAAO;EACP,MAAM;EACP"}
1
+ {"version":3,"file":"status-info.js","names":[],"sources":["../../src/playground/status-info.tsx"],"sourcesContent":["import { CircleCheck, CircleX } from 'lucide-react';\nimport type { Translations } from '@/i18n';\n\ninterface StatusInfo {\n description: string;\n color: string;\n icon: React.ElementType;\n}\n\nconst statusKeys: Record<\n number,\n { key: keyof Translations; color: string; icon: React.ElementType }\n> = {\n 400: { key: 'statusBadRequest', color: 'text-red-500', icon: CircleX },\n 401: { key: 'statusUnauthorized', color: 'text-red-500', icon: CircleX },\n 403: { key: 'statusForbidden', color: 'text-red-500', icon: CircleX },\n 404: { key: 'statusNotFound', color: 'text-fd-muted-foreground', icon: CircleX },\n 500: { key: 'statusInternalServerError', color: 'text-red-500', icon: CircleX },\n};\n\nexport function getStatusInfo(status: number, t: Translations): StatusInfo {\n if (status in statusKeys) {\n const { key, color, icon } = statusKeys[status];\n return { description: t[key], color, icon };\n }\n\n if (status >= 200 && status < 300) {\n return {\n description: t.statusSuccessful,\n color: 'text-green-500',\n icon: CircleCheck,\n };\n }\n\n if (status >= 400) {\n return { description: t.statusError, color: 'text-red-500', icon: CircleX };\n }\n\n return {\n description: t.statusNoDescription,\n color: 'text-fd-muted-foreground',\n icon: CircleX,\n };\n}\n"],"mappings":";;AASA,MAAM,aAGF;CACF,KAAK;EAAE,KAAK;EAAoB,OAAO;EAAgB,MAAM;EAAS;CACtE,KAAK;EAAE,KAAK;EAAsB,OAAO;EAAgB,MAAM;EAAS;CACxE,KAAK;EAAE,KAAK;EAAmB,OAAO;EAAgB,MAAM;EAAS;CACrE,KAAK;EAAE,KAAK;EAAkB,OAAO;EAA4B,MAAM;EAAS;CAChF,KAAK;EAAE,KAAK;EAA6B,OAAO;EAAgB,MAAM;EAAS;CAChF;AAED,SAAgB,cAAc,QAAgB,GAA6B;AACzE,KAAI,UAAU,YAAY;EACxB,MAAM,EAAE,KAAK,OAAO,SAAS,WAAW;AACxC,SAAO;GAAE,aAAa,EAAE;GAAM;GAAO;GAAM;;AAG7C,KAAI,UAAU,OAAO,SAAS,IAC5B,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP;AAGH,KAAI,UAAU,IACZ,QAAO;EAAE,aAAa,EAAE;EAAa,OAAO;EAAgB,MAAM;EAAS;AAG7E,QAAO;EACL,aAAa,EAAE;EACf,OAAO;EACP,MAAM;EACP"}
@@ -46,7 +46,7 @@ interface InlineCodeUsageGenerator<T = unknown> {
46
46
  */
47
47
  serverContext?: T;
48
48
  }
49
- declare function createCodeUsageGeneratorRegistry(ihherit?: CodeUsageGeneratorRegistry): CodeUsageGeneratorRegistry;
49
+ declare function createCodeUsageGeneratorRegistry(inherit?: CodeUsageGeneratorRegistry): CodeUsageGeneratorRegistry;
50
50
  type CodeUsageGeneratorFn<ServerContext = unknown> = (url: string, data: RequestData, context: {
51
51
  mediaAdapters: Record<string, MediaAdapter>;
52
52
  server: ServerContext;
@@ -1,6 +1,6 @@
1
1
  //#region src/requests/generators/index.ts
2
- function createCodeUsageGeneratorRegistry(ihherit) {
3
- const registry = new Map(ihherit?.map());
2
+ function createCodeUsageGeneratorRegistry(inherit) {
3
+ const registry = new Map(inherit?.map());
4
4
  return {
5
5
  add(id, generator) {
6
6
  registry.set(id, generator);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/requests/generators/index.ts"],"sourcesContent":["import type { MediaAdapter } from '../media/adapter';\nimport type { RequestData } from '../types';\n\nexport interface CodeUsageGeneratorRegistry {\n add: (id: string, generator: CodeUsageGenerator) => void;\n get: (id: string) => CodeUsageGenerator | undefined;\n addInline: (generator: InlineCodeUsageGenerator) => void;\n /**\n * @returns if the generator is removed\n */\n remove: (id: string) => boolean;\n map: () => Map<string, CodeUsageGenerator>;\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface CodeUsageGenerator {\n generate: CodeUsageGeneratorFn;\n lang: string;\n label?: string;\n\n /**\n * for inline generators passed from server, this stores info available for client (e.g. forwarded from \"use client\").\n */\n _client?: {\n generate: string | CodeUsageGeneratorFn;\n serverContext?: unknown;\n };\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface InlineCodeUsageGenerator<T = unknown> {\n id?: string;\n lang: string;\n label?: string;\n /**\n * either:\n * - code\n * - a function imported from a file with \"use client\" directive\n * - false (disabled)\n */\n source?: string | CodeUsageGeneratorFn<T> | false;\n\n /**\n * Pass extra context to client-side source generator\n */\n serverContext?: T;\n}\n\nexport function createCodeUsageGeneratorRegistry(\n ihherit?: CodeUsageGeneratorRegistry,\n): CodeUsageGeneratorRegistry {\n const registry = new Map<string, CodeUsageGenerator>(ihherit?.map());\n\n return {\n add(id, generator) {\n registry.set(id, generator);\n },\n get(id) {\n return registry.get(id);\n },\n addInline(generator) {\n const source = generator.source;\n const id = generator.id ?? generator.lang;\n if (!source) {\n this.remove(id);\n return;\n }\n\n registry.set(id, {\n lang: generator.lang,\n label: generator.label,\n generate() {\n return typeof source === 'string' ? source : '';\n },\n _client: {\n generate: source,\n serverContext: generator.serverContext,\n },\n });\n },\n remove(id) {\n return registry.delete(id);\n },\n map() {\n return registry;\n },\n };\n}\n\nexport type CodeUsageGeneratorFn<ServerContext = unknown> = (\n url: string,\n data: RequestData,\n context: {\n mediaAdapters: Record<string, MediaAdapter>;\n server: ServerContext;\n },\n) => string;\n"],"mappings":";AAoDA,SAAgB,iCACd,SAC4B;CAC5B,MAAM,WAAW,IAAI,IAAgC,SAAS,KAAK,CAAC;AAEpE,QAAO;EACL,IAAI,IAAI,WAAW;AACjB,YAAS,IAAI,IAAI,UAAU;;EAE7B,IAAI,IAAI;AACN,UAAO,SAAS,IAAI,GAAG;;EAEzB,UAAU,WAAW;GACnB,MAAM,SAAS,UAAU;GACzB,MAAM,KAAK,UAAU,MAAM,UAAU;AACrC,OAAI,CAAC,QAAQ;AACX,SAAK,OAAO,GAAG;AACf;;AAGF,YAAS,IAAI,IAAI;IACf,MAAM,UAAU;IAChB,OAAO,UAAU;IACjB,WAAW;AACT,YAAO,OAAO,WAAW,WAAW,SAAS;;IAE/C,SAAS;KACP,UAAU;KACV,eAAe,UAAU;KAC1B;IACF,CAAC;;EAEJ,OAAO,IAAI;AACT,UAAO,SAAS,OAAO,GAAG;;EAE5B,MAAM;AACJ,UAAO;;EAEV"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/requests/generators/index.ts"],"sourcesContent":["import type { MediaAdapter } from '../media/adapter';\nimport type { RequestData } from '../types';\n\nexport interface CodeUsageGeneratorRegistry {\n add: (id: string, generator: CodeUsageGenerator) => void;\n get: (id: string) => CodeUsageGenerator | undefined;\n addInline: (generator: InlineCodeUsageGenerator) => void;\n /**\n * @returns if the generator is removed\n */\n remove: (id: string) => boolean;\n map: () => Map<string, CodeUsageGenerator>;\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface CodeUsageGenerator {\n generate: CodeUsageGeneratorFn;\n lang: string;\n label?: string;\n\n /**\n * for inline generators passed from server, this stores info available for client (e.g. forwarded from \"use client\").\n */\n _client?: {\n generate: string | CodeUsageGeneratorFn;\n serverContext?: unknown;\n };\n}\n\n/**\n * Generate code example for given programming language\n */\nexport interface InlineCodeUsageGenerator<T = unknown> {\n id?: string;\n lang: string;\n label?: string;\n /**\n * either:\n * - code\n * - a function imported from a file with \"use client\" directive\n * - false (disabled)\n */\n source?: string | CodeUsageGeneratorFn<T> | false;\n\n /**\n * Pass extra context to client-side source generator\n */\n serverContext?: T;\n}\n\nexport function createCodeUsageGeneratorRegistry(\n inherit?: CodeUsageGeneratorRegistry,\n): CodeUsageGeneratorRegistry {\n const registry = new Map<string, CodeUsageGenerator>(inherit?.map());\n\n return {\n add(id, generator) {\n registry.set(id, generator);\n },\n get(id) {\n return registry.get(id);\n },\n addInline(generator) {\n const source = generator.source;\n const id = generator.id ?? generator.lang;\n if (!source) {\n this.remove(id);\n return;\n }\n\n registry.set(id, {\n lang: generator.lang,\n label: generator.label,\n generate() {\n return typeof source === 'string' ? source : '';\n },\n _client: {\n generate: source,\n serverContext: generator.serverContext,\n },\n });\n },\n remove(id) {\n return registry.delete(id);\n },\n map() {\n return registry;\n },\n };\n}\n\nexport type CodeUsageGeneratorFn<ServerContext = unknown> = (\n url: string,\n data: RequestData,\n context: {\n mediaAdapters: Record<string, MediaAdapter>;\n server: ServerContext;\n },\n) => string;\n"],"mappings":";AAoDA,SAAgB,iCACd,SAC4B;CAC5B,MAAM,WAAW,IAAI,IAAgC,SAAS,KAAK,CAAC;AAEpE,QAAO;EACL,IAAI,IAAI,WAAW;AACjB,YAAS,IAAI,IAAI,UAAU;;EAE7B,IAAI,IAAI;AACN,UAAO,SAAS,IAAI,GAAG;;EAEzB,UAAU,WAAW;GACnB,MAAM,SAAS,UAAU;GACzB,MAAM,KAAK,UAAU,MAAM,UAAU;AACrC,OAAI,CAAC,QAAQ;AACX,SAAK,OAAO,GAAG;AACf;;AAGF,YAAS,IAAI,IAAI;IACf,MAAM,UAAU;IAChB,OAAO,UAAU;IACjB,WAAW;AACT,YAAO,OAAO,WAAW,WAAW,SAAS;;IAE/C,SAAS;KACP,UAAU;KACV,eAAe,UAAU;KAC1B;IACF,CAAC;;EAEJ,OAAO,IAAI;AACT,UAAO,SAAS,OAAO,GAAG;;EAE5B,MAAM;AACJ,UAAO;;EAEV"}