@farthershore/product 0.0.0 → 0.2.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/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # @farthershore/product
2
+
3
+ Product-as-Code SDK for Farther Shore. Builder repos use this package from
4
+ `product/product.config.ts` to declare product contracts in TypeScript. Builders
5
+ author and export a `Business`; the Farther Shore GitHub bot compiles that
6
+ program to backend-owned IR, validates it, and publishes through Core when repo
7
+ changes land.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @farthershore/product
13
+ ```
14
+
15
+ Builder repos generated by Farther Shore already pin this dependency in
16
+ `product/package.json`.
17
+
18
+ ## Repo Layout
19
+
20
+ ```text
21
+ product/
22
+ package.json
23
+ product.config.ts
24
+ meters.ts
25
+ plans/
26
+ free.ts
27
+ pro.ts
28
+ routes/
29
+ api.ts
30
+ frontend/
31
+ ...
32
+ ```
33
+
34
+ `product/` is authored Product SDK code. `frontend/` is the generated editable
35
+ frontend app and is built by the frontend pipeline only. Runtime state and
36
+ compiled IR are not checked into the builder repo; Farther Shore stores them in
37
+ Core.
38
+
39
+ ## Example
40
+
41
+ ```ts
42
+ import { fs } from "@farthershore/product";
43
+ import { configureMeters } from "./meters.js";
44
+ import { configureCronRoutes } from "./routes/cron.js";
45
+ import { configurePlans } from "./plans/index.js";
46
+
47
+ const business = fs.business("croncloud", {
48
+ baseUrl: "https://api.example.com",
49
+ displayName: "CronCloud",
50
+ description: "Managed cron jobs",
51
+ });
52
+
53
+ business.use(configureMeters, configureCronRoutes, configurePlans);
54
+
55
+ export default business;
56
+ ```
57
+
58
+ Modules are plain synchronous functions:
59
+
60
+ ```ts
61
+ import { fs, type ProductModule } from "@farthershore/product";
62
+
63
+ export const configureMeters: ProductModule = (product) => {
64
+ product.meter("requests", { display: "Requests" });
65
+ };
66
+
67
+ export const configurePlans: ProductModule = (product) => {
68
+ product.plan("starter", {
69
+ name: "Starter",
70
+ price: fs.price.monthly(29),
71
+ limits: [
72
+ {
73
+ dimension: "requests",
74
+ window: { type: "named", name: "minute" },
75
+ capacity: 600,
76
+ enforcement: "enforce",
77
+ },
78
+ ],
79
+ });
80
+ };
81
+ ```
82
+
83
+ ## Bot build
84
+
85
+ Normal product repos do not call platform release or IR APIs. The GitHub bot
86
+ owns that workflow:
87
+
88
+ 1. Loads `product/product.config.ts`.
89
+ 2. Requires the default export to be the `Business` returned by
90
+ `fs.business(...)` or `fs.product(...)`.
91
+ 3. Executes imported modules and compiles the business into deterministic
92
+ Manifest IR.
93
+ 4. Validates the result against the deployed platform contract.
94
+ 5. Publishes the accepted release through Core so edge artifacts propagate.
95
+
96
+ The bundled `farthershore-manifest-build` binary is bot/build-runner plumbing.
97
+ Run it locally only when debugging the automation itself; it is not part of the
98
+ normal builder workflow.
99
+
100
+ ## Public API
101
+
102
+ - `fs.business(name, options)` / `fs.product(name, options)` — create the
103
+ product builder.
104
+ - `business.use(...modules)` — compose Product SDK modules from any files under
105
+ `product/`.
106
+ - `business.meter(...)` — declare billable or enforceable dimensions.
107
+ - `business.resource(...)` — declare counted resources for resource-count
108
+ constraints.
109
+ - `business.capability(...)` — declare capability bundles and plan grants.
110
+ - `business.feature(...)` / `business.api.route(...)` — declare gateway routes,
111
+ meters, and action metadata.
112
+ - `business.policy(...)` — declare policy files in code.
113
+ - `business.plan(...)` — declare plan pricing, limits, grants, and lifecycle
114
+ behavior.
115
+ - `business.lifecycle.*` — declare migrations.
116
+ - `business.raw.*` — escape hatches for platform-schema JSON when the typed SDK
117
+ does not yet have sugar.
118
+
119
+ ## Determinism
120
+
121
+ `product/product.config.ts` and everything it imports must be deterministic: no
122
+ dates, randomness, network calls, or process state. Sorted collections produce
123
+ stable output, while route order remains semantic because the gateway matcher is
124
+ first-match-wins.
125
+
126
+ The GitHub bot runs the build twice and rejects the push if the two generated
127
+ hashes differ.
128
+
129
+ ## Release
130
+
131
+ `@farthershore/product` publishes to public npm through the GitHub workflow
132
+ `.github/workflows/publish-product-sdk.yml`.
133
+
134
+ Release sequence:
135
+
136
+ 1. Bump `packages/product/package.json` version.
137
+ 2. Run the package checks:
138
+ ```bash
139
+ pnpm --filter @farthershore/product run lint
140
+ pnpm --filter @farthershore/product run test
141
+ pnpm --filter @farthershore/product run build
142
+ pnpm --filter @farthershore/product run pack:check
143
+ ```
144
+ 3. Commit, push, and merge through the normal PR flow.
145
+ 4. Tag from `main` with the exact package version:
146
+ ```bash
147
+ git tag product-v<version>
148
+ git push origin product-v<version>
149
+ ```
150
+
151
+ The publish workflow verifies that the tag equals
152
+ `product-v<packages/product/package.json version>`, builds/tests the package and
153
+ its dependencies, runs `pack:check`, then publishes with `NPM_PUBLISH_TOKEN`.