codeforlife 2.6.4 → 2.6.6

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.6.6](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.6.5...v2.6.6) (2025-01-27)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * csrf header for non-safe http methods ([#75](https://github.com/ocadotechnology/codeforlife-package-javascript/issues/75)) ([d0b2b78](https://github.com/ocadotechnology/codeforlife-package-javascript/commit/d0b2b7852fbdc9f84ade5ec4d46cc8a980e60f1e))
7
+
8
+ ## [2.6.5](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.6.4...v2.6.5) (2025-01-17)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * unique values ([#74](https://github.com/ocadotechnology/codeforlife-package-javascript/issues/74)) ([1d183d2](https://github.com/ocadotechnology/codeforlife-package-javascript/commit/1d183d2806a7aa8ba98e78bf8a3fa9927ff37389))
14
+
1
15
  ## [2.6.4](https://github.com/ocadotechnology/codeforlife-package-javascript/compare/v2.6.3...v2.6.4) (2025-01-10)
2
16
 
3
17
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "codeforlife",
3
3
  "description": "Common frontend code",
4
4
  "private": false,
5
- "version": "2.6.4",
5
+ "version": "2.6.6",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "dev": "vite",
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  createApi as _createApi,
3
3
  fetchBaseQuery,
4
+ type FetchArgs,
4
5
  } from "@reduxjs/toolkit/query/react"
5
6
 
6
7
  import { SERVICE_API_URL } from "../settings"
7
8
  import defaultTagTypes from "./tagTypes"
8
9
  import { buildLogoutEndpoint } from "./endpoints/session"
9
10
  import { getCsrfCookie } from "../utils/auth"
11
+ import { isSafeHttpMethod } from "../utils/api"
10
12
 
11
13
  // TODO: decide if we want to keep any of this.
12
14
  // export function handleResponseError(error: FetchBaseQueryError): void {
@@ -36,8 +38,13 @@ export default function createApi<TagTypes extends string = never>({
36
38
  const fetch = fetchBaseQuery({
37
39
  baseUrl: `${SERVICE_API_URL}/`,
38
40
  credentials: "include",
39
- prepareHeaders: (headers, { type }) => {
40
- if (type === "mutation") {
41
+ prepareHeaders: (headers, endpoint) => {
42
+ const { type, arg } = endpoint as typeof endpoint & {
43
+ arg: string | FetchArgs
44
+ }
45
+ const method = typeof arg === "string" ? "GET" : arg.method || "GET"
46
+
47
+ if (type === "mutation" || !isSafeHttpMethod(method)) {
41
48
  let csrfToken = getCsrfCookie()
42
49
  if (csrfToken) headers.set("x-csrftoken", csrfToken)
43
50
  }
@@ -30,6 +30,8 @@ export type TextFieldProps = Omit<
30
30
  validateOptions?: ValidateOptions
31
31
  dirty?: boolean
32
32
  split?: string | RegExp
33
+ unique?: boolean
34
+ uniqueCaseInsensitive?: boolean
33
35
  }
34
36
 
35
37
  // https://formik.org/docs/examples/with-material-ui
@@ -40,6 +42,8 @@ const TextField: FC<TextFieldProps> = ({
40
42
  type = "text",
41
43
  required = false,
42
44
  dirty = false,
45
+ unique = false,
46
+ uniqueCaseInsensitive = false,
43
47
  split,
44
48
  validateOptions,
45
49
  ...otherTextFieldProps
@@ -49,7 +53,27 @@ const TextField: FC<TextFieldProps> = ({
49
53
  const dotPath = name.split(".")
50
54
 
51
55
  let _schema: Schema = schema
52
- if (split) _schema = YupArray().of(_schema)
56
+ if (split) {
57
+ _schema = YupArray().of(_schema)
58
+ if (unique || uniqueCaseInsensitive) {
59
+ _schema = _schema.test({
60
+ message: "cannot have duplicates",
61
+ test: values => {
62
+ if (Array.isArray(values) && values.length >= 2) {
63
+ return (
64
+ new Set(
65
+ uniqueCaseInsensitive && typeof values[0] === "string"
66
+ ? values.map(value => value.toLowerCase())
67
+ : values,
68
+ ).size === values.length
69
+ )
70
+ }
71
+
72
+ return true
73
+ },
74
+ })
75
+ }
76
+ }
53
77
  if (required) {
54
78
  _schema = _schema.required()
55
79
  if (split) _schema = (_schema as ArraySchema<string[], any>).min(1)
package/src/utils/api.tsx CHANGED
@@ -325,3 +325,8 @@ export function handleResultState<QueryArg, ResultType>(
325
325
  // Have yet to call the API.
326
326
  return loadingNode
327
327
  }
328
+
329
+ export function isSafeHttpMethod(method: string) {
330
+ // https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1
331
+ return ["GET", "HEAD", "OPTIONS", "TRACE"].includes(method.toUpperCase())
332
+ }