@farthershore/product 0.3.1 → 0.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.
@@ -228,6 +228,48 @@ export type ProductCustomerContextJson = {
228
228
  strategy: CustomerPortalAuthStrategyJson;
229
229
  };
230
230
  };
231
+ export type ProductSurfaceTypeJson = "frontend" | "api" | "docs" | "widget" | "dashboard" | "webhook" | "worker" | "agent";
232
+ export type ProductSurfaceJson = {
233
+ key: string;
234
+ type: ProductSurfaceTypeJson;
235
+ display?: string;
236
+ description?: string;
237
+ };
238
+ export type ProductEntitlementJson = {
239
+ key: string;
240
+ description?: string;
241
+ capabilities?: string[];
242
+ featureGates?: Record<string, boolean>;
243
+ limits?: PlanLimitJson[];
244
+ meters?: string[];
245
+ };
246
+ export type ProductWorkflowKindJson = "async_job" | "agent_task" | "scheduled" | "lifecycle" | "background";
247
+ export type ProductWorkflowTriggerJson = {
248
+ type: "manual";
249
+ } | {
250
+ type: "schedule";
251
+ cron: string;
252
+ } | {
253
+ type: "event";
254
+ event: string;
255
+ } | {
256
+ type: "api";
257
+ path: string;
258
+ } | {
259
+ type: "lifecycle";
260
+ event: string;
261
+ };
262
+ export type ProductWorkflowJson = {
263
+ key: string;
264
+ title?: string;
265
+ description?: string;
266
+ kind: ProductWorkflowKindJson;
267
+ trigger: ProductWorkflowTriggerJson;
268
+ capabilities?: string[];
269
+ meters?: string[];
270
+ estimates?: Record<string, number>;
271
+ metadata?: Record<string, unknown>;
272
+ };
231
273
  export type ProductBlockJson = {
232
274
  name: string;
233
275
  displayName?: string;
@@ -257,6 +299,9 @@ export type ProductSpecJson = {
257
299
  resources?: CountedResourceJson[];
258
300
  policies?: ProductPoliciesJson;
259
301
  customer_context?: ProductCustomerContextJson;
302
+ surfaces?: ProductSurfaceJson[];
303
+ entitlements?: ProductEntitlementJson[];
304
+ workflows?: ProductWorkflowJson[];
260
305
  plans?: PlanSpecJson[];
261
306
  /** Legacy / advanced product blocks (usage, features, billing,
262
307
  * webhooks, environments, add_ons, lifecycle, ephemeral, …) ride
@@ -276,7 +321,7 @@ export type ManifestIrDocument = {
276
321
  migrations: null;
277
322
  };
278
323
  };
279
- /** `toIR()` result: the validated envelope plus its canonical hash. */
324
+ /** Platform compiler result: the validated envelope plus its canonical hash. */
280
325
  export type ManifestBuildResult = {
281
326
  ir: ManifestIrDocument;
282
327
  irHash: string;
@@ -1,15 +1,15 @@
1
- import type { CacheProfile, ActionSpecJson, CapabilityFileJson, FrontendComponentId, FrontendGateMode, FrontendManifestJson, GrantJson, ManifestBuildResult, MeterDefinitionJson, MigrationDeclJson, MigrationPinJson, MutationClass, CountedResourceJson, PlanLimitJson, PlanMeterJson, PlanSpecJson, PolicyFileJson, ProductPoliciesJson, ProductCustomerContextJson, RoutesFileJson } from "./ir-types.js";
1
+ import type { CacheProfile, ActionSpecJson, CapabilityFileJson, FrontendComponentId, FrontendGateMode, FrontendManifestJson, GrantJson, MeterDefinitionJson, MigrationDeclJson, MigrationPinJson, MutationClass, CountedResourceJson, PlanLimitJson, PlanMeterJson, PlanSpecJson, PolicyFileJson, ProductPoliciesJson, ProductCustomerContextJson, ProductWorkflowKindJson, ProductWorkflowTriggerJson, ProductSurfaceTypeJson, RoutesFileJson } from "./ir-types.js";
2
2
  import type { PriceSpec } from "./price.js";
3
3
  import { type ManifestResourceGraphSnapshot } from "./resource-graph.js";
4
- /** Brand symbol so the bin can recognize a Business across SDK copies
4
+ /** Brand symbol so the bin can recognize a Product across SDK copies
5
5
  * (the repo's pinned SDK vs whatever loaded the entry). */
6
- export declare const BUSINESS_BRAND: unique symbol;
7
- export type BusinessOptions = {
8
- /** Upstream origin the gateway proxies to. */
9
- baseUrl: string;
6
+ export declare const PRODUCT_BRAND: unique symbol;
7
+ export type ProductOptions = {
8
+ /** Business logic origin Farther Shore calls for customer-facing actions. */
9
+ origin: string;
10
10
  displayName?: string;
11
11
  description?: string;
12
- sandboxBaseUrl?: string;
12
+ sandboxOrigin?: string;
13
13
  visibility?: "public" | "private";
14
14
  logoUrl?: string;
15
15
  primaryColor?: string;
@@ -27,7 +27,7 @@ export type BusinessOptions = {
27
27
  customerContext?: {
28
28
  identityRequirement?: ProductCustomerContextJson["identity_requirement"];
29
29
  contextTokens?: ProductCustomerContextJson["context_tokens"];
30
- portalAuth?: ProductCustomerContextJson["portal_auth"];
30
+ customerAuth?: ProductCustomerContextJson["portal_auth"];
31
31
  };
32
32
  billing?: {
33
33
  gracePeriodDays?: number;
@@ -114,7 +114,7 @@ export type FeatureOptions = {
114
114
  description?: string;
115
115
  mutationClass?: MutationClass;
116
116
  cacheProfile?: CacheProfile;
117
- /** Per-feature upstream origin override (default: product baseUrl). */
117
+ /** Per-feature upstream origin override (default: product origin). */
118
118
  upstreamOrigin?: string | null;
119
119
  policies?: Array<string | PolicyRef>;
120
120
  capabilities?: Array<string | CapabilityRef>;
@@ -171,6 +171,28 @@ export type PlanOptions = {
171
171
  /** Escape hatch: merged onto the emitted plan spec last (e.g. variants). */
172
172
  raw?: Record<string, unknown>;
173
173
  };
174
+ export type SurfaceOptions = {
175
+ key?: string;
176
+ display?: string;
177
+ description?: string;
178
+ };
179
+ export type WorkflowOptions = {
180
+ title?: string;
181
+ description?: string;
182
+ kind?: ProductWorkflowKindJson;
183
+ trigger?: ProductWorkflowTriggerJson;
184
+ capabilities?: Array<string | CapabilityRef>;
185
+ meters?: Array<string | MeterRef>;
186
+ estimates?: Record<string, number>;
187
+ metadata?: Record<string, unknown>;
188
+ };
189
+ export type EntitlementOptions = {
190
+ description?: string;
191
+ capabilities?: Array<string | CapabilityRef>;
192
+ featureGates?: Record<string, boolean>;
193
+ limits?: PlanLimitJson[];
194
+ meters?: Array<string | MeterRef>;
195
+ };
174
196
  export type MeterRef = {
175
197
  readonly kind: "meter";
176
198
  readonly key: string;
@@ -191,6 +213,18 @@ export type PlanRef = {
191
213
  readonly kind: "plan";
192
214
  readonly key: string;
193
215
  };
216
+ export type SurfaceRef = {
217
+ readonly kind: "surface";
218
+ readonly key: string;
219
+ };
220
+ export type WorkflowRef = {
221
+ readonly kind: "workflow";
222
+ readonly key: string;
223
+ };
224
+ export type EntitlementRef = {
225
+ readonly kind: "entitlement";
226
+ readonly key: string;
227
+ };
194
228
  export type ActionRef = {
195
229
  readonly kind: "action";
196
230
  readonly key: string;
@@ -221,9 +255,9 @@ export type PlanCapabilityGrant = {
221
255
  * A synchronous Product SDK module. Use this to split a product across files:
222
256
  * `product.use(configureMeters, configureRoutes, configurePlans)`.
223
257
  */
224
- export type ProductModule = (product: Business) => void;
225
- export declare class Business {
226
- readonly [BUSINESS_BRAND] = true;
258
+ export type ProductModule = (product: Product) => void;
259
+ export declare class Product {
260
+ readonly [PRODUCT_BRAND] = true;
227
261
  readonly name: string;
228
262
  private readonly options;
229
263
  private readonly graph;
@@ -234,49 +268,54 @@ export declare class Business {
234
268
  readonly api: {
235
269
  route: (match: string, options: {
236
270
  feature: string | FeatureRef;
237
- } & RouteOptions) => Business;
271
+ } & RouteOptions) => Product;
238
272
  };
239
273
  readonly frontend: {
240
- nav: (items: FrontendNavItemOptions[]) => Business;
241
- page: (path: string, options: FrontendPageOptions) => Business;
242
- manifest: (manifest: FrontendManifestJson) => Business;
274
+ nav: (items: FrontendNavItemOptions[]) => Product;
275
+ page: (path: string, options: FrontendPageOptions) => Product;
276
+ manifest: (manifest: FrontendManifestJson) => Product;
243
277
  };
244
278
  readonly lifecycle: {
245
- migration: (id: string, options: MigrationOptions) => Business;
246
- migrations: (migrations: MigrationDeclJson[]) => Business;
279
+ migration: (id: string, options: MigrationOptions) => Product;
280
+ migrations: (migrations: MigrationDeclJson[]) => Product;
281
+ };
282
+ readonly offering: {
283
+ plan: (key: string, options: PlanOptions) => PlanRef;
247
284
  };
248
- /** Escape hatches — raw platform-schema JSON, validated at toIR(). */
285
+ /** Escape hatches — raw platform-schema JSON, validated by the compiler. */
249
286
  readonly raw: {
250
287
  /** Deep-merged onto the emitted product spec (usage, webhooks,
251
288
  * environments, add_ons, lifecycle, billing overrides, …). */
252
- productPatch: (patch: Record<string, unknown>) => Business;
253
- plan: (spec: PlanSpecJson) => Business;
254
- routesFile: (file: RoutesFileJson) => Business;
255
- policyFile: (file: PolicyFileJson) => Business;
256
- capabilityFile: (file: CapabilityFileJson) => Business;
257
- frontend: (manifest: FrontendManifestJson) => Business;
289
+ productPatch: (patch: Record<string, unknown>) => Product;
290
+ plan: (spec: PlanSpecJson) => Product;
291
+ routesFile: (file: RoutesFileJson) => Product;
292
+ policyFile: (file: PolicyFileJson) => Product;
293
+ capabilityFile: (file: CapabilityFileJson) => Product;
294
+ frontend: (manifest: FrontendManifestJson) => Product;
258
295
  };
259
- constructor(name: string, options: BusinessOptions);
296
+ constructor(name: string, options: ProductOptions);
260
297
  meter(key: string, options: MeterOptions): MeterRef;
261
298
  requests(options?: RequestMeterOptions): MeterRef;
262
- defaultMeters(costs: MeterCost | MeterCost[]): Business;
299
+ defaultMeters(costs: MeterCost | MeterCost[]): Product;
263
300
  resource(name: string, options?: ResourceOptions): ResourceRef;
264
301
  capability(key: string, options?: CapabilityOptions): CapabilityRef;
265
302
  feature(key: string, options?: FeatureOptions): FeatureRef;
266
303
  policy(name: string, options: PolicyOptions): PolicyRef;
304
+ surface(type: ProductSurfaceTypeJson, options?: SurfaceOptions): SurfaceRef;
305
+ workflow(key: string, options?: WorkflowOptions): WorkflowRef;
306
+ entitlement(key: string, options?: EntitlementOptions): EntitlementRef;
267
307
  plan(key: string, options: PlanOptions): PlanRef;
268
- use(...modules: ProductModule[]): Business;
308
+ use(...modules: ProductModule[]): Product;
269
309
  /** Inspect the SDK-local declaration graph used to emit the Manifest IR. */
270
310
  resourceGraph(): ManifestResourceGraphSnapshot;
271
- /** Assemble + validate the Manifest IR. Throws ManifestValidationError
272
- * with structured issues when the declared state is invalid. */
273
- toIR(): ManifestBuildResult;
274
311
  private buildProductSpec;
275
312
  private buildMeterDefinitions;
276
313
  private routeValueMeterKeys;
277
314
  private buildRoute;
278
315
  private makeMeterRef;
279
316
  private buildRouteMetering;
317
+ private materializeFeatureFiles;
318
+ private materializeRoute;
280
319
  private normalizeMeterCost;
281
320
  private normalizeMeterCosts;
282
321
  private normalizeMeterRefs;
@@ -293,6 +332,8 @@ export declare class Business {
293
332
  private syncFrontendGraphNode;
294
333
  private capabilityDependsOn;
295
334
  private policyDependsOn;
335
+ private entitlementDependsOn;
336
+ private workflowDependsOn;
296
337
  private featureDependsOn;
297
338
  private routeMeterDependencyKeys;
298
339
  private assertRouteMeteringValid;
@@ -303,5 +344,5 @@ export declare class Business {
303
344
  private dependenciesFor;
304
345
  private existingDependenciesFor;
305
346
  }
306
- export declare function isBusiness(value: unknown): value is Business;
307
- export declare function business(name: string, options: BusinessOptions, configure?: ProductModule): Business;
347
+ export declare function isProduct(value: unknown): value is Product;
348
+ export declare function product(name: string, options: ProductOptions, configure?: ProductModule): Product;
@@ -1,4 +1,4 @@
1
- export type ManifestResourceKind = "product" | "meter" | "counted_resource" | "capability" | "policy" | "feature" | "action" | "plan" | "frontend" | "lifecycle_migration";
1
+ export type ManifestResourceKind = "product" | "meter" | "counted_resource" | "capability" | "surface" | "entitlement" | "workflow" | "policy" | "feature" | "action" | "plan" | "frontend" | "lifecycle_migration";
2
2
  export type ManifestResourceUrn = `urn:farthershore:product:${ManifestResourceKind}:${string}`;
3
3
  export type ManifestResourceRef = {
4
4
  readonly kind: ManifestResourceKind;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@farthershore/product",
3
- "version": "0.3.1",
4
- "description": "Farther Shore product-as-code SDK — declare your business in TypeScript",
3
+ "version": "0.5.0",
4
+ "description": "Farther Shore product-as-code SDK — declare your software product in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -31,9 +31,9 @@
31
31
  "keywords": [
32
32
  "farthershore",
33
33
  "product-as-code",
34
- "api",
34
+ "software-product",
35
35
  "billing",
36
- "api-monetization"
36
+ "monetization"
37
37
  ],
38
38
  "author": "Farther Shore",
39
39
  "license": "MIT",