@lepsto/sdk-app 94.0.0 → 94.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/CHANGELOG.md CHANGED
@@ -29,6 +29,16 @@ are not covered here — 84.0.0 is the first version published as
29
29
  `@lepsto/sdk-app`. `@lessly/sdk-app` 86.0.0 and 87.0.0 were never mirrored to
30
30
  `@lepsto/sdk-app`, so those two numbers are absent from this package.
31
31
 
32
+ ## Unreleased (runtime minor)
33
+
34
+ ### Added
35
+
36
+ - `isEntitlementError(err)` — true for billing's plan refusal: HTTP 402 with a
37
+ body `error` of `entitlement_exhausted` or `entitlement_unavailable`, the same rule the Workspace shell
38
+ uses to show its one refusal window. Structural, like `isAccessDenied`.
39
+ - `upgradeUrl(err)` — the refusal's `upgrade_url` (absolute `http(s)` only),
40
+ for Apps the shell cannot see. Recipe: `docs/recipes/entitlements.md`.
41
+
32
42
  ## 87.3.1 — 2026-09-17
33
43
 
34
44
  ### Fixed
@@ -115,52 +125,9 @@ before this point lives in that package.
115
125
  The publish pipeline appends its machine-rendered block for the release being
116
126
  built below this line. It is not committed back to the repo, so in a git
117
127
  checkout this section is empty — see the note at the top.
118
- ## 94.0.0 (major)
119
-
120
- ### content
121
- - `content_channels_list`: new accepted value on `network`
122
- - `content_metrics_channel_series`: new accepted value on `network (output)`
123
- - `content_metrics_post_series`: new accepted value on `network (output)`
124
- - `content_posts_approve`: new optional field `targets (output)`
125
- - `content_posts_attach_media`: new optional field `targets (output)`
126
- - `content_posts_create`: its composer-step declaration changed
127
- - `content_posts_create`: new optional field `targets`
128
- - `content_posts_create`: new optional field `targets (output)`
129
- - `content_posts_create`: description updated
130
- - `content_posts_detach_media`: new optional field `targets (output)`
131
- - `content_posts_get`: its composer-step declaration changed
132
- - `content_posts_get`: new optional field `targets (output)`
133
- - `content_posts_list`: its composer-step declaration changed
134
- - `content_posts_list`: new optional field `posts.targets (output)`
135
- - `content_posts_submit`: its composer-step declaration changed
136
- - `content_posts_submit`: new optional field `targets (output)`
137
- - `content_posts_submit`: description updated
138
- - `content_posts_update`: new optional field `targets`
139
- - `content_posts_update`: new optional field `targets (output)`
140
- - `content_posts_update`: description updated
141
- - `content_posts_versions`: new optional field `versions.targets (output)`
142
- - `content_publications_cancel`: new optional field `fields (output)`
143
- - `content_publications_cancel`: new optional field `postType (output)`
144
- - `content_publications_confirm`: new optional field `fields (output)`
145
- - `content_publications_confirm`: new optional field `postType (output)`
146
- - `content_publications_get`: new optional field `fields (output)`
147
- - `content_publications_get`: new optional field `postType (output)`
148
- - `content_publications_list`: new optional field `publications.fields (output)`
149
- - `content_publications_list`: new optional field `publications.postType (output)`
150
- - `content_publications_publish`: removed field `text`
151
- - `content_publications_publish`: new optional field `fields (output)`
152
- - `content_publications_publish`: new optional field `postType (output)`
153
- - `content_publications_publish`: description updated
154
- - `content_publications_remind`: new optional field `fields (output)`
155
- - `content_publications_remind`: new optional field `postType (output)`
156
- - `content_publications_reschedule`: new optional field `fields (output)`
157
- - `content_publications_reschedule`: new optional field `postType (output)`
158
- - `content_publications_schedule`: removed field `text`
159
- - `content_publications_schedule`: new optional field `fields (output)`
160
- - `content_publications_schedule`: new optional field `postType (output)`
161
- - `content_publications_schedule`: description updated
162
- - `content_publications_validate`: removed field `channels.text`
163
- - `content_publications_validate`: new accepted value on `channels.issues.code (output)`
164
- - `content_publications_validate`: new accepted value on `channels.network (output)`
165
- - `content_publications_validate`: description updated
128
+ ## 94.2.0 (minor)
129
+
130
+ ### *
131
+ - runtime update
132
+ - documentation update
166
133
 
@@ -1,7 +1,7 @@
1
1
  export { createLesslyApp } from './runtime/createLesslyApp.js';
2
2
  export type { LesslyClientBase } from './runtime/createLesslyApp.js';
3
3
  export { connectStream } from './runtime/connectStream.js';
4
- export { LesslyApiError, isAccessDenied } from './runtime/errors.js';
4
+ export { LesslyApiError, isAccessDenied, isEntitlementError, upgradeUrl } from './runtime/errors.js';
5
5
  export { accessReason } from './runtime/access-reason.js';
6
6
  export { platformApiBaseUrl } from './runtime/platform-base-url.js';
7
7
  export { operations } from './runtime/operations.js';
@@ -16,3 +16,16 @@ export declare function parseErrorBody(body: unknown, status: number): LesslyApi
16
16
  * report false there and an App would render a red crash for an ordinary permission refusal.
17
17
  */
18
18
  export declare function isAccessDenied(err: unknown): boolean;
19
+ /**
20
+ * True iff `err` is billing refusing the call over the organization's plan (trial cap reached,
21
+ * a class closed on a trial, billing or budget paused). Inside the Workspace shell the shell
22
+ * shows the refusal itself: an App uses this to render nothing, not a second error.
23
+ */
24
+ export declare function isEntitlementError(err: unknown): boolean;
25
+ /**
26
+ * The refusal's `upgrade_url` — the Workspace billing page with the upgrade offer open for the
27
+ * refused organization — or null when `err` is not an entitlement refusal or carries no usable
28
+ * URL. For Apps the shell cannot see (standalone, or calling through their own `fetch`). Only an
29
+ * absolute http(s) URL is returned: the value is meant to be navigated to.
30
+ */
31
+ export declare function upgradeUrl(err: unknown): string | null;
package/dist/index.cjs CHANGED
@@ -33,6 +33,27 @@ function isAccessDenied(err) {
33
33
  const { status, code } = err;
34
34
  return status === 403 && typeof code === "string" && ACCESS_DENIED_CODES.has(code);
35
35
  }
36
+ var ENTITLEMENT_ERRORS = /* @__PURE__ */ new Set(["entitlement_exhausted", "entitlement_unavailable"]);
37
+ function entitlementRefusal(err) {
38
+ if (typeof err !== "object" || err === null) return null;
39
+ const { status, body } = err;
40
+ if (status !== 402 || typeof body !== "object" || body === null) return null;
41
+ const { error } = body;
42
+ return typeof error === "string" && ENTITLEMENT_ERRORS.has(error) ? body : null;
43
+ }
44
+ function isEntitlementError(err) {
45
+ return entitlementRefusal(err) !== null;
46
+ }
47
+ function upgradeUrl(err) {
48
+ const url = entitlementRefusal(err)?.upgrade_url;
49
+ if (typeof url !== "string") return null;
50
+ try {
51
+ const { protocol } = new URL(url);
52
+ return protocol === "https:" || protocol === "http:" ? url : null;
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
36
57
 
37
58
  // src/runtime/csrf.ts
38
59
  var CSRF_COOKIES = ["lepsto_csrf", "lessly_csrf"];
@@ -12965,7 +12986,9 @@ exports.compositions = compositions2;
12965
12986
  exports.connectStream = connectStream;
12966
12987
  exports.createLesslyApp = createLesslyApp;
12967
12988
  exports.isAccessDenied = isAccessDenied;
12989
+ exports.isEntitlementError = isEntitlementError;
12968
12990
  exports.operations = operations2;
12969
12991
  exports.platformApiBaseUrl = platformApiBaseUrl;
12992
+ exports.upgradeUrl = upgradeUrl;
12970
12993
  //# sourceMappingURL=index.cjs.map
12971
12994
  //# sourceMappingURL=index.cjs.map