@farthershore/product 0.1.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 +64 -51
- package/dist/bin.js +55 -14
- package/dist/index.js +16 -9
- package/dist/types/business.d.ts +7 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# @farthershore/product
|
|
2
2
|
|
|
3
|
-
Product-as-Code SDK for Farther Shore. Builder repos use this package
|
|
4
|
-
`product.config.ts` to declare product contracts in TypeScript. Builders
|
|
5
|
-
and export a `Business`; the Farther Shore GitHub bot
|
|
6
|
-
|
|
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.
|
|
7
8
|
|
|
8
9
|
## Install
|
|
9
10
|
|
|
@@ -12,12 +13,36 @@ pnpm add @farthershore/product
|
|
|
12
13
|
```
|
|
13
14
|
|
|
14
15
|
Builder repos generated by Farther Shore already pin this dependency in
|
|
15
|
-
`package.json`.
|
|
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.
|
|
16
38
|
|
|
17
39
|
## Example
|
|
18
40
|
|
|
19
41
|
```ts
|
|
20
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";
|
|
21
46
|
|
|
22
47
|
const business = fs.business("croncloud", {
|
|
23
48
|
baseUrl: "https://api.example.com",
|
|
@@ -25,49 +50,34 @@ const business = fs.business("croncloud", {
|
|
|
25
50
|
description: "Managed cron jobs",
|
|
26
51
|
});
|
|
27
52
|
|
|
28
|
-
business.
|
|
29
|
-
|
|
30
|
-
business.resource("cron_jobs", {
|
|
31
|
-
display: "Cron jobs",
|
|
32
|
-
countSource: "action_inferred",
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const cron = business.capability("managed-cron", {
|
|
36
|
-
title: "Managed Cron Jobs",
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const jobs = business.feature("cron-jobs", {
|
|
40
|
-
description: "Cron job CRUD",
|
|
41
|
-
capabilities: [cron],
|
|
42
|
-
routes: [{ match: "GET /v1/cron-jobs", meters: ["requests"] }],
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const createJob = jobs.action("cron-job.create", {
|
|
46
|
-
kind: "mutation",
|
|
47
|
-
title: "Create cron job",
|
|
48
|
-
resource: { resource: "cron_jobs", effect: "create" },
|
|
49
|
-
});
|
|
53
|
+
business.use(configureMeters, configureCronRoutes, configurePlans);
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
action: createJob,
|
|
54
|
-
});
|
|
55
|
+
export default business;
|
|
56
|
+
```
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
name: "Starter",
|
|
58
|
-
price: fs.price.monthly(29),
|
|
59
|
-
grants: [cron.enable({ limits: { cron_jobs: 10 } })],
|
|
60
|
-
limits: [
|
|
61
|
-
{
|
|
62
|
-
dimension: "requests",
|
|
63
|
-
window: { type: "named", name: "minute" },
|
|
64
|
-
capacity: 600,
|
|
65
|
-
enforcement: "enforce",
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
});
|
|
58
|
+
Modules are plain synchronous functions:
|
|
69
59
|
|
|
70
|
-
|
|
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
|
+
};
|
|
71
81
|
```
|
|
72
82
|
|
|
73
83
|
## Bot build
|
|
@@ -75,10 +85,11 @@ export default business;
|
|
|
75
85
|
Normal product repos do not call platform release or IR APIs. The GitHub bot
|
|
76
86
|
owns that workflow:
|
|
77
87
|
|
|
78
|
-
1. Loads `product.config.ts`.
|
|
88
|
+
1. Loads `product/product.config.ts`.
|
|
79
89
|
2. Requires the default export to be the `Business` returned by
|
|
80
90
|
`fs.business(...)` or `fs.product(...)`.
|
|
81
|
-
3.
|
|
91
|
+
3. Executes imported modules and compiles the business into deterministic
|
|
92
|
+
Manifest IR.
|
|
82
93
|
4. Validates the result against the deployed platform contract.
|
|
83
94
|
5. Publishes the accepted release through Core so edge artifacts propagate.
|
|
84
95
|
|
|
@@ -90,6 +101,8 @@ normal builder workflow.
|
|
|
90
101
|
|
|
91
102
|
- `fs.business(name, options)` / `fs.product(name, options)` — create the
|
|
92
103
|
product builder.
|
|
104
|
+
- `business.use(...modules)` — compose Product SDK modules from any files under
|
|
105
|
+
`product/`.
|
|
93
106
|
- `business.meter(...)` — declare billable or enforceable dimensions.
|
|
94
107
|
- `business.resource(...)` — declare counted resources for resource-count
|
|
95
108
|
constraints.
|
|
@@ -99,16 +112,16 @@ normal builder workflow.
|
|
|
99
112
|
- `business.policy(...)` — declare policy files in code.
|
|
100
113
|
- `business.plan(...)` — declare plan pricing, limits, grants, and lifecycle
|
|
101
114
|
behavior.
|
|
102
|
-
- `business.frontend.*` — declare generated portal navigation and gates.
|
|
103
115
|
- `business.lifecycle.*` — declare migrations.
|
|
104
116
|
- `business.raw.*` — escape hatches for platform-schema JSON when the typed SDK
|
|
105
117
|
does not yet have sugar.
|
|
106
118
|
|
|
107
119
|
## Determinism
|
|
108
120
|
|
|
109
|
-
`product.config.ts` must be deterministic: no
|
|
110
|
-
or process state. Sorted collections produce
|
|
111
|
-
remains semantic because the gateway matcher is
|
|
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.
|
|
112
125
|
|
|
113
126
|
The GitHub bot runs the build twice and rejects the push if the two generated
|
|
114
127
|
hashes differ.
|
package/dist/bin.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { createRequire as __createRequire } from "node:module";const require=__createRequire(import.meta.url);
|
|
3
3
|
|
|
4
4
|
// src/bin.ts
|
|
5
|
-
import { writeFile } from "node:fs/promises";
|
|
5
|
+
import { access, writeFile } from "node:fs/promises";
|
|
6
|
+
import { constants } from "node:fs";
|
|
6
7
|
import { resolve } from "node:path";
|
|
7
8
|
import { pathToFileURL } from "node:url";
|
|
8
9
|
import { tsImport } from "tsx/esm/api";
|
|
@@ -1398,7 +1399,7 @@ var productCustomerContextSchema = z13.object({
|
|
|
1398
1399
|
identity_requirement: customerIdentityRequirementSchema.optional(),
|
|
1399
1400
|
/**
|
|
1400
1401
|
* Enables signed customer-context tokens (`fsc_*`) without putting the
|
|
1401
|
-
* runtime signing secret in product.config.ts. Core generates/preserves the
|
|
1402
|
+
* runtime signing secret in product/product.config.ts. Core generates/preserves the
|
|
1402
1403
|
* secret when this is true and clears it when explicitly false.
|
|
1403
1404
|
*/
|
|
1404
1405
|
context_tokens: z13.object({
|
|
@@ -1447,10 +1448,9 @@ var productSpecSchema = z13.object({
|
|
|
1447
1448
|
policies: productOperatorPoliciesSchema,
|
|
1448
1449
|
customer_context: productCustomerContextSchema.optional(),
|
|
1449
1450
|
/**
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
* sections remain template-owned.
|
|
1451
|
+
* Legacy/internal declarative frontend surface. New product repos customize
|
|
1452
|
+
* the generated `frontend/` project directly; this remains for existing IR
|
|
1453
|
+
* and internal template metadata.
|
|
1454
1454
|
*/
|
|
1455
1455
|
frontend: frontendManifestSchema.optional(),
|
|
1456
1456
|
migrations: migrationDeclsSchema.optional(),
|
|
@@ -1574,7 +1574,7 @@ var productSpecSchema = z13.object({
|
|
|
1574
1574
|
*
|
|
1575
1575
|
* Once a product has compiled with a `webhooks` block, API mutations
|
|
1576
1576
|
* on those endpoints fail with `409 MANAGED_BY_CODE` — see
|
|
1577
|
-
* `core/src/routes/management-webhooks.ts`. Tie-breaker: product.config.ts
|
|
1577
|
+
* `core/src/routes/management-webhooks.ts`. Tie-breaker: product/product.config.ts
|
|
1578
1578
|
* wins over API state if an endpoint id appears in both.
|
|
1579
1579
|
*/
|
|
1580
1580
|
webhooks: webhooksBlockSchema.optional(),
|
|
@@ -2360,7 +2360,7 @@ function hashIr(ir) {
|
|
|
2360
2360
|
}
|
|
2361
2361
|
|
|
2362
2362
|
// src/version.ts
|
|
2363
|
-
var SDK_VERSION = true ? "0.
|
|
2363
|
+
var SDK_VERSION = true ? "0.2.0" : "0.0.0-dev";
|
|
2364
2364
|
|
|
2365
2365
|
// src/business.ts
|
|
2366
2366
|
var BUSINESS_BRAND = Symbol.for("farthershore.product.business");
|
|
@@ -2726,6 +2726,12 @@ var Business = class {
|
|
|
2726
2726
|
this.graph.register("plan", key, spec, this.planDependsOn(spec));
|
|
2727
2727
|
return { kind: "plan", key };
|
|
2728
2728
|
}
|
|
2729
|
+
use(...modules) {
|
|
2730
|
+
for (const module of modules) {
|
|
2731
|
+
module(this);
|
|
2732
|
+
}
|
|
2733
|
+
return this;
|
|
2734
|
+
}
|
|
2729
2735
|
/** Inspect the SDK-local declaration graph used to emit the Manifest IR. */
|
|
2730
2736
|
resourceGraph() {
|
|
2731
2737
|
return this.graph.snapshot();
|
|
@@ -3009,9 +3015,13 @@ function describeResourceUrn(urn) {
|
|
|
3009
3015
|
}
|
|
3010
3016
|
|
|
3011
3017
|
// src/bin.ts
|
|
3018
|
+
var DEFAULT_ENTRY_CANDIDATES = [
|
|
3019
|
+
"product/product.config.ts",
|
|
3020
|
+
"product.config.ts"
|
|
3021
|
+
];
|
|
3012
3022
|
function parseArgs(argv) {
|
|
3013
3023
|
const args = {
|
|
3014
|
-
entry:
|
|
3024
|
+
entry: null,
|
|
3015
3025
|
out: "manifest-ir.json",
|
|
3016
3026
|
diagnosticsOut: "manifest-diagnostics.json"
|
|
3017
3027
|
};
|
|
@@ -3029,13 +3039,35 @@ function parseArgs(argv) {
|
|
|
3029
3039
|
i++;
|
|
3030
3040
|
} else if (flag === "--help" || flag === "-h") {
|
|
3031
3041
|
process.stdout.write(
|
|
3032
|
-
"Usage: farthershore-manifest-build [--entry product.config.ts] [--out manifest-ir.json] [--diagnostics-out manifest-diagnostics.json]\n"
|
|
3042
|
+
"Usage: farthershore-manifest-build [--entry product/product.config.ts] [--out manifest-ir.json] [--diagnostics-out manifest-diagnostics.json]\n"
|
|
3033
3043
|
);
|
|
3034
3044
|
process.exit(0);
|
|
3035
3045
|
}
|
|
3036
3046
|
}
|
|
3037
3047
|
return args;
|
|
3038
3048
|
}
|
|
3049
|
+
async function fileExists(path) {
|
|
3050
|
+
try {
|
|
3051
|
+
await access(path, constants.R_OK);
|
|
3052
|
+
return true;
|
|
3053
|
+
} catch {
|
|
3054
|
+
return false;
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
async function resolveEntry(args) {
|
|
3058
|
+
if (args.entry) {
|
|
3059
|
+
return { entry: args.entry, entryPath: resolve(process.cwd(), args.entry) };
|
|
3060
|
+
}
|
|
3061
|
+
for (const candidate of DEFAULT_ENTRY_CANDIDATES) {
|
|
3062
|
+
const entryPath = resolve(process.cwd(), candidate);
|
|
3063
|
+
if (await fileExists(entryPath)) {
|
|
3064
|
+
return { entry: candidate, entryPath };
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
throw new Error(
|
|
3068
|
+
`no Product SDK entry found; expected ${DEFAULT_ENTRY_CANDIDATES.join(" or ")}`
|
|
3069
|
+
);
|
|
3070
|
+
}
|
|
3039
3071
|
function validationIssues(error) {
|
|
3040
3072
|
if (error instanceof ManifestValidationError) return error.issues;
|
|
3041
3073
|
if (typeof error === "object" && error !== null && error.name === "ManifestValidationError" && Array.isArray(error.issues)) {
|
|
@@ -3048,16 +3080,25 @@ function errorMessage(error) {
|
|
|
3048
3080
|
}
|
|
3049
3081
|
async function main() {
|
|
3050
3082
|
const args = parseArgs(process.argv.slice(2));
|
|
3051
|
-
|
|
3083
|
+
let resolvedEntry;
|
|
3084
|
+
try {
|
|
3085
|
+
resolvedEntry = await resolveEntry(args);
|
|
3086
|
+
} catch (error) {
|
|
3087
|
+
process.stderr.write(
|
|
3088
|
+
`farthershore-manifest-build: ${errorMessage(error)}
|
|
3089
|
+
`
|
|
3090
|
+
);
|
|
3091
|
+
process.exit(1);
|
|
3092
|
+
}
|
|
3052
3093
|
let mod;
|
|
3053
3094
|
try {
|
|
3054
3095
|
mod = await tsImport(
|
|
3055
|
-
pathToFileURL(entryPath).href,
|
|
3096
|
+
pathToFileURL(resolvedEntry.entryPath).href,
|
|
3056
3097
|
import.meta.url
|
|
3057
3098
|
);
|
|
3058
3099
|
} catch (error) {
|
|
3059
3100
|
process.stderr.write(
|
|
3060
|
-
`farthershore-manifest-build: failed to load ${
|
|
3101
|
+
`farthershore-manifest-build: failed to load ${resolvedEntry.entry}: ${error instanceof Error ? error.message : String(error)}
|
|
3061
3102
|
`
|
|
3062
3103
|
);
|
|
3063
3104
|
process.exit(1);
|
|
@@ -3067,7 +3108,7 @@ async function main() {
|
|
|
3067
3108
|
const candidate = isBusiness(direct) ? direct : interop;
|
|
3068
3109
|
if (!isBusiness(candidate)) {
|
|
3069
3110
|
process.stderr.write(
|
|
3070
|
-
`farthershore-manifest-build: ${
|
|
3111
|
+
`farthershore-manifest-build: ${resolvedEntry.entry} must \`export default\` the Business returned by fs.business(\u2026)
|
|
3071
3112
|
`
|
|
3072
3113
|
);
|
|
3073
3114
|
process.exit(1);
|
package/dist/index.js
CHANGED
|
@@ -1391,7 +1391,7 @@ var productCustomerContextSchema = z13.object({
|
|
|
1391
1391
|
identity_requirement: customerIdentityRequirementSchema.optional(),
|
|
1392
1392
|
/**
|
|
1393
1393
|
* Enables signed customer-context tokens (`fsc_*`) without putting the
|
|
1394
|
-
* runtime signing secret in product.config.ts. Core generates/preserves the
|
|
1394
|
+
* runtime signing secret in product/product.config.ts. Core generates/preserves the
|
|
1395
1395
|
* secret when this is true and clears it when explicitly false.
|
|
1396
1396
|
*/
|
|
1397
1397
|
context_tokens: z13.object({
|
|
@@ -1440,10 +1440,9 @@ var productSpecSchema = z13.object({
|
|
|
1440
1440
|
policies: productOperatorPoliciesSchema,
|
|
1441
1441
|
customer_context: productCustomerContextSchema.optional(),
|
|
1442
1442
|
/**
|
|
1443
|
-
*
|
|
1444
|
-
*
|
|
1445
|
-
*
|
|
1446
|
-
* sections remain template-owned.
|
|
1443
|
+
* Legacy/internal declarative frontend surface. New product repos customize
|
|
1444
|
+
* the generated `frontend/` project directly; this remains for existing IR
|
|
1445
|
+
* and internal template metadata.
|
|
1447
1446
|
*/
|
|
1448
1447
|
frontend: frontendManifestSchema.optional(),
|
|
1449
1448
|
migrations: migrationDeclsSchema.optional(),
|
|
@@ -1567,7 +1566,7 @@ var productSpecSchema = z13.object({
|
|
|
1567
1566
|
*
|
|
1568
1567
|
* Once a product has compiled with a `webhooks` block, API mutations
|
|
1569
1568
|
* on those endpoints fail with `409 MANAGED_BY_CODE` — see
|
|
1570
|
-
* `core/src/routes/management-webhooks.ts`. Tie-breaker: product.config.ts
|
|
1569
|
+
* `core/src/routes/management-webhooks.ts`. Tie-breaker: product/product.config.ts
|
|
1571
1570
|
* wins over API state if an endpoint id appears in both.
|
|
1572
1571
|
*/
|
|
1573
1572
|
webhooks: webhooksBlockSchema.optional(),
|
|
@@ -2356,7 +2355,7 @@ function canonicalIrJson(ir) {
|
|
|
2356
2355
|
}
|
|
2357
2356
|
|
|
2358
2357
|
// src/version.ts
|
|
2359
|
-
var SDK_VERSION = true ? "0.
|
|
2358
|
+
var SDK_VERSION = true ? "0.2.0" : "0.0.0-dev";
|
|
2360
2359
|
|
|
2361
2360
|
// src/business.ts
|
|
2362
2361
|
var BUSINESS_BRAND = Symbol.for("farthershore.product.business");
|
|
@@ -2722,6 +2721,12 @@ var Business = class {
|
|
|
2722
2721
|
this.graph.register("plan", key, spec, this.planDependsOn(spec));
|
|
2723
2722
|
return { kind: "plan", key };
|
|
2724
2723
|
}
|
|
2724
|
+
use(...modules) {
|
|
2725
|
+
for (const module of modules) {
|
|
2726
|
+
module(this);
|
|
2727
|
+
}
|
|
2728
|
+
return this;
|
|
2729
|
+
}
|
|
2725
2730
|
/** Inspect the SDK-local declaration graph used to emit the Manifest IR. */
|
|
2726
2731
|
resourceGraph() {
|
|
2727
2732
|
return this.graph.snapshot();
|
|
@@ -2975,8 +2980,10 @@ var Business = class {
|
|
|
2975
2980
|
function isBusiness(value) {
|
|
2976
2981
|
return typeof value === "object" && value !== null && value[BUSINESS_BRAND] === true;
|
|
2977
2982
|
}
|
|
2978
|
-
function business(name, options) {
|
|
2979
|
-
|
|
2983
|
+
function business(name, options, configure) {
|
|
2984
|
+
const product2 = new Business(name, options);
|
|
2985
|
+
if (configure) product2.use(configure);
|
|
2986
|
+
return product2;
|
|
2980
2987
|
}
|
|
2981
2988
|
function isPlainObject(value) {
|
|
2982
2989
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
package/dist/types/business.d.ts
CHANGED
|
@@ -191,6 +191,11 @@ export type PlanCapabilityGrant = {
|
|
|
191
191
|
readonly capability: string;
|
|
192
192
|
readonly limits?: Record<string, number | boolean>;
|
|
193
193
|
};
|
|
194
|
+
/**
|
|
195
|
+
* A synchronous Product SDK module. Use this to split a product across files:
|
|
196
|
+
* `product.use(configureMeters, configureRoutes, configurePlans)`.
|
|
197
|
+
*/
|
|
198
|
+
export type ProductModule = (product: Business) => void;
|
|
194
199
|
export declare class Business {
|
|
195
200
|
readonly [BUSINESS_BRAND] = true;
|
|
196
201
|
readonly name: string;
|
|
@@ -231,6 +236,7 @@ export declare class Business {
|
|
|
231
236
|
feature(key: string, options?: FeatureOptions): FeatureRef;
|
|
232
237
|
policy(name: string, options: PolicyOptions): PolicyRef;
|
|
233
238
|
plan(key: string, options: PlanOptions): PlanRef;
|
|
239
|
+
use(...modules: ProductModule[]): Business;
|
|
234
240
|
/** Inspect the SDK-local declaration graph used to emit the Manifest IR. */
|
|
235
241
|
resourceGraph(): ManifestResourceGraphSnapshot;
|
|
236
242
|
/** Assemble + validate the Manifest IR. Throws ManifestValidationError
|
|
@@ -260,4 +266,4 @@ export declare class Business {
|
|
|
260
266
|
private existingDependenciesFor;
|
|
261
267
|
}
|
|
262
268
|
export declare function isBusiness(value: unknown): value is Business;
|
|
263
|
-
export declare function business(name: string, options: BusinessOptions): Business;
|
|
269
|
+
export declare function business(name: string, options: BusinessOptions, configure?: ProductModule): Business;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { price } from "./price.js";
|
|
|
14
14
|
export { validateManifestIr, hashIr, canonicalIrJson } from "./validate.js";
|
|
15
15
|
export { ManifestValidationError, ManifestBuilderError } from "./errors.js";
|
|
16
16
|
export { SDK_VERSION } from "./version.js";
|
|
17
|
-
export type { BusinessOptions, MeterOptions, ResourceOptions, CapabilityOptions, ActionOptions, FrontendNavItemOptions, FrontendPageOptions, FrontendComponentOptions, MigrationOptions, FeatureOptions, RouteOptions, PolicyOptions, PlanOptions, MeterRef, ResourceRef, ActionRef, PolicyRef, PlanRef, FeatureRef, CapabilityRef, PlanCapabilityGrant, } from "./business.js";
|
|
17
|
+
export type { BusinessOptions, MeterOptions, ResourceOptions, CapabilityOptions, ActionOptions, FrontendNavItemOptions, FrontendPageOptions, FrontendComponentOptions, MigrationOptions, FeatureOptions, RouteOptions, PolicyOptions, PlanOptions, MeterRef, ResourceRef, ActionRef, PolicyRef, PlanRef, FeatureRef, CapabilityRef, PlanCapabilityGrant, ProductModule, } from "./business.js";
|
|
18
18
|
export type { ManifestResourceGraphSnapshot, ManifestResourceKind, ManifestResourceUrn, } from "./resource-graph.js";
|
|
19
19
|
export type { PriceSpec } from "./price.js";
|
|
20
20
|
export type { ManifestIssue } from "./errors.js";
|