@openlup/core 0.11.0 → 0.13.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 +103 -0
- package/CHANGELOG.md +64 -8
- package/CONTRIBUTING.md +4 -2
- package/MAINTAINERS.md +2 -1
- package/README.md +59 -21
- package/SECURITY.md +4 -4
- package/dist/outbox/index.d.ts +55 -0
- package/dist/outbox/index.js +1 -0
- package/dist/outbox/vocabulary.d.ts +7 -0
- package/dist/outbox/vocabulary.js +36 -0
- package/dist/platform-runtime/index.d.ts +1 -0
- package/dist/platform-runtime/ports.d.ts +24 -0
- package/dist/readiness/contracts.d.ts +121 -0
- package/dist/readiness/contracts.js +2 -0
- package/dist/readiness/declarations.d.ts +45 -0
- package/dist/readiness/declarations.js +58 -0
- package/dist/readiness/index.d.ts +5 -0
- package/dist/readiness/index.js +147 -0
- package/dist/readiness/schemaProbe.d.ts +13 -0
- package/dist/readiness/schemaProbe.js +25 -0
- package/dist/standard-schema/index.d.ts +26 -0
- package/dist/standard-schema/index.js +1 -0
- package/docs/SUBSCRIPTION_ENGINE.md +235 -0
- package/package.json +33 -11
- package/release-gates.json +91 -29
- package/src/outbox/index.ts +44 -0
- package/src/outbox/vocabulary.ts +38 -0
- package/src/platform-runtime/index.ts +2 -0
- package/src/platform-runtime/ports.ts +43 -0
- package/src/readiness/contracts.ts +57 -0
- package/src/readiness/declarations.ts +38 -0
- package/src/readiness/index.ts +97 -0
- package/src/readiness/schemaProbe.ts +24 -0
- package/src/standard-schema/index.ts +17 -0
- 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,103 @@
|
|
|
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
|
+
| `./outbox` | kernel | experimental |
|
|
31
|
+
| `./readiness` | kernel | experimental |
|
|
32
|
+
| `./standard-schema` | kernel | experimental |
|
|
33
|
+
| `./testing` | testing | testing |
|
|
34
|
+
|
|
35
|
+
Any version may change an export, and each change is recorded in
|
|
36
|
+
[the changelog](CHANGELOG.md).
|
|
37
|
+
|
|
38
|
+
## Wiring example
|
|
39
|
+
|
|
40
|
+
The application owns its composition. This example compiles in OpenLup's CI:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import {
|
|
44
|
+
createPlatformBundleRegistry,
|
|
45
|
+
platformEnvSchema,
|
|
46
|
+
type PlatformBundleReadiness,
|
|
47
|
+
type PlatformEnvInput,
|
|
48
|
+
} from "@openlup/core/platform-runtime";
|
|
49
|
+
|
|
50
|
+
// Application composition: the application, not the package, owns its bundles.
|
|
51
|
+
const registry = createPlatformBundleRegistry({
|
|
52
|
+
defaultBundleId: "self-host",
|
|
53
|
+
descriptors: [
|
|
54
|
+
{
|
|
55
|
+
id: "self-host",
|
|
56
|
+
capabilities: {
|
|
57
|
+
http: "node-http",
|
|
58
|
+
scheduler: "cron",
|
|
59
|
+
blob: "filesystem",
|
|
60
|
+
data: "postgres",
|
|
61
|
+
migrations: "sql-files",
|
|
62
|
+
analytics: "none",
|
|
63
|
+
transactional: "smtp",
|
|
64
|
+
},
|
|
65
|
+
readReadiness: (env) =>
|
|
66
|
+
env.APP_BASE_URL ? { ok: true } : { ok: false, error: "APP_BASE_URL is not set" },
|
|
67
|
+
},
|
|
68
|
+
] as const,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export function readPlatformReadiness(input: PlatformEnvInput): PlatformBundleReadiness {
|
|
72
|
+
const env = platformEnvSchema.parse(input);
|
|
73
|
+
return registry.getBundleDescriptor(registry.resolveBundleId(env)).readReadiness(input);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Sources and declarations
|
|
78
|
+
|
|
79
|
+
The tarball ships its TypeScript sources under `src/` and its JavaScript and
|
|
80
|
+
declarations under `dist/`. Each export's `types` condition names its
|
|
81
|
+
declaration file, and its `core-source` condition names its source file. Read
|
|
82
|
+
those before guessing at a contract.
|
|
83
|
+
|
|
84
|
+
## Readiness codes
|
|
85
|
+
|
|
86
|
+
The checker reports `OPENLUP_E_PORT_MISSING`, `OPENLUP_E_EVENT_UNHANDLED`,
|
|
87
|
+
`OPENLUP_E_EVENT_DUPLICATE`, `OPENLUP_E_SCHEDULE_UNBOUND`, `OPENLUP_E_SCHEMA_BEHIND`,
|
|
88
|
+
`OPENLUP_E_SET_MISMATCH` and `OPENLUP_E_ENV_MISSING`. Only a `ready` report admits
|
|
89
|
+
its exact candidate. A host must provide complete installed metadata and selected-adapter
|
|
90
|
+
observations; a report does not prove ACL, function bodies or recovery.
|
|
91
|
+
|
|
92
|
+
## Using this package in an application
|
|
93
|
+
|
|
94
|
+
- **Do not edit the installed package.** Do not change files under `node_modules/@openlup/`, and
|
|
95
|
+
do not patch it with `patch-package`, `overrides` or a fork.
|
|
96
|
+
- **Change behaviour through seams.** Use this package's ports and options and your application's
|
|
97
|
+
own composition. If a seam is missing, raise an upstream issue.
|
|
98
|
+
- **Copying source is ejection.** Copying this package's source into your application makes the
|
|
99
|
+
copy yours, including its upgrades.
|
|
100
|
+
- **Upgrade every `@openlup/*` package together,** after reading each changelog's `Migration:`
|
|
101
|
+
blocks.
|
|
102
|
+
- **Inside the OpenLup monorepo,** where this package is a workspace, the repository's root
|
|
103
|
+
`AGENTS.md` governs instead.
|
package/CHANGELOG.md
CHANGED
|
@@ -6,13 +6,41 @@ 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.13.0]
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
- Publishable on the npm `latest` dist-tag as `0.13.0`, from tag
|
|
14
|
+
`openlup-core-v0.13.0`.
|
|
15
|
+
|
|
16
|
+
- Add experimental outbox envelope/handler descriptors, structural validation, job lease and candidate readiness contracts.
|
|
17
|
+
- Check package inventory, event ownership/coverage, actual bindings and qualified schema observations before admitting a new candidate.
|
|
18
|
+
|
|
19
|
+
Migration: existing exports remain; compose the selected rail and bind its schema probe before activation. Unknown observations refuse the new candidate and do not stop a serving version.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- `AGENTS.md` gains a required "Using this package in an application" section: do not edit or
|
|
25
|
+
patch the installed package, change behaviour through its seams, and upgrade every
|
|
26
|
+
`@openlup/*` package together. `docs:check` refuses a guide without it.
|
|
27
|
+
|
|
28
|
+
## [0.12.0]
|
|
29
|
+
|
|
30
|
+
### Removed
|
|
31
|
+
|
|
32
|
+
- **API REMOVAL: the `./checkout` subpath.** It held only an
|
|
33
|
+
`Idempotency-Key` header-shape helper that no checkout path used.
|
|
34
|
+
|
|
35
|
+
Migration: replace
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { validateCheckoutIdempotencyHeader } from "@openlup/core/checkout";
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
with an application-owned validator, or delete the call if, like the
|
|
42
|
+
reference checkout, your checkout carries its idempotency key in the
|
|
43
|
+
request body.
|
|
16
44
|
|
|
17
45
|
### Changed
|
|
18
46
|
|
|
@@ -36,6 +64,15 @@ SemVer promise.
|
|
|
36
64
|
`dunning_not_exhausted`. An exhaustive `switch` over the union must handle
|
|
37
65
|
both.
|
|
38
66
|
|
|
67
|
+
- `release-gates.json` sets `packageRelease.versionRule` to `0.N.P`. Below
|
|
68
|
+
1.0 every `@openlup/*` package carries one set version: a minor set for any
|
|
69
|
+
API, behaviour or schema change, a patch set for a fix only.
|
|
70
|
+
|
|
71
|
+
Migration: a tool that reads `versionRule` expects the set rule. Before:
|
|
72
|
+
`"versionRule": "0.<n>.0"`. After: `"versionRule": "0.N.P"`.
|
|
73
|
+
|
|
74
|
+
- Publishable on the npm `latest` dist-tag as `0.12.0`, from tag
|
|
75
|
+
`openlup-core-v0.12.0`.
|
|
39
76
|
- Publishable on the npm `preview` dist-tag as `0.11.0`, for source preview
|
|
40
77
|
`openlup-source-preview/11`.
|
|
41
78
|
- Publishable on the npm `preview` dist-tag as `0.10.0`, for source preview
|
|
@@ -65,6 +102,22 @@ SemVer promise.
|
|
|
65
102
|
|
|
66
103
|
### Added
|
|
67
104
|
|
|
105
|
+
- `AGENTS.md` ships in the tarball. It states the package's kind and each
|
|
106
|
+
subpath's maturity, gives one wiring example that compiles in CI, points to
|
|
107
|
+
the shipped sources and declarations, and lists the readiness codes the
|
|
108
|
+
package raises (none yet).
|
|
109
|
+
- `release-gates.json` schema 5 declares the package kind (`"kind": "kernel"`)
|
|
110
|
+
and splits the pack budget. Code files (dist JavaScript, declarations and
|
|
111
|
+
shipped sources) and root documentation and metadata files each have their
|
|
112
|
+
own caps on packed bytes and files; the tarball total stays as a backstop.
|
|
113
|
+
|
|
114
|
+
Migration: a tool that reads `release-gates.json` checks `schemaVersion: 5`.
|
|
115
|
+
Before: `"pack": { "maxPackedBytes": …, "maxFiles": … }`. After: `"pack": {
|
|
116
|
+
"code": { "maxPackedBytes": …, "maxFiles": … }, "docs": { … },
|
|
117
|
+
"maxPackedBytes": …, "maxFiles": … }`.
|
|
118
|
+
- Add neutral checkout recovery evidence, method, operation and action contracts
|
|
119
|
+
to the existing payment surface. They describe guidance only and do not change
|
|
120
|
+
payment admission, renewal classification or enabled payment methods.
|
|
68
121
|
- Export neutral lookup normalization from `./company-identity` for extensions.
|
|
69
122
|
|
|
70
123
|
- `SUBSCRIPTION_STATUS_TRANSITIONS`, the frozen status matrix, and
|
|
@@ -226,6 +279,9 @@ SemVer promise.
|
|
|
226
279
|
|
|
227
280
|
## Release Status
|
|
228
281
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
282
|
+
Versions up to `0.11.0` were published on the npm `preview` dist-tag without
|
|
283
|
+
sections of their own, so the `0.12.0` section also lists the changes they
|
|
284
|
+
carried. A release-preparation pull request turns the Unreleased section into
|
|
285
|
+
the next version's section; its release tag and npm record when it is
|
|
286
|
+
published. No version establishes a stable package API or supported upgrade
|
|
287
|
+
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,27 @@
|
|
|
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). Its "Using this package in an
|
|
7
|
+
application" section, which `docs:check` requires, tells an application's agent
|
|
8
|
+
not to edit or patch the installed package and to upgrade every `@openlup/*`
|
|
9
|
+
package together.
|
|
10
|
+
|
|
11
|
+
## Channel and stability
|
|
12
|
+
|
|
13
|
+
- **Channel:** npm, on the `latest` dist-tag. Each version is published with
|
|
14
|
+
provenance from its release tag `openlup-core-v<version>` after a protected
|
|
15
|
+
release approval. Versions up to `0.11.0` were published on the `preview`
|
|
16
|
+
dist-tag only. `npm publish` from this directory is refused.
|
|
17
|
+
- **Versions:** below 1.0 every `@openlup/*` package shares one set version
|
|
18
|
+
`0.N.P`: a minor set for any API, behaviour or schema change, a patch set for
|
|
19
|
+
a fix only.
|
|
20
|
+
- **Stability:** development preview. Any version may change an export, and
|
|
21
|
+
each change is recorded in [the changelog](CHANGELOG.md). Pin an exact
|
|
22
|
+
version and read the changelog when you upgrade.
|
|
23
|
+
|
|
24
|
+
The experimental `./outbox`, `./standard-schema` and `./readiness` subpaths provide shared infrastructure contracts. `checkReadiness` evaluates inert contribution descriptors, the complete host-observed package set, actual host bindings (schedule/route function identity must match the contribution) and a bounded schema probe. It never migrates, leases or sends. Only `ready` admits a new candidate; `unknown` and `unsatisfied` leave the serving candidate in place. The host owns inventory completeness, immutable artifact/configuration/schema identity and admission at every work entrance. Catalog existence does not prove SQL bodies, permissions or provider recovery.
|
|
12
25
|
|
|
13
26
|
## Package Surface Maturity
|
|
14
27
|
|
|
@@ -20,7 +33,6 @@ promise.
|
|
|
20
33
|
| --- | --- | --- | --- |
|
|
21
34
|
| `./bundle` | kernel | candidate | `smoke/subscriptionBundleStandalone.test.ts` |
|
|
22
35
|
| `./catalog` | kernel | candidate | `smoke/catalogStandalone.test.ts` |
|
|
23
|
-
| `./checkout` | kernel | experimental | `smoke/checkoutStandalone.test.ts` |
|
|
24
36
|
| `./company-identity` | kernel | experimental | `smoke/companyIdentityStandalone.test.ts` |
|
|
25
37
|
| `./fulfillment` | kernel | experimental | `smoke/fulfillmentStandalone.test.ts` |
|
|
26
38
|
| `./inventory` | kernel | candidate | `smoke/inventoryStandalone.test.ts` |
|
|
@@ -33,6 +45,9 @@ promise.
|
|
|
33
45
|
| `./risk` | kernel | candidate | `smoke/riskStandalone.test.ts` |
|
|
34
46
|
| `./shipping` | kernel | candidate | `smoke/shippingStandalone.test.ts` |
|
|
35
47
|
| `./subscription` | kernel | candidate | `smoke/subscriptionBundleStandalone.test.ts` |
|
|
48
|
+
| `./outbox` | kernel | experimental | `smoke/outboxStandalone.test.ts` |
|
|
49
|
+
| `./readiness` | kernel | experimental | `smoke/readinessStandalone.test.ts` |
|
|
50
|
+
| `./standard-schema` | kernel | experimental | `smoke/standardSchemaStandalone.test.ts` |
|
|
36
51
|
| `./testing` | testing | testing | `smoke/testingStandalone.test.ts` |
|
|
37
52
|
|
|
38
53
|
`release-gates.json` records four distinct evidence classes:
|
|
@@ -45,9 +60,26 @@ promise.
|
|
|
45
60
|
- `externalConsumerEvidence`: not yet evaluated; a first-party packed consumer
|
|
46
61
|
remains package smoke, not external adoption.
|
|
47
62
|
|
|
48
|
-
##
|
|
63
|
+
## Use in an application
|
|
64
|
+
|
|
65
|
+
From your application's root, with Node 24 and npm 11.19.0:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npm install --save-exact @openlup/core@0.12.0
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Read the installed `AGENTS.md`, then compose the [typed wiring example](AGENTS.md#wiring-example)
|
|
72
|
+
with your application's own ports and options. Inspect the shipped sources and
|
|
73
|
+
declarations for the exact version you installed. A missing seam needs an
|
|
74
|
+
upstream proposal under your application's submission authority; the dependency
|
|
75
|
+
guide grants no permission to publish an issue or change your application.
|
|
76
|
+
Keep every installed `@openlup/*` package on the same exact set version.
|
|
77
|
+
|
|
78
|
+
## Local verification from source
|
|
49
79
|
|
|
50
|
-
|
|
80
|
+
The following developer commands require a source checkout of this package;
|
|
81
|
+
the npm tarball omits its development scripts and tests. From the source package
|
|
82
|
+
directory:
|
|
51
83
|
|
|
52
84
|
```sh
|
|
53
85
|
npm ci
|
|
@@ -55,12 +87,18 @@ npm run ci
|
|
|
55
87
|
```
|
|
56
88
|
|
|
57
89
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
90
|
+
`npm run test:consumer`. The root test script skips this suite.
|
|
91
|
+
`npm run docs:check` requires relative links in shipped Markdown to resolve to
|
|
92
|
+
files actually packed in the tarball; a target present only in source refuses.
|
|
93
|
+
Ambiguous destinations refuse explicitly: use literal punctuation or
|
|
94
|
+
percent-encoded filenames, with ASCII whitespace before an optional title.
|
|
95
|
+
Raw ampersands, angle characters and Unicode whitespace in local destinations
|
|
96
|
+
require a canonical rewrite rather than passing an incomplete link check.
|
|
97
|
+
|
|
98
|
+
The [repository neutrality checks](https://github.com/openlup/openlup/blob/openlup-core-v0.12.0/CONTRIBUTING.md#development-preview-checks)
|
|
99
|
+
reuse the source scanner through `./scripts/neutrality-tree-counts.ts` relative
|
|
100
|
+
to this source package. This process interface reads JSON containing source paths,
|
|
101
|
+
contents and a policy
|
|
64
102
|
from standard input, then emits finding counts for each path. Shell sources
|
|
65
103
|
retain the scanner's existing shell handling. The interface adds no package
|
|
66
104
|
export and changes no matcher or kernel behavior.
|
|
@@ -68,7 +106,7 @@ export and changes no matcher or kernel behavior.
|
|
|
68
106
|
Repository lint keeps this package's production source independent of configured
|
|
69
107
|
provider SDKs and explicit industry contract names. Adopter adapters compose
|
|
70
108
|
providers; generic ports can forward opaque extension data. See the
|
|
71
|
-
[syntax scope and exceptions](https://github.com/openlup/openlup/blob/
|
|
109
|
+
[syntax scope and exceptions](https://github.com/openlup/openlup/blob/openlup-core-v0.12.0/CONTRIBUTING.md#development-preview-checks).
|
|
72
110
|
|
|
73
111
|
The repository checker also calls the UI neutrality counting process with
|
|
74
112
|
`--counts-json` to count its existing patterns over the supplied sources. Running that checker without
|
|
@@ -84,9 +122,9 @@ neutrality evidence, not package activation or consumer compatibility evidence.
|
|
|
84
122
|
|
|
85
123
|
## Kernel Documentation
|
|
86
124
|
|
|
125
|
+
<!-- openlup-doc-impact {"unit":"core","digest":"sha256-bf338e121135843e55d78dab92d8620fd1dcd67be34e9302aef01ea893d361ba","reason":"Release preparation changes only the core manifest and its lockfile version from 0.12.0 to 0.13.0. Exports, dependencies, API snapshots, implementation, package gates and the installation and verification guidance remain unchanged; the changelog identifies the prepared set."} -->
|
|
126
|
+
|
|
87
127
|
- [`docs/SUBSCRIPTION_ENGINE.md`](docs/SUBSCRIPTION_ENGINE.md) — what the
|
|
88
128
|
`./subscription` kernel owns, its deterministic-clock contract, the
|
|
89
129
|
late-payment cycle-shift rule and its monotonic clamp, and how a host
|
|
90
130
|
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
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** @beta Shared event envelope. Storage and execution policy belong to the rail. */
|
|
2
|
+
export interface OutboxEventRow {
|
|
3
|
+
id: string;
|
|
4
|
+
created_at: string;
|
|
5
|
+
available_at: string;
|
|
6
|
+
processed_at: string | null;
|
|
7
|
+
aggregate_type: string;
|
|
8
|
+
aggregate_id: string;
|
|
9
|
+
event_type: string;
|
|
10
|
+
idempotency_key: string;
|
|
11
|
+
status: string;
|
|
12
|
+
attempts: number;
|
|
13
|
+
payload: Record<string, unknown>;
|
|
14
|
+
error: string | null;
|
|
15
|
+
metadata: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
/** @beta */
|
|
18
|
+
export type OutboxHandlerOutcome = {
|
|
19
|
+
kind: "processed";
|
|
20
|
+
detail?: Record<string, unknown>;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "retry";
|
|
23
|
+
reason: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "discard";
|
|
26
|
+
reason: string;
|
|
27
|
+
benign?: boolean;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "snooze";
|
|
30
|
+
reason: string;
|
|
31
|
+
};
|
|
32
|
+
/** @beta Phase observations are transient; never put payloads or credentials here. */
|
|
33
|
+
export interface OutboxHandlerExecutionContext {
|
|
34
|
+
setPhase(phase: string): void;
|
|
35
|
+
}
|
|
36
|
+
/** @beta Inert registration shared by preflight and the run-bound builder. */
|
|
37
|
+
export interface OutboxHandlerDescriptor {
|
|
38
|
+
readonly eventType: string;
|
|
39
|
+
readonly timeoutMs: number;
|
|
40
|
+
}
|
|
41
|
+
/** @beta Structural abort signal, shared by browser and server implementations. */
|
|
42
|
+
export interface OutboxAbortSignal {
|
|
43
|
+
readonly aborted: boolean;
|
|
44
|
+
readonly reason: unknown;
|
|
45
|
+
addEventListener(type: "abort", listener: () => void, options?: {
|
|
46
|
+
once?: boolean;
|
|
47
|
+
}): void;
|
|
48
|
+
removeEventListener(type: "abort", listener: () => void): void;
|
|
49
|
+
}
|
|
50
|
+
/** @beta Effects must be idempotent and honor the abort signal. */
|
|
51
|
+
export interface OutboxHandler<Signal extends OutboxAbortSignal = OutboxAbortSignal> extends OutboxHandlerDescriptor {
|
|
52
|
+
handle(row: OutboxEventRow, signal: Signal, execution?: OutboxHandlerExecutionContext): Promise<OutboxHandlerOutcome>;
|
|
53
|
+
}
|
|
54
|
+
export { PLATFORM_EVENT_VOCABULARY } from "./vocabulary.js";
|
|
55
|
+
export type { EventVocabularyEntry } from "./vocabulary.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { PLATFORM_EVENT_VOCABULARY } from "./vocabulary.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @beta Vocabulary ownership is separate from consumer registration. */
|
|
2
|
+
export interface EventVocabularyEntry {
|
|
3
|
+
eventType: string;
|
|
4
|
+
owner: string;
|
|
5
|
+
}
|
|
6
|
+
/** @beta Applications supply their complete ordered persisted vocabulary separately. */
|
|
7
|
+
export declare const PLATFORM_EVENT_VOCABULARY: readonly EventVocabularyEntry[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** @beta Applications supply their complete ordered persisted vocabulary separately. */
|
|
2
|
+
export const PLATFORM_EVENT_VOCABULARY = [
|
|
3
|
+
{ eventType: "commerce.order_draft.created", owner: "@openlup/core" },
|
|
4
|
+
{ eventType: "commerce.order.paid", owner: "@openlup/core" },
|
|
5
|
+
{ eventType: "commerce.order.paid.email", owner: "@openlup/core" },
|
|
6
|
+
{ eventType: "commerce.payment.failed", owner: "@openlup/core" },
|
|
7
|
+
{ eventType: "commerce.checkout.expired", owner: "@openlup/core" },
|
|
8
|
+
{ eventType: "commerce.order.canceled", owner: "@openlup/core" },
|
|
9
|
+
{ eventType: "commerce.order.refunded", owner: "@openlup/core" },
|
|
10
|
+
{ eventType: "commerce.shipment.dispatched", owner: "@openlup/core" },
|
|
11
|
+
{ eventType: "commerce.shipment.delivered", owner: "@openlup/core" },
|
|
12
|
+
{ eventType: "commerce.shipment.exception", owner: "@openlup/core" },
|
|
13
|
+
{ eventType: "commerce.return.approved", owner: "@openlup/core" },
|
|
14
|
+
{ eventType: "commerce.return.rejected", owner: "@openlup/core" },
|
|
15
|
+
{ eventType: "commerce.order.review_request", owner: "@openlup/core" },
|
|
16
|
+
{ eventType: "commerce.order.review_effects", owner: "@openlup/core" },
|
|
17
|
+
{ eventType: "commerce.product.back_in_stock", owner: "@openlup/core" },
|
|
18
|
+
{ eventType: "commerce.order_draft.abandoned.1h", owner: "@openlup/core" },
|
|
19
|
+
{ eventType: "commerce.order_draft.abandoned.24h", owner: "@openlup/core" },
|
|
20
|
+
{ eventType: "commerce.order_draft.abandoned.72h", owner: "@openlup/core" },
|
|
21
|
+
{ eventType: "commerce.order.reorder_reminder", owner: "@openlup/core" },
|
|
22
|
+
{ eventType: "commerce.checkout_recovery", owner: "@openlup/core" },
|
|
23
|
+
{ eventType: "subscription.cancelled", owner: "@openlup/core" },
|
|
24
|
+
{ eventType: "subscription.created", owner: "@openlup/core" },
|
|
25
|
+
{ eventType: "subscription.activation_action_required", owner: "@openlup/core" },
|
|
26
|
+
{ eventType: "subscription.pause_reminder_due", owner: "@openlup/core" },
|
|
27
|
+
{ eventType: "subscription.paused", owner: "@openlup/core" },
|
|
28
|
+
{ eventType: "subscription.resumed", owner: "@openlup/core" },
|
|
29
|
+
{ eventType: "subscription.delivery_rescheduled", owner: "@openlup/core" },
|
|
30
|
+
{ eventType: "subscription.cycle_skipped", owner: "@openlup/core" },
|
|
31
|
+
{ eventType: "subscription.address_changed", owner: "@openlup/core" },
|
|
32
|
+
{ eventType: "subscription.package_changed", owner: "@openlup/core" },
|
|
33
|
+
{ eventType: "subscription.renewal_upcoming", owner: "@openlup/core" },
|
|
34
|
+
{ eventType: "accounting.order.reversal_requested", owner: "@openlup/core" },
|
|
35
|
+
{ eventType: "commerce.fulfillment.handed_over", owner: "@openlup/core" },
|
|
36
|
+
];
|
|
@@ -8,3 +8,4 @@ export { createPlatformBundleRegistry, platformEnvSchema, } from "./platformKern
|
|
|
8
8
|
export type { CreatePlatformBundleRegistryInput, PlatformBundleDescriptor, PlatformBundleRegistry, PlatformBundleReadiness, PlatformEnv, PlatformEnvInput, } from "./platformKernel.js";
|
|
9
9
|
/** @beta */
|
|
10
10
|
export type { AnalyticsPort, BlobStoragePort, DataGatewayPort, HttpRuntimePort, MigrationRunnerPort, PlatformHttpRequest, PlatformHttpResponse, SchedulerPort, TransactionalRuntimePort, } from "./ports.js";
|
|
11
|
+
export type { JobLeasePort, PlatformJobTriggerKind, PlatformJobInvocation, PlatformJobClaim, PlatformJobFinishStatus, PlatformJobFinishSummary } from "./ports.js";
|
|
@@ -98,3 +98,27 @@ export interface TransactionalRuntimePort {
|
|
|
98
98
|
status: number;
|
|
99
99
|
}>;
|
|
100
100
|
}
|
|
101
|
+
/** @beta Invocation evidence and claim/finish contract shared by infrastructure rails. */
|
|
102
|
+
export type PlatformJobTriggerKind = "worker" | "scheduler" | "operator";
|
|
103
|
+
export type PlatformJobInvocation = {
|
|
104
|
+
triggerKind: PlatformJobTriggerKind;
|
|
105
|
+
/** Observational adapter evidence; it never grants execution authority. */
|
|
106
|
+
invocationSource: string;
|
|
107
|
+
};
|
|
108
|
+
export type PlatformJobClaim = {
|
|
109
|
+
acquired: boolean;
|
|
110
|
+
runId: string | null;
|
|
111
|
+
reason: string;
|
|
112
|
+
};
|
|
113
|
+
export type PlatformJobFinishStatus = "success" | "failed";
|
|
114
|
+
export type PlatformJobFinishSummary = {
|
|
115
|
+
checked: number;
|
|
116
|
+
updated: number;
|
|
117
|
+
failures: number;
|
|
118
|
+
skipped: boolean;
|
|
119
|
+
reason?: string;
|
|
120
|
+
};
|
|
121
|
+
export interface JobLeasePort {
|
|
122
|
+
claimJobRun(jobName: string, invocation: PlatformJobInvocation, leaseSeconds?: number): Promise<PlatformJobClaim>;
|
|
123
|
+
finishJobRun(jobName: string, runId: string, invocation: PlatformJobInvocation, status: PlatformJobFinishStatus, result: PlatformJobFinishSummary, extraMetadata?: Record<string, unknown>): Promise<boolean>;
|
|
124
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { OutboxHandlerDescriptor } from "../outbox/index.js";
|
|
2
|
+
import type { EventVocabularyEntry } from "../outbox/vocabulary.js";
|
|
3
|
+
/** @beta */
|
|
4
|
+
export declare const READINESS_CODES: readonly ["OPENLUP_E_PORT_MISSING", "OPENLUP_E_EVENT_UNHANDLED", "OPENLUP_E_EVENT_DUPLICATE", "OPENLUP_E_SCHEDULE_UNBOUND", "OPENLUP_E_SCHEMA_BEHIND", "OPENLUP_E_SET_MISMATCH", "OPENLUP_E_ENV_MISSING"];
|
|
5
|
+
/** @beta */
|
|
6
|
+
export type ReadinessCode = typeof READINESS_CODES[number];
|
|
7
|
+
/** @beta */
|
|
8
|
+
export interface ReadinessIssue {
|
|
9
|
+
code: ReadinessCode;
|
|
10
|
+
package: string;
|
|
11
|
+
subject: string;
|
|
12
|
+
fix: string;
|
|
13
|
+
observation?: string;
|
|
14
|
+
}
|
|
15
|
+
/** @beta */
|
|
16
|
+
export interface SchemaObject {
|
|
17
|
+
kind: "table" | "column" | "function";
|
|
18
|
+
name: string;
|
|
19
|
+
signature?: string;
|
|
20
|
+
}
|
|
21
|
+
/** @beta Version is an adapter-specific migration identity, not inferred from object existence. */
|
|
22
|
+
export interface RequiredSchema {
|
|
23
|
+
version: string;
|
|
24
|
+
migration: string;
|
|
25
|
+
objects: readonly SchemaObject[];
|
|
26
|
+
}
|
|
27
|
+
/** @beta */
|
|
28
|
+
export interface PackageManifest {
|
|
29
|
+
name: string;
|
|
30
|
+
version: string;
|
|
31
|
+
kind: "kernel" | "rail" | "capability" | "implementation";
|
|
32
|
+
emits: readonly string[];
|
|
33
|
+
handles: readonly string[];
|
|
34
|
+
schedules: readonly {
|
|
35
|
+
id: string;
|
|
36
|
+
cadenceSeconds: number;
|
|
37
|
+
}[];
|
|
38
|
+
routes: readonly string[];
|
|
39
|
+
requiredPorts: readonly string[];
|
|
40
|
+
env: readonly string[];
|
|
41
|
+
requiredSchema?: RequiredSchema;
|
|
42
|
+
}
|
|
43
|
+
/** @beta Run-bound handlers are represented by their shared inert descriptors. */
|
|
44
|
+
export interface Contribution {
|
|
45
|
+
manifest: PackageManifest;
|
|
46
|
+
handlers: readonly OutboxHandlerDescriptor[];
|
|
47
|
+
schedules: readonly {
|
|
48
|
+
id: string;
|
|
49
|
+
cadenceSeconds: number;
|
|
50
|
+
run: (...args: never[]) => unknown;
|
|
51
|
+
}[];
|
|
52
|
+
routes: readonly {
|
|
53
|
+
id: string;
|
|
54
|
+
handle: (...args: never[]) => unknown;
|
|
55
|
+
}[];
|
|
56
|
+
}
|
|
57
|
+
/** @beta Host-observed inventory, including core. The loader owns completeness. */
|
|
58
|
+
export interface LoadedPackage {
|
|
59
|
+
name: string;
|
|
60
|
+
version: string;
|
|
61
|
+
kind: PackageManifest["kind"];
|
|
62
|
+
}
|
|
63
|
+
/** @beta Candidate identity must change when configuration, schema or artifact changes. */
|
|
64
|
+
export interface CandidateIdentity {
|
|
65
|
+
artifact: string;
|
|
66
|
+
configuration: string;
|
|
67
|
+
environment: string;
|
|
68
|
+
database: string;
|
|
69
|
+
schema: string;
|
|
70
|
+
}
|
|
71
|
+
/** @beta */
|
|
72
|
+
export interface EventExemption {
|
|
73
|
+
pattern: string;
|
|
74
|
+
prefix: boolean;
|
|
75
|
+
owner: string;
|
|
76
|
+
reason: string;
|
|
77
|
+
state: "ignored" | "dormant";
|
|
78
|
+
}
|
|
79
|
+
/** @beta */
|
|
80
|
+
export interface ReadinessInput {
|
|
81
|
+
candidate: CandidateIdentity;
|
|
82
|
+
inventoryComplete: boolean;
|
|
83
|
+
loadedPackages: readonly LoadedPackage[];
|
|
84
|
+
contributions: readonly Contribution[];
|
|
85
|
+
vocabulary: readonly EventVocabularyEntry[];
|
|
86
|
+
exemptions: readonly EventExemption[];
|
|
87
|
+
bindings: {
|
|
88
|
+
ports: Readonly<Record<string, unknown>>;
|
|
89
|
+
triggers: Readonly<Record<string, unknown>>;
|
|
90
|
+
routes: Readonly<Record<string, unknown>>;
|
|
91
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
92
|
+
};
|
|
93
|
+
schemaProbe: SchemaProbePort;
|
|
94
|
+
probeTimeoutMs?: number;
|
|
95
|
+
}
|
|
96
|
+
/** @beta A bounded catalog observation, not proof of SQL bodies, ACL or recovery. */
|
|
97
|
+
export interface SchemaObservation {
|
|
98
|
+
database: string;
|
|
99
|
+
version: string | null;
|
|
100
|
+
objects: readonly {
|
|
101
|
+
object: SchemaObject;
|
|
102
|
+
present: boolean | null;
|
|
103
|
+
}[];
|
|
104
|
+
}
|
|
105
|
+
/** @beta */
|
|
106
|
+
export interface SchemaProbePort {
|
|
107
|
+
observe(requirement: RequiredSchema): Promise<SchemaObservation>;
|
|
108
|
+
}
|
|
109
|
+
/** @beta Each operation commits before resolving; never lend a producer transaction to dispatch. */
|
|
110
|
+
export interface SqlExecutor {
|
|
111
|
+
query<Row extends Record<string, unknown> = Record<string, unknown>>(text: string, values?: readonly unknown[]): Promise<{
|
|
112
|
+
rows: Row[];
|
|
113
|
+
}>;
|
|
114
|
+
}
|
|
115
|
+
/** @beta */
|
|
116
|
+
export interface ReadinessReport {
|
|
117
|
+
state: "ready" | "unsatisfied" | "unknown";
|
|
118
|
+
candidate: CandidateIdentity;
|
|
119
|
+
loadedPackages: readonly LoadedPackage[];
|
|
120
|
+
issues: readonly ReadinessIssue[];
|
|
121
|
+
}
|