@atproto/oauth-provider 0.5.0 → 0.5.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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/oauth-provider.d.ts +3 -3
  3. package/dist/oauth-provider.d.ts.map +1 -1
  4. package/dist/oauth-provider.js.map +1 -1
  5. package/dist/output/build-customization-data.d.ts +20 -11
  6. package/dist/output/build-customization-data.d.ts.map +1 -1
  7. package/dist/output/build-customization-data.js +72 -43
  8. package/dist/output/build-customization-data.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/assets/app/locales/an/messages.po +6 -6
  11. package/src/assets/app/locales/ast/messages.po +6 -6
  12. package/src/assets/app/locales/ca/messages.po +6 -6
  13. package/src/assets/app/locales/da/messages.po +6 -6
  14. package/src/assets/app/locales/de/messages.po +6 -6
  15. package/src/assets/app/locales/el/messages.po +6 -6
  16. package/src/assets/app/locales/en/messages.po +6 -6
  17. package/src/assets/app/locales/en-GB/messages.po +6 -6
  18. package/src/assets/app/locales/es/messages.po +6 -6
  19. package/src/assets/app/locales/eu/messages.po +6 -6
  20. package/src/assets/app/locales/fi/messages.po +6 -6
  21. package/src/assets/app/locales/fr/messages.po +6 -6
  22. package/src/assets/app/locales/ga/messages.po +6 -6
  23. package/src/assets/app/locales/gl/messages.po +6 -6
  24. package/src/assets/app/locales/hi/messages.po +6 -6
  25. package/src/assets/app/locales/hu/messages.po +6 -6
  26. package/src/assets/app/locales/ia/messages.po +6 -6
  27. package/src/assets/app/locales/id/messages.po +6 -6
  28. package/src/assets/app/locales/it/messages.po +6 -6
  29. package/src/assets/app/locales/ja/messages.po +6 -6
  30. package/src/assets/app/locales/km/messages.po +6 -6
  31. package/src/assets/app/locales/ko/messages.po +6 -6
  32. package/src/assets/app/locales/ne/messages.po +6 -6
  33. package/src/assets/app/locales/nl/messages.po +6 -6
  34. package/src/assets/app/locales/pl/messages.po +6 -6
  35. package/src/assets/app/locales/pt-BR/messages.po +6 -6
  36. package/src/assets/app/locales/ro/messages.po +6 -6
  37. package/src/assets/app/locales/ru/messages.po +6 -6
  38. package/src/assets/app/locales/sv/messages.po +6 -6
  39. package/src/assets/app/locales/th/messages.po +6 -6
  40. package/src/assets/app/locales/tr/messages.po +6 -6
  41. package/src/assets/app/locales/uk/messages.po +6 -6
  42. package/src/assets/app/locales/vi/messages.po +6 -6
  43. package/src/assets/app/locales/zh-CN/messages.po +6 -6
  44. package/src/assets/app/locales/zh-HK/messages.po +6 -6
  45. package/src/assets/app/locales/zh-TW/messages.po +6 -6
  46. package/src/oauth-provider.ts +7 -3
  47. package/src/output/build-customization-data.ts +89 -50
@@ -9,8 +9,32 @@ export const colorNames = ['brand', 'error', 'warning', 'success'] as const
9
9
  export const colorNameSchema = z.enum(colorNames)
10
10
  export type ColorName = z.infer<typeof colorNameSchema>
11
11
 
12
- export const ColorsDefinitionSchema = z.record(colorNameSchema, z.string())
13
- export type ColorsDefinition = z.infer<typeof ColorsDefinitionSchema>
12
+ const parsedColorSchema = z.string().transform((value, ctx): RgbColor => {
13
+ try {
14
+ const { r, g, b, a } = parseColor(value)
15
+ if (a != null) {
16
+ ctx.addIssue({
17
+ code: z.ZodIssueCode.custom,
18
+ message: 'Alpha values are not supported',
19
+ })
20
+ }
21
+ return { r, g, b }
22
+ } catch (e) {
23
+ ctx.addIssue({
24
+ code: z.ZodIssueCode.custom,
25
+ message: e instanceof Error ? e.message : 'Invalid color value',
26
+ })
27
+ // Won't actually be used (since an issue was added):
28
+ return { r: 0, g: 0, b: 0 }
29
+ }
30
+ })
31
+ export type ParsedColor = z.infer<typeof parsedColorSchema> // Same as RgbColor
32
+
33
+ export const colorsDefinitionSchema = z.record(
34
+ colorNameSchema,
35
+ parsedColorSchema.optional(),
36
+ )
37
+ export type ColorsDefinition = z.infer<typeof colorsDefinitionSchema>
14
38
 
15
39
  export const localizedStringSchema = z.union([
16
40
  z.string(),
@@ -34,10 +58,11 @@ export type LinkDefinition = z.infer<typeof linkDefinitionSchema>
34
58
  export const brandingConfigSchema = z.object({
35
59
  name: z.string().optional(),
36
60
  logo: z.string().optional(),
37
- colors: ColorsDefinitionSchema.optional(),
61
+ colors: colorsDefinitionSchema.optional(),
38
62
  links: z.array(linkDefinitionSchema).readonly().optional(),
39
63
  })
40
- export type BrandingConfig = z.infer<typeof brandingConfigSchema>
64
+ export type BrandingInput = z.input<typeof brandingConfigSchema>
65
+ export type Branding = z.infer<typeof brandingConfigSchema>
41
66
 
42
67
  export const customizationSchema = z.object({
43
68
  /**
@@ -58,6 +83,7 @@ export const customizationSchema = z.object({
58
83
  */
59
84
  hcaptcha: hcaptchaConfigSchema.optional(),
60
85
  })
86
+ export type CustomizationInput = z.input<typeof customizationSchema>
61
87
  export type Customization = z.infer<typeof customizationSchema>
62
88
 
63
89
  export type CustomizationData = {
@@ -99,19 +125,13 @@ export function buildCustomizationCss({ branding }: Customization) {
99
125
  return ''
100
126
  }
101
127
 
102
- function* buildCustomizationVars(branding?: BrandingConfig) {
128
+ function* buildCustomizationVars(branding?: Branding) {
103
129
  if (branding?.colors) {
104
130
  for (const name of colorNames) {
105
131
  const value = branding.colors[name]
106
- if (!value) continue
107
-
108
- // Skip undefined values
109
- if (value === undefined) continue
132
+ if (!value) continue // Skip missing colors
110
133
 
111
- const { r, g, b, a } = parseColor(value)
112
-
113
- // Tailwind does not apply alpha values to base colors
114
- if (a !== undefined) throw new TypeError('Alpha not supported')
134
+ const { r, g, b } = value
115
135
 
116
136
  const contrast = computeLuma({ r, g, b }) > 128 ? '0 0 0' : '255 255 255'
117
137
 
@@ -121,54 +141,71 @@ function* buildCustomizationVars(branding?: BrandingConfig) {
121
141
  }
122
142
  }
123
143
 
144
+ type RgbColor = { r: number; g: number; b: number }
124
145
  type RgbaColor = { r: number; g: number; b: number; a?: number }
125
- function parseColor(color: unknown): RgbaColor {
126
- if (typeof color !== 'string') {
127
- throw new TypeError(`Invalid color value: ${typeof color}`)
146
+ function parseColor(color: string): RgbaColor {
147
+ if (color.startsWith('#')) {
148
+ return parseHexColor(color)
128
149
  }
129
150
 
130
- if (color.startsWith('#')) {
131
- if (color.length === 4 || color.length === 5) {
132
- const r = parseUi8Hex(color.slice(1, 2))
133
- const g = parseUi8Hex(color.slice(2, 3))
134
- const b = parseUi8Hex(color.slice(3, 4))
135
- const a = color.length > 4 ? parseUi8Hex(color.slice(4, 5)) : undefined
136
- return { r, g, b, a }
137
- }
151
+ if (color.startsWith('rgba(')) {
152
+ return parseRgbaColor(color)
153
+ }
138
154
 
139
- if (color.length === 7 || color.length === 9) {
140
- const r = parseUi8Hex(color.slice(1, 3))
141
- const g = parseUi8Hex(color.slice(3, 5))
142
- const b = parseUi8Hex(color.slice(5, 7))
143
- const a = color.length > 8 ? parseUi8Hex(color.slice(7, 9)) : undefined
144
- return { r, g, b, a }
145
- }
155
+ if (color.startsWith('rgb(')) {
156
+ return parseRgbColor(color)
157
+ }
158
+
159
+ // Should never happen (as long as the input is a validated WebColor)
160
+ throw new TypeError(`Invalid color value: ${color}`)
161
+ }
146
162
 
147
- throw new TypeError(`Invalid hex color: ${color}`)
163
+ function parseHexColor(v: string) {
164
+ // parseInt('az', 16) does not return NaN so we need to check the format
165
+ if (!/^#[0-9a-f]+$/i.test(v)) {
166
+ throw new TypeError(`Invalid hex color value: ${v}`)
148
167
  }
149
168
 
150
- const rgbMatch = color.match(
151
- /^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,
152
- )
153
- if (rgbMatch) {
154
- const r = parseUi8Dec(rgbMatch[1])
155
- const g = parseUi8Dec(rgbMatch[2])
156
- const b = parseUi8Dec(rgbMatch[3])
157
- return { r, g, b }
169
+ if (v.length === 4 || v.length === 5) {
170
+ const r = parseUi8Hex(v.slice(1, 2))
171
+ const g = parseUi8Hex(v.slice(2, 3))
172
+ const b = parseUi8Hex(v.slice(3, 4))
173
+ const a = v.length > 4 ? parseUi8Hex(v.slice(4, 5)) : undefined
174
+ return { r, g, b, a }
158
175
  }
159
176
 
160
- const rgbaMatch = color.match(
161
- /^\s*rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,
162
- )
163
- if (rgbaMatch) {
164
- const r = parseUi8Dec(rgbaMatch[1])
165
- const g = parseUi8Dec(rgbaMatch[2])
166
- const b = parseUi8Dec(rgbaMatch[3])
167
- const a = parseUi8Dec(rgbaMatch[4])
177
+ if (v.length === 7 || v.length === 9) {
178
+ const r = parseUi8Hex(v.slice(1, 3))
179
+ const g = parseUi8Hex(v.slice(3, 5))
180
+ const b = parseUi8Hex(v.slice(5, 7))
181
+ const a = v.length > 8 ? parseUi8Hex(v.slice(7, 9)) : undefined
168
182
  return { r, g, b, a }
169
183
  }
170
184
 
171
- throw new TypeError(`Unsupported color format: ${color}`)
185
+ throw new TypeError(`Invalid hex color value: ${v}`)
186
+ }
187
+
188
+ function parseRgbColor(v: string) {
189
+ const matches = v.match(/^\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/)
190
+ if (!matches) throw new TypeError(`Invalid rgb color value: ${v}`)
191
+
192
+ const r = parseUi8Dec(matches[1])
193
+ const g = parseUi8Dec(matches[2])
194
+ const b = parseUi8Dec(matches[3])
195
+ return { r, g, b }
196
+ }
197
+
198
+ function parseRgbaColor(v: string) {
199
+ const matches = v.match(
200
+ /^\s*rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/,
201
+ )
202
+ if (!matches) throw new TypeError(`Invalid rgba color value: ${v}`)
203
+
204
+ const r = parseUi8Dec(matches[1])
205
+ const g = parseUi8Dec(matches[2])
206
+ const b = parseUi8Dec(matches[3])
207
+ const a = parseUi8Dec(matches[4])
208
+ return { r, g, b, a }
172
209
  }
173
210
 
174
211
  function computeLuma({ r, g, b }: RgbaColor) {
@@ -185,5 +222,7 @@ function parseUi8Dec(v: string) {
185
222
 
186
223
  function asUi8(v: number) {
187
224
  if (v >= 0 && v <= 255 && v === (v | 0)) return v
188
- throw new TypeError(`Invalid color component: ${v}`)
225
+ throw new TypeError(
226
+ `Invalid color component "${v}" (expected an integer between 0 and 255)`,
227
+ )
189
228
  }