@objectstack/cloud-connection 9.3.0 → 9.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.
package/dist/index.d.cts CHANGED
@@ -432,26 +432,50 @@ declare function createCloudConnectionPlugin(config?: CloudConnectionPluginConfi
432
432
  * cloudUrl: string, // base URL of the upstream cloud ('' = same origin)
433
433
  * singleEnvironment: boolean,
434
434
  * defaultOrgId?, defaultEnvironmentId?, // multi-tenant, per-hostname
435
- * features: { installLocal, marketplace, aiStudio, autoPublishAiBuilds },
435
+ * features: { installLocal, marketplace, aiStudio, autoPublishAiBuilds, ... },
436
436
  * branding: { productName, productShortName }
437
437
  * }
438
438
  *
439
- * ## Policy seam (ADR-0008 / open-mechanism-closed-intelligence)
439
+ * ## Feature seam (open-core boundary — cloud ADR-0012)
440
440
  *
441
- * Which features a *plan* unlocks is distribution policy, not mechanism — it
442
- * intentionally does NOT live in this open package. Hosts inject it via
443
- * {@link RuntimeConfigPluginConfig.resolvePlanFeatures}: the cloud
444
- * distribution passes its plan-entitlement rules there; a self-hosted or
445
- * vanilla deployment omits it and gets static config-driven flags.
441
+ * This open package owns the **mechanism**: serve a per-request `features`
442
+ * map to the SPA. It does NOT own the **catalog or policy** which feature
443
+ * keys exist and which billing plan unlocks them is a distribution concern
444
+ * and must never be enumerated here (that would bleed commercial/pricing
445
+ * policy into the open framework).
446
+ *
447
+ * Hosts inject policy via {@link RuntimeConfigPluginConfig.resolveFeatures}: it
448
+ * receives an opaque environment token (the cloud distribution passes the plan
449
+ * string) and returns an **open-ended** map of feature flags that is merged
450
+ * verbatim into `features`. The framework neither names nor knows those keys —
451
+ * e.g. the cloud distribution returns `customDomain` / `sso` from its plan
452
+ * entitlements without any framework change. A self-hosted / vanilla
453
+ * deployment omits the hook and gets static, config-driven flags.
454
+ *
455
+ * `aiStudio` / `autoPublishAiBuilds` are the framework's own non-commercial
456
+ * mechanism defaults (ADR-0005: AI authoring is an all-plan capability gated
457
+ * by cost, not a paid tier), so they keep first-class config knobs here.
446
458
  */
447
459
 
448
- /** Capability flags a host's plan policy can derive per request. */
449
- interface RuntimeConfigPlanFeatures {
460
+ /**
461
+ * Feature-flag overrides a host's distribution policy can derive per request.
462
+ *
463
+ * Open-ended on purpose: the framework's own flags (`aiStudio`,
464
+ * `autoPublishAiBuilds`) are named, but a distribution may return **any**
465
+ * additional boolean keys (commercial tiering, white-label toggles, …) and
466
+ * they pass through to the SPA untouched. The framework does not enumerate
467
+ * the distribution's feature catalog.
468
+ */
469
+ interface RuntimeFeatureOverrides {
450
470
  /** Whether the SPA should surface AI-driven metadata authoring. */
451
471
  aiStudio?: boolean;
452
472
  /** Whether AI-built apps auto-publish in the author's own environment. */
453
473
  autoPublishAiBuilds?: boolean;
474
+ /** Distribution-specific flags pass through opaquely (e.g. customDomain, sso). */
475
+ [feature: string]: boolean | undefined;
454
476
  }
477
+ /** @deprecated billing-vocab name; use {@link RuntimeFeatureOverrides}. */
478
+ type RuntimeConfigPlanFeatures = RuntimeFeatureOverrides;
455
479
  interface RuntimeConfigPluginConfig {
456
480
  /**
457
481
  * Upstream cloud base URL. Falls back to `resolveCloudUrl()` (reads
@@ -485,13 +509,21 @@ interface RuntimeConfigPluginConfig {
485
509
  /** Short product name (PWA shortName, compact spots). Defaults to productName. */
486
510
  productShortName?: string;
487
511
  /**
488
- * Plan feature policy hook. Called with `undefined` for the static
489
- * default (no environment resolved / no plan known) and with the
490
- * environment's plan string once hostname resolution provides one.
491
- * Returned flags override the static config defaults; omitted keys keep
492
- * them. When the hook itself is omitted, flags are purely config-driven.
512
+ * Distribution feature-policy hook (open-core seam cloud ADR-0012).
513
+ * Called with `undefined` for the static default (no environment resolved
514
+ * / no token known) and with an opaque environment token (the cloud
515
+ * distribution passes the plan string) once hostname resolution provides
516
+ * one. Returned flags are merged verbatim into `features` arbitrary keys
517
+ * pass through. Omitted keys keep the static config defaults; when the hook
518
+ * itself is omitted, flags are purely config-driven. The framework does NOT
519
+ * know the distribution's feature catalog or pricing.
520
+ */
521
+ resolveFeatures?: (token: string | undefined) => RuntimeFeatureOverrides;
522
+ /**
523
+ * @deprecated billing-vocab name; use {@link resolveFeatures}. Still
524
+ * honoured when `resolveFeatures` is absent so existing hosts keep working.
493
525
  */
494
- resolvePlanFeatures?: (plan: string | undefined) => RuntimeConfigPlanFeatures;
526
+ resolvePlanFeatures?: (plan: string | undefined) => RuntimeFeatureOverrides;
495
527
  }
496
528
  declare class RuntimeConfigPlugin implements Plugin$1 {
497
529
  readonly name = "com.objectstack.runtime.runtime-config";
@@ -502,11 +534,10 @@ declare class RuntimeConfigPlugin implements Plugin$1 {
502
534
  private readonly singleEnvironment;
503
535
  private readonly productName;
504
536
  private readonly productShortName;
505
- private readonly resolvePlanFeatures?;
537
+ private readonly resolveFeatures?;
506
538
  constructor(config?: RuntimeConfigPluginConfig);
507
539
  init: (_ctx: PluginContext$1) => Promise<void>;
508
540
  start: (ctx: PluginContext$1) => Promise<void>;
509
- destroy: () => Promise<void>;
510
541
  }
511
542
 
512
543
  /** Persisted binding credential + context. */
@@ -565,7 +596,7 @@ declare const CLOUD_CONNECTION_UI_BUNDLE: {
565
596
  pages: {
566
597
  name: string;
567
598
  label: string;
568
- type: "app" | "record" | "dashboard" | "grid" | "form" | "utility" | "kanban" | "gallery" | "calendar" | "timeline" | "list" | "home" | "record_detail" | "record_review" | "overview" | "blank";
599
+ type: "app" | "record" | "dashboard" | "form" | "utility" | "list" | "home" | "record_detail" | "record_review" | "overview" | "blank";
569
600
  template: string;
570
601
  regions: {
571
602
  name: string;
@@ -685,7 +716,7 @@ declare const CLOUD_CONNECTION_UI_BUNDLE: {
685
716
  }[] | undefined;
686
717
  appearance?: {
687
718
  showDescription: boolean;
688
- allowedVisualizations?: ("grid" | "kanban" | "gallery" | "calendar" | "timeline" | "map" | "gantt" | "chart")[] | undefined;
719
+ allowedVisualizations?: ("map" | "grid" | "kanban" | "gallery" | "calendar" | "timeline" | "gantt" | "chart")[] | undefined;
689
720
  } | undefined;
690
721
  userFilters?: {
691
722
  element: "tabs" | "toggle" | "dropdown";
@@ -1691,4 +1722,4 @@ declare const MARKETPLACE_INSTALLED_UI_BUNDLE: {
1691
1722
  }[];
1692
1723
  };
1693
1724
 
1694
- export { CLOUD_CONNECTION_UI_BUNDLE, CloudConnectionPlugin, type CloudConnectionPluginConfig, CloudConnectionSettingsPage, ConnectionCredentialStore, DEFAULT_CLOUD_URL, DEFAULT_CONNECTION_CREDENTIAL_PATH, DEFAULT_INSTALLED_PACKAGES_DIR, type InstalledManifestEntry, LocalManifestSource, MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, type RuntimeConfigPlanFeatures, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, type StoredConnectionCredential, createCloudConnectionPlugin, publicMarketplaceKeyForApiPath, resolveCloudUrl, resolveMarketplacePublicBaseUrl };
1725
+ export { CLOUD_CONNECTION_UI_BUNDLE, CloudConnectionPlugin, type CloudConnectionPluginConfig, CloudConnectionSettingsPage, ConnectionCredentialStore, DEFAULT_CLOUD_URL, DEFAULT_CONNECTION_CREDENTIAL_PATH, DEFAULT_INSTALLED_PACKAGES_DIR, type InstalledManifestEntry, LocalManifestSource, MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, type RuntimeConfigPlanFeatures, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, type RuntimeFeatureOverrides, type StoredConnectionCredential, createCloudConnectionPlugin, publicMarketplaceKeyForApiPath, resolveCloudUrl, resolveMarketplacePublicBaseUrl };
package/dist/index.d.ts CHANGED
@@ -432,26 +432,50 @@ declare function createCloudConnectionPlugin(config?: CloudConnectionPluginConfi
432
432
  * cloudUrl: string, // base URL of the upstream cloud ('' = same origin)
433
433
  * singleEnvironment: boolean,
434
434
  * defaultOrgId?, defaultEnvironmentId?, // multi-tenant, per-hostname
435
- * features: { installLocal, marketplace, aiStudio, autoPublishAiBuilds },
435
+ * features: { installLocal, marketplace, aiStudio, autoPublishAiBuilds, ... },
436
436
  * branding: { productName, productShortName }
437
437
  * }
438
438
  *
439
- * ## Policy seam (ADR-0008 / open-mechanism-closed-intelligence)
439
+ * ## Feature seam (open-core boundary — cloud ADR-0012)
440
440
  *
441
- * Which features a *plan* unlocks is distribution policy, not mechanism — it
442
- * intentionally does NOT live in this open package. Hosts inject it via
443
- * {@link RuntimeConfigPluginConfig.resolvePlanFeatures}: the cloud
444
- * distribution passes its plan-entitlement rules there; a self-hosted or
445
- * vanilla deployment omits it and gets static config-driven flags.
441
+ * This open package owns the **mechanism**: serve a per-request `features`
442
+ * map to the SPA. It does NOT own the **catalog or policy** which feature
443
+ * keys exist and which billing plan unlocks them is a distribution concern
444
+ * and must never be enumerated here (that would bleed commercial/pricing
445
+ * policy into the open framework).
446
+ *
447
+ * Hosts inject policy via {@link RuntimeConfigPluginConfig.resolveFeatures}: it
448
+ * receives an opaque environment token (the cloud distribution passes the plan
449
+ * string) and returns an **open-ended** map of feature flags that is merged
450
+ * verbatim into `features`. The framework neither names nor knows those keys —
451
+ * e.g. the cloud distribution returns `customDomain` / `sso` from its plan
452
+ * entitlements without any framework change. A self-hosted / vanilla
453
+ * deployment omits the hook and gets static, config-driven flags.
454
+ *
455
+ * `aiStudio` / `autoPublishAiBuilds` are the framework's own non-commercial
456
+ * mechanism defaults (ADR-0005: AI authoring is an all-plan capability gated
457
+ * by cost, not a paid tier), so they keep first-class config knobs here.
446
458
  */
447
459
 
448
- /** Capability flags a host's plan policy can derive per request. */
449
- interface RuntimeConfigPlanFeatures {
460
+ /**
461
+ * Feature-flag overrides a host's distribution policy can derive per request.
462
+ *
463
+ * Open-ended on purpose: the framework's own flags (`aiStudio`,
464
+ * `autoPublishAiBuilds`) are named, but a distribution may return **any**
465
+ * additional boolean keys (commercial tiering, white-label toggles, …) and
466
+ * they pass through to the SPA untouched. The framework does not enumerate
467
+ * the distribution's feature catalog.
468
+ */
469
+ interface RuntimeFeatureOverrides {
450
470
  /** Whether the SPA should surface AI-driven metadata authoring. */
451
471
  aiStudio?: boolean;
452
472
  /** Whether AI-built apps auto-publish in the author's own environment. */
453
473
  autoPublishAiBuilds?: boolean;
474
+ /** Distribution-specific flags pass through opaquely (e.g. customDomain, sso). */
475
+ [feature: string]: boolean | undefined;
454
476
  }
477
+ /** @deprecated billing-vocab name; use {@link RuntimeFeatureOverrides}. */
478
+ type RuntimeConfigPlanFeatures = RuntimeFeatureOverrides;
455
479
  interface RuntimeConfigPluginConfig {
456
480
  /**
457
481
  * Upstream cloud base URL. Falls back to `resolveCloudUrl()` (reads
@@ -485,13 +509,21 @@ interface RuntimeConfigPluginConfig {
485
509
  /** Short product name (PWA shortName, compact spots). Defaults to productName. */
486
510
  productShortName?: string;
487
511
  /**
488
- * Plan feature policy hook. Called with `undefined` for the static
489
- * default (no environment resolved / no plan known) and with the
490
- * environment's plan string once hostname resolution provides one.
491
- * Returned flags override the static config defaults; omitted keys keep
492
- * them. When the hook itself is omitted, flags are purely config-driven.
512
+ * Distribution feature-policy hook (open-core seam cloud ADR-0012).
513
+ * Called with `undefined` for the static default (no environment resolved
514
+ * / no token known) and with an opaque environment token (the cloud
515
+ * distribution passes the plan string) once hostname resolution provides
516
+ * one. Returned flags are merged verbatim into `features` arbitrary keys
517
+ * pass through. Omitted keys keep the static config defaults; when the hook
518
+ * itself is omitted, flags are purely config-driven. The framework does NOT
519
+ * know the distribution's feature catalog or pricing.
520
+ */
521
+ resolveFeatures?: (token: string | undefined) => RuntimeFeatureOverrides;
522
+ /**
523
+ * @deprecated billing-vocab name; use {@link resolveFeatures}. Still
524
+ * honoured when `resolveFeatures` is absent so existing hosts keep working.
493
525
  */
494
- resolvePlanFeatures?: (plan: string | undefined) => RuntimeConfigPlanFeatures;
526
+ resolvePlanFeatures?: (plan: string | undefined) => RuntimeFeatureOverrides;
495
527
  }
496
528
  declare class RuntimeConfigPlugin implements Plugin$1 {
497
529
  readonly name = "com.objectstack.runtime.runtime-config";
@@ -502,11 +534,10 @@ declare class RuntimeConfigPlugin implements Plugin$1 {
502
534
  private readonly singleEnvironment;
503
535
  private readonly productName;
504
536
  private readonly productShortName;
505
- private readonly resolvePlanFeatures?;
537
+ private readonly resolveFeatures?;
506
538
  constructor(config?: RuntimeConfigPluginConfig);
507
539
  init: (_ctx: PluginContext$1) => Promise<void>;
508
540
  start: (ctx: PluginContext$1) => Promise<void>;
509
- destroy: () => Promise<void>;
510
541
  }
511
542
 
512
543
  /** Persisted binding credential + context. */
@@ -565,7 +596,7 @@ declare const CLOUD_CONNECTION_UI_BUNDLE: {
565
596
  pages: {
566
597
  name: string;
567
598
  label: string;
568
- type: "app" | "record" | "dashboard" | "grid" | "form" | "utility" | "kanban" | "gallery" | "calendar" | "timeline" | "list" | "home" | "record_detail" | "record_review" | "overview" | "blank";
599
+ type: "app" | "record" | "dashboard" | "form" | "utility" | "list" | "home" | "record_detail" | "record_review" | "overview" | "blank";
569
600
  template: string;
570
601
  regions: {
571
602
  name: string;
@@ -685,7 +716,7 @@ declare const CLOUD_CONNECTION_UI_BUNDLE: {
685
716
  }[] | undefined;
686
717
  appearance?: {
687
718
  showDescription: boolean;
688
- allowedVisualizations?: ("grid" | "kanban" | "gallery" | "calendar" | "timeline" | "map" | "gantt" | "chart")[] | undefined;
719
+ allowedVisualizations?: ("map" | "grid" | "kanban" | "gallery" | "calendar" | "timeline" | "gantt" | "chart")[] | undefined;
689
720
  } | undefined;
690
721
  userFilters?: {
691
722
  element: "tabs" | "toggle" | "dropdown";
@@ -1691,4 +1722,4 @@ declare const MARKETPLACE_INSTALLED_UI_BUNDLE: {
1691
1722
  }[];
1692
1723
  };
1693
1724
 
1694
- export { CLOUD_CONNECTION_UI_BUNDLE, CloudConnectionPlugin, type CloudConnectionPluginConfig, CloudConnectionSettingsPage, ConnectionCredentialStore, DEFAULT_CLOUD_URL, DEFAULT_CONNECTION_CREDENTIAL_PATH, DEFAULT_INSTALLED_PACKAGES_DIR, type InstalledManifestEntry, LocalManifestSource, MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, type RuntimeConfigPlanFeatures, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, type StoredConnectionCredential, createCloudConnectionPlugin, publicMarketplaceKeyForApiPath, resolveCloudUrl, resolveMarketplacePublicBaseUrl };
1725
+ export { CLOUD_CONNECTION_UI_BUNDLE, CloudConnectionPlugin, type CloudConnectionPluginConfig, CloudConnectionSettingsPage, ConnectionCredentialStore, DEFAULT_CLOUD_URL, DEFAULT_CONNECTION_CREDENTIAL_PATH, DEFAULT_INSTALLED_PACKAGES_DIR, type InstalledManifestEntry, LocalManifestSource, MARKETPLACE_BROWSE_UI_BUNDLE, MARKETPLACE_INSTALLED_UI_BUNDLE, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, type RuntimeConfigPlanFeatures, RuntimeConfigPlugin, type RuntimeConfigPluginConfig, type RuntimeFeatureOverrides, type StoredConnectionCredential, createCloudConnectionPlugin, publicMarketplaceKeyForApiPath, resolveCloudUrl, resolveMarketplacePublicBaseUrl };
package/dist/index.js CHANGED
@@ -1689,12 +1689,14 @@ var RuntimeConfigPlugin = class {
1689
1689
  envRegistry = ctx.getService("env-registry");
1690
1690
  } catch {
1691
1691
  }
1692
- const featuresFor = (plan, base) => {
1693
- const derived = this.resolvePlanFeatures?.(plan);
1694
- return {
1695
- aiStudio: derived?.aiStudio ?? base.aiStudio,
1696
- autoPublishAiBuilds: derived?.autoPublishAiBuilds ?? base.autoPublishAiBuilds
1697
- };
1692
+ const featuresFor = (token, base) => {
1693
+ const derived = this.resolveFeatures?.(token);
1694
+ if (!derived) return { ...base };
1695
+ const out = { ...base };
1696
+ for (const [k, v] of Object.entries(derived)) {
1697
+ if (typeof v === "boolean") out[k] = v;
1698
+ }
1699
+ return out;
1698
1700
  };
1699
1701
  const handler = async (c) => {
1700
1702
  const rawHost = c.req.header("host") ?? "";
@@ -1727,8 +1729,8 @@ var RuntimeConfigPlugin = class {
1727
1729
  features: {
1728
1730
  installLocal: this.installLocal,
1729
1731
  marketplace: true,
1730
- aiStudio: features.aiStudio,
1731
- autoPublishAiBuilds: features.autoPublishAiBuilds
1732
+ // aiStudio + autoPublishAiBuilds + any distribution keys.
1733
+ ...features
1732
1734
  },
1733
1735
  branding: {
1734
1736
  productName: this.productName,
@@ -1738,20 +1740,13 @@ var RuntimeConfigPlugin = class {
1738
1740
  };
1739
1741
  rawApp.get("/api/v1/runtime/config", handler);
1740
1742
  rawApp.get("/api/v1/studio/runtime-config", handler);
1741
- ctx.logger?.info?.("[RuntimeConfigPlugin] mounted /api/v1/runtime/config", {
1742
- cloudUrl: this.cloudUrl || "(empty)",
1743
- installLocal: this.installLocal,
1744
- perHostEnvResolution: !!envRegistry
1745
- });
1746
1743
  });
1747
1744
  };
1748
- this.destroy = async () => {
1749
- };
1750
1745
  this.cloudUrl = config.controlPlaneUrl === "" ? "" : resolveCloudUrl(config.controlPlaneUrl) ?? "";
1751
1746
  this.installLocal = !!config.installLocal;
1752
1747
  this.aiStudio = config.aiStudio !== false;
1753
1748
  this.singleEnvironment = !!config.singleEnvironment;
1754
- this.resolvePlanFeatures = config.resolvePlanFeatures;
1749
+ this.resolveFeatures = config.resolveFeatures ?? config.resolvePlanFeatures;
1755
1750
  const envName = (typeof process !== "undefined" ? process.env?.OS_PRODUCT_NAME : void 0)?.trim();
1756
1751
  const envShort = (typeof process !== "undefined" ? process.env?.OS_PRODUCT_SHORT_NAME : void 0)?.trim();
1757
1752
  this.productName = (config.productName ?? envName ?? "ObjectOS").trim() || "ObjectOS";