@model-ts/graphql 7.2.0 → 7.4.0

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,5 +1,19 @@
1
1
  # @model-ts/graphql
2
2
 
3
+ ## 7.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6032bfa: Let the JSON scalar declare `@specifiedBy`. `jsonScalar({ specifiedByURL, description })` is exported and returns the built-in JSON scalar with that metadata. Registering `"JSON"` with an annotated `JSONValue`, as in `GraphQL.scalar("JSON", JSONValue.annotate({ specifiedByURL }))`, now keeps the built-in JSON parsing (enum literals rejected at any depth, the ECMA-404 description by default) and takes the annotations' metadata. `Register` infers a schema of unknown values, such as `JSONValue`, as a scalar.
8
+
9
+ ## 7.3.0
10
+
11
+ ### Minor Changes
12
+
13
+ - ce187d1: Add `where` to models, unions and `DynamoDB`: a pipe step that keeps a loaded item only when a predicate holds. After `load`, a rejected item fails with `ItemNotFoundError` for its key; after `loadOption` or any read of an `Option`, it becomes `Option.none()`.
14
+
15
+ Add `publicMessages` to `withErrorPolicy`: a public error with a fixed message reaches clients as only that message and its code, without its own message or declared fields.
16
+
3
17
  ## 7.2.0
4
18
 
5
19
  ## 7.1.0
package/README.md CHANGED
@@ -874,6 +874,27 @@ valid Date or parseable date string and serializes to ISO.
874
874
  `graphql-type-json` convention. Literal JSON rejects unquoted enum values. For
875
875
  stricter validation, use `Schema.Json.annotate({ graphqlType: "JSON" })`.
876
876
 
877
+ To give the JSON scalar a `@specifiedBy` URL or its own description, register
878
+ it with an annotated `JSONValue`. The builder keeps the built-in JSON parsing
879
+ and takes `specifiedByURL` and `description` from the annotations:
880
+
881
+ ```ts
882
+ import { JSONValue } from "@model-ts/graphql"
883
+ import { GraphQL, type Register } from "../api/graphql.ts"
884
+
885
+ const specifiedByURL =
886
+ "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf"
887
+ const AnnotatedJSON = JSONValue.annotate({ specifiedByURL })
888
+ declare module "../api/graphql.ts" {
889
+ interface Types extends Register<typeof AnnotatedJSON, "JSON"> {}
890
+ }
891
+ export const JSONType = GraphQL.scalar("JSON", AnnotatedJSON)
892
+ ```
893
+
894
+ The schema then prints `scalar JSON @specifiedBy(url: "...")`. To set the
895
+ metadata on the scalar itself, pass `jsonScalar({ specifiedByURL, description })`
896
+ as the third argument; it has the same parsing as the built-in scalar.
897
+
877
898
  Custom scalars pair a registered name with a Schema codec:
878
899
 
879
900
  `examples/custom-scalar.ts`
@@ -1057,6 +1078,7 @@ Choose the public error code exposed to clients:
1057
1078
  `examples/error-policy.ts`
1058
1079
 
1059
1080
  ```ts
1081
+ import { ItemNotFoundError } from "@model-ts/dynamodb"
1060
1082
  import { createBuilder, ErrorReporter } from "@model-ts/graphql"
1061
1083
  import { Cause, Effect, Layer, Schema } from "effect"
1062
1084
  import type { AppContext, Types } from "../api/graphql.ts"
@@ -1065,8 +1087,12 @@ class AccessDenied extends Schema.TaggedError<AccessDenied>()("AccessDenied", {
1065
1087
  message: Schema.String,
1066
1088
  }) {}
1067
1089
  export const GraphQL = createBuilder<Types, AppContext>().withErrorPolicy({
1068
- public: [AccessDenied],
1069
- publicCodes: { AccessDenied: "ACCESS_DENIED" },
1090
+ public: [AccessDenied, ItemNotFoundError],
1091
+ publicCodes: {
1092
+ AccessDenied: "ACCESS_DENIED",
1093
+ ItemNotFoundError: "NOT_FOUND",
1094
+ },
1095
+ publicMessages: { ItemNotFoundError: "Not found" },
1070
1096
  })
1071
1097
  export const Reporting = Layer.succeed(ErrorReporter, {
1072
1098
  report: ({ cause, coordinate, phase }) =>
@@ -1087,6 +1113,14 @@ arbitrary thrown exception does not make it public. This policy also applies to
1087
1113
  custom scalar callbacks and abstract-type resolution. Ordinary graphql-js
1088
1114
  document diagnostics remain available to clients.
1089
1115
 
1116
+ Some errors are safe to report but carry fields that are not, such as the
1117
+ storage key of an `ItemNotFoundError`. Give their tag a fixed message in
1118
+ `publicMessages`: clients then get only that message and the error's code, here
1119
+ `{ message: "Not found", extensions: { code: "NOT_FOUND" } }`, and never the
1120
+ error's own message or fields. The keys must be tags of the `public` errors. A
1121
+ field that lists the error in its `errors` union still returns it as a union
1122
+ member with its declared fields.
1123
+
1090
1124
  Provide `Reporting` alongside the application's service layers, for example with
1091
1125
  `Layer.mergeAll(Sandbox.layerMemory(), Reporting)`. The optional `ErrorReporter`
1092
1126
  receives the original Effect cause, field coordinate, and phase for masked
@@ -1261,6 +1295,7 @@ functions such as `executor` are separate exports, not builder methods.
1261
1295
  | `ExecutionResult`, `FormattedExecutionResult` | Direct graphql-js results and formatted executor results |
1262
1296
  | `ErrorReporter` | Optional service for masked-failure telemetry |
1263
1297
  | `ID`, `DateTime`, `JSONValue` | Built-in input schemas |
1298
+ | `jsonScalar({ specifiedByURL?, description? })` | The built-in JSON scalar, with its own metadata |
1264
1299
  | `id`, `input`, `defaulted` | Package-level schema annotation helpers |
1265
1300
  | `Connection`, `Edge`, `PageInfo`, `ConnectionArgs` | Structural pagination types |
1266
1301
  | `@model-ts/graphql/Testing` | Test clients, the graphql tag, and normalized snapshots |