@doswiftly/storefront-operations 22.4.0 → 22.5.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/AGENTS.md +2 -2
- package/CHANGELOG.md +32 -0
- package/README.md +39 -0
- package/codegen.js +113 -0
- package/llms-full.txt +1 -1
- package/operations.json +1 -1
- package/package.json +3 -1
package/AGENTS.md
CHANGED
|
@@ -27,7 +27,7 @@ consumer's `codegen.ts` references this package's `.graphql` files as
|
|
|
27
27
|
live in the consumer's repo.
|
|
28
28
|
|
|
29
29
|
<!-- AUTOGEN:STATS:BEGIN — auto-regenerated, do not edit by hand -->
|
|
30
|
-
- **Schema version**: 22.
|
|
30
|
+
- **Schema version**: 22.5.0
|
|
31
31
|
- **Queries**: 52
|
|
32
32
|
- **Mutations**: 44
|
|
33
33
|
- **Fragments**: 105
|
|
@@ -203,4 +203,4 @@ directly, and CORS errors only surface on the first client-side mutation.
|
|
|
203
203
|
- **Operation question** ("which mutation does Y?") → grep `llms-full.txt` for the verb in `**Description**:` lines
|
|
204
204
|
- **Programmatic enumeration** → load `operations.json`
|
|
205
205
|
|
|
206
|
-
For codegen setup and runtime transport, see `README.md` and [`@doswiftly/storefront-sdk`](https://www.npmjs.com/package/@doswiftly/storefront-sdk).
|
|
206
|
+
For codegen setup and runtime transport, see `README.md` and [`@doswiftly/storefront-sdk`](https://www.npmjs.com/package/@doswiftly/storefront-sdk). To make public reads edge-cacheable, use the ready persisted-documents recipe `@doswiftly/storefront-operations/codegen` (`createCodegenConfig`) — it emits `documentId`s in the API's `sha256:<hex>` format. See README → "Edge-cacheable reads".
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 22.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3d5f1d3: Public reads now use the cacheable `GET` transport **by default** — you no longer opt in per query with `cacheLong()`. A non-mutation query that carries a persisted-document id and no signed-in identity is sent as a shared, credential-less `GET` so a CDN can cache it; a request carrying an `Authorization` bearer or a cart secret automatically stays on `POST` with credentials, so personalised reads are never shared. The server decides whether a result is actually cacheable via its `Cache-Control` response — the client only chooses the transport. Opt a specific persisted read out of the shared cache with `cachePrivate()` or `cacheNone()` (forces `POST`). Mutations and any request without a document id keep the existing `POST` behaviour, so current behaviour is unchanged until document ids are present.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Cacheable GET automatically (anonymous visitor) — no cacheLong() needed:
|
|
11
|
+
const products = await client.query(ProductsQuery, { first: 20 });
|
|
12
|
+
|
|
13
|
+
// Keep a persisted read per-user (forces POST):
|
|
14
|
+
const account = await client.query(MyAccountQuery, {}, cachePrivate());
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- 7664b81: Added a ready GraphQL codegen recipe for edge-cacheable reads. Import `createCodegenConfig` from `@doswiftly/storefront-operations/codegen` and `export default` it from your `codegen.ts` — it points the client preset at the bundled schema and emits persisted documents whose `documentId` matches the Storefront API's `sha256:<hex>` contract, so public reads resolve server-side and can be cached at the edge.
|
|
18
|
+
|
|
19
|
+
You write operations with the generated `gql(...)` tag. They compile to lightweight typed strings (no `graphql` package at runtime) that the SDK's `query` / `mutate` accept directly, custom scalars are mapped to precision-safe TypeScript types (money and 64-bit integers as strings), and fragment fields are read directly with no unmasking helper. If your project already imports a `gql` from another GraphQL client, override the tag name: `createCodegenConfig({ gqlTagName: 'graphql' })`. Requires `@graphql-codegen/cli`, `@graphql-codegen/client-preset@^4` and `graphql@^16` as devDependencies (the preset doesn't support `graphql` v17 yet — fragment operations fail to generate). See the README "Edge-cacheable reads" section. `@doswiftly/storefront-sdk` accepts these generated documents directly in `query` / `mutate`, and its cacheable `GET` transport degrades to a `POST` on any non-success response.
|
|
20
|
+
|
|
21
|
+
Author operations with the generated tag — codegen emits each as a typed document carrying its `documentId`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { gql } from "./gql";
|
|
25
|
+
|
|
26
|
+
export const ProductsQuery = gql(`
|
|
27
|
+
query Products($first: Int) {
|
|
28
|
+
products(first: $first) {
|
|
29
|
+
nodes { id handle title }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`);
|
|
33
|
+
```
|
|
34
|
+
|
|
3
35
|
## 22.4.0
|
|
4
36
|
|
|
5
37
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -116,6 +116,45 @@ export default config;
|
|
|
116
116
|
The schema lives offline as a file in the package — no running backend needed
|
|
117
117
|
for codegen.
|
|
118
118
|
|
|
119
|
+
### Edge-cacheable reads: persisted documents (recommended)
|
|
120
|
+
|
|
121
|
+
To make your public reads cacheable at the edge, the API accepts a short
|
|
122
|
+
`documentId` (`sha256:<hex>`) instead of the full query. This package ships a
|
|
123
|
+
codegen recipe that wires it up — it points the client preset at the schema and
|
|
124
|
+
sets the `documentId` hash to the exact format the API validates:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// codegen.ts
|
|
128
|
+
import { createCodegenConfig } from '@doswiftly/storefront-operations/codegen';
|
|
129
|
+
|
|
130
|
+
export default createCodegenConfig({ documents: 'src/**/*.{ts,tsx}' });
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Add `@graphql-codegen/cli`, `@graphql-codegen/client-preset@^4` and `graphql@^16` to
|
|
134
|
+
your devDependencies. (The preset doesn't support `graphql` v17 yet — fragment
|
|
135
|
+
operations fail to generate with it; pin `graphql@^16`.) Codegen then emits a `persisted-documents.json`
|
|
136
|
+
(`documentId → query`) you publish at deploy time, plus typed documents whose
|
|
137
|
+
`documentId` the SDK sends automatically for public reads.
|
|
138
|
+
|
|
139
|
+
Write operations with the generated `gql(...)` tag. If your project already imports a
|
|
140
|
+
`gql` from another GraphQL client (Apollo, urql, graphql-request), pass a different name
|
|
141
|
+
to avoid a clash: `createCodegenConfig({ documents, gqlTagName: 'graphql' })`.
|
|
142
|
+
|
|
143
|
+
You can assert your manifest matches the API contract (`documentId` is the SHA-256
|
|
144
|
+
of the query body):
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
import { readFileSync } from 'node:fs';
|
|
148
|
+
import { createHash } from 'node:crypto';
|
|
149
|
+
|
|
150
|
+
const manifest = JSON.parse(readFileSync('src/gql/persisted-documents.json', 'utf8'));
|
|
151
|
+
for (const [id, body] of Object.entries(manifest)) {
|
|
152
|
+
if (id !== 'sha256:' + createHash('sha256').update(body, 'utf8').digest('hex')) {
|
|
153
|
+
throw new Error('documentId mismatch: ' + id);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
119
158
|
### Advanced: codegen the entire catalog (not recommended for custom storefronts)
|
|
120
159
|
|
|
121
160
|
You *can* hook the package's operation files directly into your codegen as
|
package/codegen.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time codegen recipe for the DoSwiftly Storefront GraphQL API.
|
|
3
|
+
*
|
|
4
|
+
* This is a devDependency helper — NOT runtime code. It returns a `graphql-codegen`
|
|
5
|
+
* configuration wired to this package's schema and to the persisted-document
|
|
6
|
+
* contract the Storefront API expects: every operation is identified by
|
|
7
|
+
* `sha256:<hex of the printed document>` and sent as a short `documentId`, so
|
|
8
|
+
* public reads can be cached at the edge.
|
|
9
|
+
*
|
|
10
|
+
* Requires these devDependencies in your project:
|
|
11
|
+
* @graphql-codegen/cli + @graphql-codegen/client-preset + graphql
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // codegen.ts
|
|
15
|
+
* import { createCodegenConfig } from '@doswiftly/storefront-operations/codegen';
|
|
16
|
+
* export default createCodegenConfig({ documents: 'src/**\/*.{ts,tsx}' });
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const crypto = require('crypto');
|
|
21
|
+
|
|
22
|
+
/** Path to the schema shipped in this package — always matches the installed version. */
|
|
23
|
+
const SCHEMA_PATH = path.join(__dirname, 'schema.graphql');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Compute a persisted-document id for a printed GraphQL document, in the exact
|
|
27
|
+
* format the Storefront API stores and validates: `sha256:` followed by the
|
|
28
|
+
* lowercase hex SHA-256 of the document body. Exposed so you can assert your
|
|
29
|
+
* generated manifest matches (see the README "Verify" snippet).
|
|
30
|
+
*
|
|
31
|
+
* @param {string} documentBody - the printed GraphQL document (operation + its fragments).
|
|
32
|
+
* @returns {string} `sha256:<64 hex chars>`
|
|
33
|
+
*/
|
|
34
|
+
function trustedDocumentHash(documentBody) {
|
|
35
|
+
return 'sha256:' + crypto.createHash('sha256').update(documentBody, 'utf8').digest('hex');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build a `graphql-codegen` config (client preset + persisted documents) pointed
|
|
40
|
+
* at this package's schema, producing `documentId`s in the Storefront API's
|
|
41
|
+
* trusted-document format. `export default` the result from your codegen file.
|
|
42
|
+
*
|
|
43
|
+
* Write operations with the generated `gql(...)` tag. Operations compile to
|
|
44
|
+
* lightweight typed strings (no `graphql` runtime dependency), custom scalars
|
|
45
|
+
* are mapped to precision-safe TypeScript types, and fragment fields are read
|
|
46
|
+
* directly (no unmasking helper) for a simpler developer experience.
|
|
47
|
+
*
|
|
48
|
+
* @param {object} options
|
|
49
|
+
* @param {string | string[]} options.documents - glob(s) for your GraphQL operations.
|
|
50
|
+
* @param {string} [options.outDir='./src/gql/'] - output directory for generated code.
|
|
51
|
+
* @param {string} [options.gqlTagName='gql'] - name of the generated operation tag.
|
|
52
|
+
* Override (e.g. `'graphql'`) if your project already imports a `gql` from
|
|
53
|
+
* another GraphQL client (Apollo, urql, graphql-request) to avoid a clash.
|
|
54
|
+
* @returns {object} a graphql-codegen configuration object.
|
|
55
|
+
*/
|
|
56
|
+
function createCodegenConfig(options) {
|
|
57
|
+
const documents = options && options.documents;
|
|
58
|
+
if (!documents) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'createCodegenConfig: `documents` is required — pass glob(s) pointing at your GraphQL operations.',
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const outDir = (options && options.outDir) || './src/gql/';
|
|
64
|
+
const gqlTagName = (options && options.gqlTagName) || 'gql';
|
|
65
|
+
return {
|
|
66
|
+
schema: SCHEMA_PATH,
|
|
67
|
+
documents,
|
|
68
|
+
ignoreNoDocuments: true,
|
|
69
|
+
generates: {
|
|
70
|
+
[outDir]: {
|
|
71
|
+
preset: 'client',
|
|
72
|
+
config: {
|
|
73
|
+
// Emit each operation as a lightweight typed string (a `String`
|
|
74
|
+
// subclass carrying its result/variable types and persisted-document
|
|
75
|
+
// id), not a parsed AST object. This keeps the `graphql` package out
|
|
76
|
+
// of your runtime bundle and is the shape the Storefront client's
|
|
77
|
+
// `query` / `mutate` accept directly (it reads the query body and the
|
|
78
|
+
// document id off the string — no AST printing at runtime).
|
|
79
|
+
documentMode: 'string',
|
|
80
|
+
// Map the API's custom scalars to the TypeScript types your generated
|
|
81
|
+
// operations use. Money (`Decimal`) and 64-bit integers
|
|
82
|
+
// (`UnsignedInt64`) are serialized as strings to avoid precision loss;
|
|
83
|
+
// dates and URLs are encoded strings; `JSON` is an open object.
|
|
84
|
+
scalars: {
|
|
85
|
+
DateTime: 'string',
|
|
86
|
+
URL: 'string',
|
|
87
|
+
Decimal: 'string',
|
|
88
|
+
UnsignedInt64: 'string',
|
|
89
|
+
JSON: 'Record<string, unknown>',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
presetConfig: {
|
|
93
|
+
// Name the generated document tag `gql(...)` instead of the default
|
|
94
|
+
// `graphql(...)` — shorter, and the conventional name in examples.
|
|
95
|
+
// Overridable via `options.gqlTagName` when a project already imports a
|
|
96
|
+
// `gql` from another GraphQL client.
|
|
97
|
+
gqlTagName,
|
|
98
|
+
// Read fragment fields directly, without an unmasking helper, so a
|
|
99
|
+
// component can use the data it selected as plain typed objects.
|
|
100
|
+
fragmentMasking: false,
|
|
101
|
+
persistedDocuments: {
|
|
102
|
+
// Custom hash → `documentId` matches the Storefront API's trusted-document
|
|
103
|
+
// format exactly (`sha256:<hex>`), so the published manifest is accepted
|
|
104
|
+
// verbatim and the runtime `documentId` resolves server-side.
|
|
105
|
+
hashAlgorithm: trustedDocumentHash,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = { createCodegenConfig, trustedDocumentHash, SCHEMA_PATH };
|
package/llms-full.txt
CHANGED
package/operations.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doswiftly/storefront-operations",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.5.0",
|
|
4
4
|
"description": "GraphQL operations for DoSwiftly Storefront - SSOT from backend",
|
|
5
5
|
"homepage": "https://doswiftly.pl",
|
|
6
6
|
"publishConfig": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"./mutations.graphql": "./mutations.graphql",
|
|
14
14
|
"./fragments.graphql": "./fragments.graphql",
|
|
15
15
|
"./operations.json": "./operations.json",
|
|
16
|
+
"./codegen": "./codegen.js",
|
|
16
17
|
"./*.graphql": "./*.graphql"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
"mutations.graphql",
|
|
34
35
|
"fragments.graphql",
|
|
35
36
|
"operations.json",
|
|
37
|
+
"codegen.js",
|
|
36
38
|
"README.md",
|
|
37
39
|
"AGENTS.md",
|
|
38
40
|
"llms-full.txt",
|