@openlup/core 0.11.0 → 0.12.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 +83 -0
- package/CHANGELOG.md +47 -8
- package/CONTRIBUTING.md +4 -2
- package/MAINTAINERS.md +2 -1
- package/README.md +18 -14
- package/SECURITY.md +4 -4
- package/package.json +2 -11
- package/release-gates.json +16 -14
- package/dist/checkout/idempotency.d.ts +0 -29
- package/dist/checkout/idempotency.js +0 -37
- package/dist/checkout/index.d.ts +0 -2
- package/dist/checkout/index.js +0 -2
- package/src/checkout/idempotency.ts +0 -49
- package/src/checkout/index.ts +0 -2
package/AGENTS.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# `@openlup/core` for agents
|
|
2
|
+
|
|
3
|
+
## Purpose and kind
|
|
4
|
+
|
|
5
|
+
Kind: `kernel`.
|
|
6
|
+
|
|
7
|
+
`@openlup/core` holds the I/O-free contracts and logic that more than one
|
|
8
|
+
`@openlup/*` package, or an application's composition, reads. Its only runtime
|
|
9
|
+
dependency is `zod`. It performs no I/O, reads no environment and starts no
|
|
10
|
+
process: an application binds its ports and composes it.
|
|
11
|
+
|
|
12
|
+
## Subpath maturity
|
|
13
|
+
|
|
14
|
+
| Export | Role | Maturity |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `./bundle` | kernel | candidate |
|
|
17
|
+
| `./catalog` | kernel | candidate |
|
|
18
|
+
| `./company-identity` | kernel | experimental |
|
|
19
|
+
| `./fulfillment` | kernel | experimental |
|
|
20
|
+
| `./inventory` | kernel | candidate |
|
|
21
|
+
| `./marketing/research` | kernel | experimental |
|
|
22
|
+
| `./partners` | kernel | experimental |
|
|
23
|
+
| `./payment` | kernel | experimental |
|
|
24
|
+
| `./platform-runtime` | kernel | experimental |
|
|
25
|
+
| `./pricing` | kernel | candidate |
|
|
26
|
+
| `./promo` | kernel | candidate |
|
|
27
|
+
| `./risk` | kernel | candidate |
|
|
28
|
+
| `./shipping` | kernel | candidate |
|
|
29
|
+
| `./subscription` | kernel | candidate |
|
|
30
|
+
| `./testing` | testing | testing |
|
|
31
|
+
|
|
32
|
+
Any version may change an export, and each change is recorded in
|
|
33
|
+
[the changelog](CHANGELOG.md).
|
|
34
|
+
|
|
35
|
+
## Wiring example
|
|
36
|
+
|
|
37
|
+
The application owns its composition. This example compiles in OpenLup's CI:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import {
|
|
41
|
+
createPlatformBundleRegistry,
|
|
42
|
+
platformEnvSchema,
|
|
43
|
+
type PlatformBundleReadiness,
|
|
44
|
+
type PlatformEnvInput,
|
|
45
|
+
} from "@openlup/core/platform-runtime";
|
|
46
|
+
|
|
47
|
+
// Application composition: the application, not the package, owns its bundles.
|
|
48
|
+
const registry = createPlatformBundleRegistry({
|
|
49
|
+
defaultBundleId: "self-host",
|
|
50
|
+
descriptors: [
|
|
51
|
+
{
|
|
52
|
+
id: "self-host",
|
|
53
|
+
capabilities: {
|
|
54
|
+
http: "node-http",
|
|
55
|
+
scheduler: "cron",
|
|
56
|
+
blob: "filesystem",
|
|
57
|
+
data: "postgres",
|
|
58
|
+
migrations: "sql-files",
|
|
59
|
+
analytics: "none",
|
|
60
|
+
transactional: "smtp",
|
|
61
|
+
},
|
|
62
|
+
readReadiness: (env) =>
|
|
63
|
+
env.APP_BASE_URL ? { ok: true } : { ok: false, error: "APP_BASE_URL is not set" },
|
|
64
|
+
},
|
|
65
|
+
] as const,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export function readPlatformReadiness(input: PlatformEnvInput): PlatformBundleReadiness {
|
|
69
|
+
const env = platformEnvSchema.parse(input);
|
|
70
|
+
return registry.getBundleDescriptor(registry.resolveBundleId(env)).readReadiness(input);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Sources and declarations
|
|
75
|
+
|
|
76
|
+
The tarball ships its TypeScript sources under `src/` and its JavaScript and
|
|
77
|
+
declarations under `dist/`. Each export's `types` condition names its
|
|
78
|
+
declaration file, and its `core-source` condition names its source file. Read
|
|
79
|
+
those before guessing at a contract.
|
|
80
|
+
|
|
81
|
+
## Readiness codes
|
|
82
|
+
|
|
83
|
+
This version raises no `OPENLUP_E_*` readiness code.
|
package/CHANGELOG.md
CHANGED
|
@@ -6,13 +6,24 @@ source previews may already ship some changes, and their release notes say
|
|
|
6
6
|
which. Declaration snapshots track candidate drift, not a stable API or
|
|
7
7
|
SemVer promise.
|
|
8
8
|
|
|
9
|
-
## Unreleased
|
|
9
|
+
## [Unreleased]
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
to the existing payment surface. They describe guidance only and do not change
|
|
13
|
-
payment admission, renewal classification or enabled payment methods.
|
|
11
|
+
## [0.12.0]
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
### Removed
|
|
14
|
+
|
|
15
|
+
- **API REMOVAL: the `./checkout` subpath.** It held only an
|
|
16
|
+
`Idempotency-Key` header-shape helper that no checkout path used.
|
|
17
|
+
|
|
18
|
+
Migration: replace
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { validateCheckoutIdempotencyHeader } from "@openlup/core/checkout";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
with an application-owned validator, or delete the call if, like the
|
|
25
|
+
reference checkout, your checkout carries its idempotency key in the
|
|
26
|
+
request body.
|
|
16
27
|
|
|
17
28
|
### Changed
|
|
18
29
|
|
|
@@ -36,6 +47,15 @@ SemVer promise.
|
|
|
36
47
|
`dunning_not_exhausted`. An exhaustive `switch` over the union must handle
|
|
37
48
|
both.
|
|
38
49
|
|
|
50
|
+
- `release-gates.json` sets `packageRelease.versionRule` to `0.N.P`. Below
|
|
51
|
+
1.0 every `@openlup/*` package carries one set version: a minor set for any
|
|
52
|
+
API, behaviour or schema change, a patch set for a fix only.
|
|
53
|
+
|
|
54
|
+
Migration: a tool that reads `versionRule` expects the set rule. Before:
|
|
55
|
+
`"versionRule": "0.<n>.0"`. After: `"versionRule": "0.N.P"`.
|
|
56
|
+
|
|
57
|
+
- Publishable on the npm `latest` dist-tag as `0.12.0`, from tag
|
|
58
|
+
`openlup-core-v0.12.0`.
|
|
39
59
|
- Publishable on the npm `preview` dist-tag as `0.11.0`, for source preview
|
|
40
60
|
`openlup-source-preview/11`.
|
|
41
61
|
- Publishable on the npm `preview` dist-tag as `0.10.0`, for source preview
|
|
@@ -65,6 +85,22 @@ SemVer promise.
|
|
|
65
85
|
|
|
66
86
|
### Added
|
|
67
87
|
|
|
88
|
+
- `AGENTS.md` ships in the tarball. It states the package's kind and each
|
|
89
|
+
subpath's maturity, gives one wiring example that compiles in CI, points to
|
|
90
|
+
the shipped sources and declarations, and lists the readiness codes the
|
|
91
|
+
package raises (none yet).
|
|
92
|
+
- `release-gates.json` schema 5 declares the package kind (`"kind": "kernel"`)
|
|
93
|
+
and splits the pack budget. Code files (dist JavaScript, declarations and
|
|
94
|
+
shipped sources) and root documentation and metadata files each have their
|
|
95
|
+
own caps on packed bytes and files; the tarball total stays as a backstop.
|
|
96
|
+
|
|
97
|
+
Migration: a tool that reads `release-gates.json` checks `schemaVersion: 5`.
|
|
98
|
+
Before: `"pack": { "maxPackedBytes": …, "maxFiles": … }`. After: `"pack": {
|
|
99
|
+
"code": { "maxPackedBytes": …, "maxFiles": … }, "docs": { … },
|
|
100
|
+
"maxPackedBytes": …, "maxFiles": … }`.
|
|
101
|
+
- Add neutral checkout recovery evidence, method, operation and action contracts
|
|
102
|
+
to the existing payment surface. They describe guidance only and do not change
|
|
103
|
+
payment admission, renewal classification or enabled payment methods.
|
|
68
104
|
- Export neutral lookup normalization from `./company-identity` for extensions.
|
|
69
105
|
|
|
70
106
|
- `SUBSCRIPTION_STATUS_TRANSITIONS`, the frozen status matrix, and
|
|
@@ -226,6 +262,9 @@ SemVer promise.
|
|
|
226
262
|
|
|
227
263
|
## Release Status
|
|
228
264
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
265
|
+
Versions up to `0.11.0` were published on the npm `preview` dist-tag without
|
|
266
|
+
sections of their own, so the `0.12.0` section also lists the changes they
|
|
267
|
+
carried. A release-preparation pull request turns the Unreleased section into
|
|
268
|
+
the next version's section; its release tag and npm record when it is
|
|
269
|
+
published. No version establishes a stable package API or supported upgrade
|
|
270
|
+
channel.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Contributing
|
|
2
2
|
|
|
3
3
|
Commerce Core is public source for framework-independent commerce kernels.
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Below 1.0 its npm versions are set versions `0.N.P`, shared by every
|
|
5
|
+
`@openlup/*` package and published on the `latest` dist-tag; versions up to
|
|
6
|
+
`0.11.0` rode on the source previews (`preview` dist-tag only). No version
|
|
7
|
+
activates a separate package product or stable API.
|
|
6
8
|
|
|
7
9
|
## Set up and verify
|
|
8
10
|
|
package/MAINTAINERS.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Maintainers
|
|
2
2
|
|
|
3
3
|
`@openlup/core` is maintained in the phase-5 platform monorepo. It is not an
|
|
4
|
-
independent product
|
|
4
|
+
independent product. Below 1.0 its versions are set versions `0.N.P`, shared by
|
|
5
|
+
every `@openlup/*` package; versions up to `0.11.0` rode on the source previews.
|
|
5
6
|
|
|
6
7
|
## Responsibilities
|
|
7
8
|
|
package/README.md
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
# Commerce Core
|
|
2
2
|
|
|
3
|
-
`@openlup/core` is
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
`@openlup/core` is the kernel of the `@openlup/*` package family: the
|
|
4
|
+
framework-independent TypeScript contracts and logic for subscription and
|
|
5
|
+
bundle commerce that the other packages and an application's composition read.
|
|
6
|
+
Agents start with [AGENTS.md](AGENTS.md).
|
|
7
|
+
|
|
8
|
+
## Channel and stability
|
|
9
|
+
|
|
10
|
+
- **Channel:** npm, on the `latest` dist-tag. Each version is published with
|
|
11
|
+
provenance from its release tag `openlup-core-v<version>` after a protected
|
|
12
|
+
release approval. Versions up to `0.11.0` were published on the `preview`
|
|
13
|
+
dist-tag only. `npm publish` from this directory is refused.
|
|
14
|
+
- **Versions:** below 1.0 every `@openlup/*` package shares one set version
|
|
15
|
+
`0.N.P`: a minor set for any API, behaviour or schema change, a patch set for
|
|
16
|
+
a fix only.
|
|
17
|
+
- **Stability:** development preview. Any version may change an export, and
|
|
18
|
+
each change is recorded in [the changelog](CHANGELOG.md). Pin an exact
|
|
19
|
+
version and read the changelog when you upgrade.
|
|
12
20
|
|
|
13
21
|
## Package Surface Maturity
|
|
14
22
|
|
|
@@ -20,7 +28,6 @@ promise.
|
|
|
20
28
|
| --- | --- | --- | --- |
|
|
21
29
|
| `./bundle` | kernel | candidate | `smoke/subscriptionBundleStandalone.test.ts` |
|
|
22
30
|
| `./catalog` | kernel | candidate | `smoke/catalogStandalone.test.ts` |
|
|
23
|
-
| `./checkout` | kernel | experimental | `smoke/checkoutStandalone.test.ts` |
|
|
24
31
|
| `./company-identity` | kernel | experimental | `smoke/companyIdentityStandalone.test.ts` |
|
|
25
32
|
| `./fulfillment` | kernel | experimental | `smoke/fulfillmentStandalone.test.ts` |
|
|
26
33
|
| `./inventory` | kernel | candidate | `smoke/inventoryStandalone.test.ts` |
|
|
@@ -55,8 +62,7 @@ npm run ci
|
|
|
55
62
|
```
|
|
56
63
|
|
|
57
64
|
Focused proofs are `npm run api:check`, `npm run release:check`, and
|
|
58
|
-
`npm run test:consumer`. The root test script skips this suite.
|
|
59
|
-
install is evaluation, not a supported install.
|
|
65
|
+
`npm run test:consumer`. The root test script skips this suite.
|
|
60
66
|
|
|
61
67
|
Repository neutrality checks reuse the existing source scanner through
|
|
62
68
|
[the tree counting interface](./scripts/neutrality-tree-counts.ts). This
|
|
@@ -88,5 +94,3 @@ neutrality evidence, not package activation or consumer compatibility evidence.
|
|
|
88
94
|
`./subscription` kernel owns, its deterministic-clock contract, the
|
|
89
95
|
late-payment cycle-shift rule and its monotonic clamp, and how a host
|
|
90
96
|
application consumes it.
|
|
91
|
-
|
|
92
|
-
<!-- openlup-doc-impact {"unit":"core","digest":"sha256-fbf1589b7a2c49f656a295c102b1076d8beaa5180bdc369ba575c462f39ec96f","reason":"The core manifest and lockfile advance only the lockstep version from 0.10.0 to 0.11.0. Exports, dependencies, package smoke, publication settings, and development-preview maturity remain unchanged."} -->
|
package/SECURITY.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Release Support
|
|
4
4
|
|
|
5
|
-
No package version is supported. A `0
|
|
6
|
-
|
|
7
|
-
future support policy belongs to phase-5 public
|
|
8
|
-
separate package release channel.
|
|
5
|
+
No package version is supported. A `0.N.P` version, on the `preview` dist-tag
|
|
6
|
+
up to `0.11.0` or on `latest` after it, is development-preview evaluation, not a
|
|
7
|
+
supported public release. A future support policy belongs to phase-5 public
|
|
8
|
+
platform governance, not to a separate package release channel.
|
|
9
9
|
|
|
10
10
|
## Vulnerability Reporting
|
|
11
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openlup/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Neutral D2C subscription and bundle commerce kernels; a development preview with no stable API.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"dist/**",
|
|
24
24
|
"src/**",
|
|
25
|
+
"AGENTS.md",
|
|
25
26
|
"CHANGELOG.md",
|
|
26
27
|
"CODE_OF_CONDUCT.md",
|
|
27
28
|
"CONTRIBUTING.md",
|
|
@@ -74,16 +75,6 @@
|
|
|
74
75
|
"import": "./dist/bundle/contracts.js",
|
|
75
76
|
"default": "./dist/bundle/contracts.js"
|
|
76
77
|
},
|
|
77
|
-
"./checkout": {
|
|
78
|
-
"core-source": "./src/checkout/index.ts",
|
|
79
|
-
"types": "./dist/checkout/index.d.ts",
|
|
80
|
-
"module": "./dist/checkout/index.js",
|
|
81
|
-
"node": "./dist/checkout/index.js",
|
|
82
|
-
"development": "./dist/checkout/index.js",
|
|
83
|
-
"production": "./dist/checkout/index.js",
|
|
84
|
-
"import": "./dist/checkout/index.js",
|
|
85
|
-
"default": "./dist/checkout/index.js"
|
|
86
|
-
},
|
|
87
78
|
"./company-identity": {
|
|
88
79
|
"core-source": "./src/company-identity/index.ts",
|
|
89
80
|
"types": "./dist/company-identity/index.d.ts",
|
package/release-gates.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
2
|
+
"schemaVersion": 5,
|
|
3
|
+
"kind": "kernel",
|
|
3
4
|
"compatibilityPolicies": {
|
|
4
5
|
"internal-candidate": "Candidate package surfaces may change until the platform phase-5 activation explicitly freezes a public API.",
|
|
5
6
|
"testing-internal": "Test-support surfaces may change and are not runtime compatibility promises."
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
"phase": "platform-monorepo-phase-5",
|
|
9
10
|
"publicStability": "not-claimed",
|
|
10
11
|
"artifactChannel": "npm-staged-preview",
|
|
11
|
-
"versionRule": "0
|
|
12
|
+
"versionRule": "0.N.P"
|
|
12
13
|
},
|
|
13
14
|
"evidence": {
|
|
14
15
|
"packageSmokeEvidence": {
|
|
@@ -53,14 +54,6 @@
|
|
|
53
54
|
"entrypoint": "dist/pricing/index.d.ts",
|
|
54
55
|
"snapshot": "api/pricing.api.md"
|
|
55
56
|
},
|
|
56
|
-
"./checkout": {
|
|
57
|
-
"role": "kernel",
|
|
58
|
-
"maturity": "experimental",
|
|
59
|
-
"compatibilityPolicy": "internal-candidate",
|
|
60
|
-
"packageSmokeEvidence": ["smoke/checkoutStandalone.test.ts"],
|
|
61
|
-
"entrypoint": "dist/checkout/index.d.ts",
|
|
62
|
-
"snapshot": "api/checkout.api.md"
|
|
63
|
-
},
|
|
64
57
|
"./company-identity": {
|
|
65
58
|
"role": "kernel",
|
|
66
59
|
"maturity": "experimental",
|
|
@@ -209,11 +202,20 @@
|
|
|
209
202
|
}
|
|
210
203
|
},
|
|
211
204
|
"pack": {
|
|
212
|
-
"$
|
|
213
|
-
"
|
|
214
|
-
|
|
215
|
-
|
|
205
|
+
"$budgetReason": "2026-10-02, owner-approved at the patch read: the pack budget splits into classes so that documentation and metadata cannot crowd out code, and code growth stays visible. Code counts dist JavaScript, declarations and src TypeScript; docs counts the documentation and metadata files at the package root; anything else counts only toward the total. A class's packed bytes are its files gzipped together. Measured, not estimated: clean origin/main packs 131062 packed bytes, 572032 unpacked bytes and 192 files against caps of 131072, 573440 and 192. With AGENTS.md this change packs about 132.1 thousand packed and 575.7 thousand unpacked bytes and 193 files: code exactly 113573 packed bytes in 183 files, docs about 17.9 thousand packed bytes in 10 files (rounded, because this note's own text moves the last digits). The code caps of 114688 bytes and 183 files admit no new code file without a raise. The docs caps are 24576 bytes and 12 files. The total backstop is the sum of the class caps, 139264 packed bytes and 195 files, with 614400 unpacked bytes.",
|
|
206
|
+
"code": {
|
|
207
|
+
"maxPackedBytes": 114688,
|
|
208
|
+
"maxFiles": 183
|
|
209
|
+
},
|
|
210
|
+
"docs": {
|
|
211
|
+
"maxPackedBytes": 24576,
|
|
212
|
+
"maxFiles": 12
|
|
213
|
+
},
|
|
214
|
+
"maxPackedBytes": 139264,
|
|
215
|
+
"maxUnpackedBytes": 614400,
|
|
216
|
+
"maxFiles": 195,
|
|
216
217
|
"requiredFiles": [
|
|
218
|
+
"AGENTS.md",
|
|
217
219
|
"CHANGELOG.md",
|
|
218
220
|
"CODE_OF_CONDUCT.md",
|
|
219
221
|
"CONTRIBUTING.md",
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reference checkout idempotency-key contract.
|
|
3
|
-
*
|
|
4
|
-
* This module validates the shape of a header-bound idempotency key only. The
|
|
5
|
-
* current product checkout validates body `intent.idempotencyKey`, not this
|
|
6
|
-
* header contract; downstream checkout runtimes must explicitly wire this
|
|
7
|
-
* helper before treating the header as authoritative.
|
|
8
|
-
*
|
|
9
|
-
* Callers own any persistence workflow for inserting, replaying, or completing
|
|
10
|
-
* a checkout idempotency record.
|
|
11
|
-
*/
|
|
12
|
-
/** @beta */
|
|
13
|
-
export declare const CHECKOUT_IDEMPOTENCY_KEY_HEADER = "idempotency-key";
|
|
14
|
-
/** @beta */
|
|
15
|
-
export type CheckoutIdempotencyRejection = {
|
|
16
|
-
reason: "missing";
|
|
17
|
-
message: string;
|
|
18
|
-
} | {
|
|
19
|
-
reason: "malformed";
|
|
20
|
-
message: string;
|
|
21
|
-
};
|
|
22
|
-
/** @beta */
|
|
23
|
-
export declare function validateCheckoutIdempotencyHeader(headerValue: string | undefined | null): {
|
|
24
|
-
ok: true;
|
|
25
|
-
key: string;
|
|
26
|
-
} | {
|
|
27
|
-
ok: false;
|
|
28
|
-
rejection: CheckoutIdempotencyRejection;
|
|
29
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reference checkout idempotency-key contract.
|
|
3
|
-
*
|
|
4
|
-
* This module validates the shape of a header-bound idempotency key only. The
|
|
5
|
-
* current product checkout validates body `intent.idempotencyKey`, not this
|
|
6
|
-
* header contract; downstream checkout runtimes must explicitly wire this
|
|
7
|
-
* helper before treating the header as authoritative.
|
|
8
|
-
*
|
|
9
|
-
* Callers own any persistence workflow for inserting, replaying, or completing
|
|
10
|
-
* a checkout idempotency record.
|
|
11
|
-
*/
|
|
12
|
-
/** @beta */
|
|
13
|
-
export const CHECKOUT_IDEMPOTENCY_KEY_HEADER = "idempotency-key";
|
|
14
|
-
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
15
|
-
/** @beta */
|
|
16
|
-
export function validateCheckoutIdempotencyHeader(headerValue) {
|
|
17
|
-
if (headerValue === undefined || headerValue === null || headerValue.trim().length === 0) {
|
|
18
|
-
return {
|
|
19
|
-
ok: false,
|
|
20
|
-
rejection: {
|
|
21
|
-
reason: "missing",
|
|
22
|
-
message: `Missing required ${CHECKOUT_IDEMPOTENCY_KEY_HEADER} header.`,
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
const trimmed = headerValue.trim();
|
|
27
|
-
if (!UUID_V4_PATTERN.test(trimmed)) {
|
|
28
|
-
return {
|
|
29
|
-
ok: false,
|
|
30
|
-
rejection: {
|
|
31
|
-
reason: "malformed",
|
|
32
|
-
message: `${CHECKOUT_IDEMPOTENCY_KEY_HEADER} must be a UUID v4.`,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
return { ok: true, key: trimmed };
|
|
37
|
-
}
|
package/dist/checkout/index.d.ts
DELETED
package/dist/checkout/index.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reference checkout idempotency-key contract.
|
|
3
|
-
*
|
|
4
|
-
* This module validates the shape of a header-bound idempotency key only. The
|
|
5
|
-
* current product checkout validates body `intent.idempotencyKey`, not this
|
|
6
|
-
* header contract; downstream checkout runtimes must explicitly wire this
|
|
7
|
-
* helper before treating the header as authoritative.
|
|
8
|
-
*
|
|
9
|
-
* Callers own any persistence workflow for inserting, replaying, or completing
|
|
10
|
-
* a checkout idempotency record.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/** @beta */
|
|
14
|
-
export const CHECKOUT_IDEMPOTENCY_KEY_HEADER = "idempotency-key";
|
|
15
|
-
|
|
16
|
-
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
17
|
-
|
|
18
|
-
/** @beta */
|
|
19
|
-
export type CheckoutIdempotencyRejection =
|
|
20
|
-
| { reason: "missing"; message: string }
|
|
21
|
-
| { reason: "malformed"; message: string };
|
|
22
|
-
|
|
23
|
-
/** @beta */
|
|
24
|
-
export function validateCheckoutIdempotencyHeader(
|
|
25
|
-
headerValue: string | undefined | null,
|
|
26
|
-
): { ok: true; key: string } | { ok: false; rejection: CheckoutIdempotencyRejection } {
|
|
27
|
-
if (headerValue === undefined || headerValue === null || headerValue.trim().length === 0) {
|
|
28
|
-
return {
|
|
29
|
-
ok: false,
|
|
30
|
-
rejection: {
|
|
31
|
-
reason: "missing",
|
|
32
|
-
message: `Missing required ${CHECKOUT_IDEMPOTENCY_KEY_HEADER} header.`,
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const trimmed = headerValue.trim();
|
|
38
|
-
if (!UUID_V4_PATTERN.test(trimmed)) {
|
|
39
|
-
return {
|
|
40
|
-
ok: false,
|
|
41
|
-
rejection: {
|
|
42
|
-
reason: "malformed",
|
|
43
|
-
message: `${CHECKOUT_IDEMPOTENCY_KEY_HEADER} must be a UUID v4.`,
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return { ok: true, key: trimmed };
|
|
49
|
-
}
|
package/src/checkout/index.ts
DELETED