@farthershore/product 0.0.0 → 0.1.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.
@@ -1,5 +1,6 @@
1
- import type { CacheProfile, ActionSpecJson, CapabilityFileJson, FrontendComponentId, FrontendGateMode, FrontendManifestJson, GrantJson, ManifestBuildResult, MeterDefinitionJson, MigrationDeclJson, MigrationPinJson, MutationClass, CountedResourceJson, PlanLimitJson, PlanMeterJson, PlanSpecJson, PolicyFileJson, RoutesFileJson } from "./ir-types.js";
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";
2
2
  import type { PriceSpec } from "./price.js";
3
+ import { type ManifestResourceGraphSnapshot } from "./resource-graph.js";
3
4
  /** Brand symbol so the bin can recognize a Business across SDK copies
4
5
  * (the repo's pinned SDK vs whatever loaded the entry). */
5
6
  export declare const BUSINESS_BRAND: unique symbol;
@@ -20,6 +21,14 @@ export type BusinessOptions = {
20
21
  token?: string;
21
22
  };
22
23
  billOn4xx?: boolean;
24
+ /** Product operator policies, e.g. zero-traffic cleanup report/PR mode. */
25
+ operatorPolicies?: ProductPoliciesJson;
26
+ /** Customer-context controls emitted as product.customer_context. */
27
+ customerContext?: {
28
+ identityRequirement?: ProductCustomerContextJson["identity_requirement"];
29
+ contextTokens?: ProductCustomerContextJson["context_tokens"];
30
+ portalAuth?: ProductCustomerContextJson["portal_auth"];
31
+ };
23
32
  billing?: {
24
33
  gracePeriodDays?: number;
25
34
  applyLimitUpgradesInstantly?: boolean;
@@ -186,13 +195,7 @@ export declare class Business {
186
195
  readonly [BUSINESS_BRAND] = true;
187
196
  readonly name: string;
188
197
  private readonly options;
189
- private readonly meters;
190
- private readonly resources;
191
- private readonly plans;
192
- private readonly features;
193
- private readonly policies;
194
- private readonly capabilities;
195
- private migrations;
198
+ private readonly graph;
196
199
  private frontendManifest?;
197
200
  private productPatch;
198
201
  /** Sugar for binding API routes to features. */
@@ -228,6 +231,8 @@ export declare class Business {
228
231
  feature(key: string, options?: FeatureOptions): FeatureRef;
229
232
  policy(name: string, options: PolicyOptions): PolicyRef;
230
233
  plan(key: string, options: PlanOptions): PlanRef;
234
+ /** Inspect the SDK-local declaration graph used to emit the Manifest IR. */
235
+ resourceGraph(): ManifestResourceGraphSnapshot;
231
236
  /** Assemble + validate the Manifest IR. Throws ManifestValidationError
232
237
  * with structured issues when the declared state is invalid. */
233
238
  toIR(): ManifestBuildResult;
@@ -236,9 +241,23 @@ export declare class Business {
236
241
  private ensureFrontendManifest;
237
242
  private normalizeMigrationPlanRef;
238
243
  private normalizeMigrationTargetRef;
239
- private assertUniqueMigrationId;
240
244
  private assertUniqueMigrationIds;
241
245
  private assertNewKey;
246
+ private assertGraphDependenciesSatisfied;
247
+ private getFeatureFile;
248
+ private registerFeatureFile;
249
+ private syncFeatureGraphNode;
250
+ private registerAction;
251
+ private syncFrontendGraphNode;
252
+ private capabilityDependsOn;
253
+ private policyDependsOn;
254
+ private featureDependsOn;
255
+ private actionDependsOn;
256
+ private planDependsOn;
257
+ private migrationDependsOn;
258
+ private frontendDependsOn;
259
+ private dependenciesFor;
260
+ private existingDependenciesFor;
242
261
  }
243
262
  export declare function isBusiness(value: unknown): value is Business;
244
263
  export declare function business(name: string, options: BusinessOptions): Business;
@@ -14,7 +14,8 @@ 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, CapabilityOptions, FrontendNavItemOptions, FrontendPageOptions, FrontendComponentOptions, FeatureOptions, RouteOptions, PolicyOptions, PlanOptions, MeterRef, 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, } from "./business.js";
18
+ export type { ManifestResourceGraphSnapshot, ManifestResourceKind, ManifestResourceUrn, } from "./resource-graph.js";
18
19
  export type { PriceSpec } from "./price.js";
19
20
  export type { ManifestIssue } from "./errors.js";
20
21
  export type { ValidationResult } from "./validate.js";
@@ -197,6 +197,29 @@ export type CountedResourceJson = {
197
197
  subjectType?: string;
198
198
  countSource?: CountedResourceCountSourceJson;
199
199
  };
200
+ export type ProductCleanupPolicyModeJson = "report" | "pull_request";
201
+ export type ProductChangeApprovalRiskJson = "safe" | "non_blocking" | "economic_risk" | "blocking";
202
+ export type ProductPoliciesJson = {
203
+ cleanup?: {
204
+ enabled?: boolean;
205
+ mode?: ProductCleanupPolicyModeJson;
206
+ };
207
+ change_approval?: {
208
+ auto_merge_max_risk?: "none" | "safe" | "non_blocking";
209
+ require_human_for?: ProductChangeApprovalRiskJson[];
210
+ };
211
+ };
212
+ export type CustomerIdentityRequirementJson = "org_only" | "org_and_user";
213
+ export type CustomerPortalAuthStrategyJson = "clerk" | "test-personas";
214
+ export type ProductCustomerContextJson = {
215
+ identity_requirement?: CustomerIdentityRequirementJson;
216
+ context_tokens?: {
217
+ enabled?: boolean;
218
+ };
219
+ portal_auth?: {
220
+ strategy: CustomerPortalAuthStrategyJson;
221
+ };
222
+ };
200
223
  export type ProductBlockJson = {
201
224
  name: string;
202
225
  displayName?: string;
@@ -224,6 +247,8 @@ export type ProductSpecJson = {
224
247
  frontend?: FrontendManifestJson;
225
248
  migrations?: MigrationDeclJson[];
226
249
  resources?: CountedResourceJson[];
250
+ policies?: ProductPoliciesJson;
251
+ customer_context?: ProductCustomerContextJson;
227
252
  plans?: PlanSpecJson[];
228
253
  /** Legacy / advanced product blocks (usage, features, billing,
229
254
  * webhooks, environments, add_ons, lifecycle, ephemeral, …) ride
@@ -0,0 +1,36 @@
1
+ export type ManifestResourceKind = "product" | "meter" | "counted_resource" | "capability" | "policy" | "feature" | "action" | "plan" | "frontend" | "lifecycle_migration";
2
+ export type ManifestResourceUrn = `urn:farthershore:product:${ManifestResourceKind}:${string}`;
3
+ export type ManifestResourceRef = {
4
+ readonly kind: ManifestResourceKind;
5
+ readonly key: string;
6
+ };
7
+ export type ManifestResourceNode<T = unknown> = {
8
+ readonly urn: ManifestResourceUrn;
9
+ readonly kind: ManifestResourceKind;
10
+ readonly key: string;
11
+ readonly value: T;
12
+ readonly dependsOn: readonly ManifestResourceUrn[];
13
+ readonly declarationOrder: number;
14
+ };
15
+ export type ManifestResourceGraphSnapshot = {
16
+ readonly nodes: readonly Omit<ManifestResourceNode, "value">[];
17
+ };
18
+ export type MissingManifestResourceDependency = {
19
+ readonly from: ManifestResourceUrn;
20
+ readonly missing: ManifestResourceUrn;
21
+ };
22
+ export declare class ManifestResourceGraph {
23
+ private readonly nodes;
24
+ private declarationOrder;
25
+ register<T>(kind: ManifestResourceKind, key: string, value: T, dependsOn?: readonly ManifestResourceUrn[]): ManifestResourceNode<T>;
26
+ upsert<T>(kind: ManifestResourceKind, key: string, value: T, dependsOn?: readonly ManifestResourceUrn[]): ManifestResourceNode<T>;
27
+ clearKind(kind: ManifestResourceKind): void;
28
+ has(kind: ManifestResourceKind, key: string): boolean;
29
+ get<T>(kind: ManifestResourceKind, key: string): ManifestResourceNode<T> | null;
30
+ values<T>(kind: ManifestResourceKind): T[];
31
+ sortedValues<T>(kind: ManifestResourceKind, key: (value: T) => string): T[];
32
+ snapshot(): ManifestResourceGraphSnapshot;
33
+ missingDependencies(): MissingManifestResourceDependency[];
34
+ }
35
+ export declare function resourceUrn(kind: ManifestResourceKind, key: string): ManifestResourceUrn;
36
+ export declare function resourceDependency(kind: ManifestResourceKind, key: string): ManifestResourceUrn;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farthershore/product",
3
- "version": "0.0.0",
3
+ "version": "0.1.0",
4
4
  "description": "Farther Shore product-as-code SDK — declare your business in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",