@streamoid/settings 0.7.6 → 0.7.8
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 +2 -0
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +219 -63
- package/dist/index.mjs +227 -71
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -223,3 +223,5 @@ and shares light/dark canvas, card, text, divider and selection colors with the
|
|
|
223
223
|
host sidebar. Removing settings restores the host theme. Host wrappers must
|
|
224
224
|
remain transparent and use `--alias-surface-canvas` for the app floor; do not
|
|
225
225
|
paint `--alias-surface-base` behind the whole settings page.
|
|
226
|
+
|
|
227
|
+
Handled cancellations remain silent through the toast adapter. A confirmed member update or removal closes its editor before refreshing the list. The only-admin leave guard inspects retained diagnostics before selecting its authored guidance; diagnostic text is never rendered.
|
package/dist/index.d.mts
CHANGED
|
@@ -366,9 +366,12 @@ interface OrganizationWorkspaceItem {
|
|
|
366
366
|
imageUrl?: string;
|
|
367
367
|
orgVisibility: "private" | "shared";
|
|
368
368
|
/** Whether the viewer is in it. An org member is shown every shared
|
|
369
|
-
* workspace; the ones with `joined: false`
|
|
370
|
-
* `joinWorkspaces`). Absent is treated as joined.
|
|
369
|
+
* workspace, an org admin every workspace; the ones with `joined: false`
|
|
370
|
+
* get a Join button (with `joinWorkspaces`). Absent is treated as joined.
|
|
371
|
+
* A member joins as member, an org admin as admin. */
|
|
371
372
|
joined?: boolean;
|
|
373
|
+
/** "inactive" workspaces are listed to org admins but can't be joined. */
|
|
374
|
+
status?: string;
|
|
372
375
|
}
|
|
373
376
|
/** A shared workspace in the organization that the viewer isn't in yet. */
|
|
374
377
|
interface OrganizationJoinableWorkspace {
|
package/dist/index.d.ts
CHANGED
|
@@ -366,9 +366,12 @@ interface OrganizationWorkspaceItem {
|
|
|
366
366
|
imageUrl?: string;
|
|
367
367
|
orgVisibility: "private" | "shared";
|
|
368
368
|
/** Whether the viewer is in it. An org member is shown every shared
|
|
369
|
-
* workspace; the ones with `joined: false`
|
|
370
|
-
* `joinWorkspaces`). Absent is treated as joined.
|
|
369
|
+
* workspace, an org admin every workspace; the ones with `joined: false`
|
|
370
|
+
* get a Join button (with `joinWorkspaces`). Absent is treated as joined.
|
|
371
|
+
* A member joins as member, an org admin as admin. */
|
|
371
372
|
joined?: boolean;
|
|
373
|
+
/** "inactive" workspaces are listed to org admins but can't be joined. */
|
|
374
|
+
status?: string;
|
|
372
375
|
}
|
|
373
376
|
/** A shared workspace in the organization that the viewer isn't in yet. */
|
|
374
377
|
interface OrganizationJoinableWorkspace {
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,161 @@ __export(index_exports, {
|
|
|
67
67
|
});
|
|
68
68
|
module.exports = __toCommonJS(index_exports);
|
|
69
69
|
|
|
70
|
+
// src/settings-errors.ts
|
|
71
|
+
function quietErrorToast(toast) {
|
|
72
|
+
return { ...toast, error(message) {
|
|
73
|
+
if (message.trim()) toast.error(message);
|
|
74
|
+
} };
|
|
75
|
+
}
|
|
76
|
+
function isOnlyWorkspaceAdmin(failure) {
|
|
77
|
+
const seen = /* @__PURE__ */ new Set();
|
|
78
|
+
const visit = (value, depth) => {
|
|
79
|
+
if (depth > 4 || value == null || seen.has(value)) return false;
|
|
80
|
+
if (typeof value === "string") return /single admin|only admin/i.test(value);
|
|
81
|
+
if (typeof value !== "object") return false;
|
|
82
|
+
seen.add(value);
|
|
83
|
+
const error = value;
|
|
84
|
+
return [error.body, error.data, error.status, error.message, error.error, error.cause].some((child) => visit(child, depth + 1));
|
|
85
|
+
};
|
|
86
|
+
return visit(failure, 0);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ../errors/index.js
|
|
90
|
+
var actions = /* @__PURE__ */ new Set(["edit_input", "sign_in", "ask_admin", "wait", "view_status", "retry", "contact_support"]);
|
|
91
|
+
var states = /* @__PURE__ */ new Set(["not_started", "failed", "partial", "in_progress", "unknown"]);
|
|
92
|
+
var isObject = (value) => value !== null && typeof value === "object";
|
|
93
|
+
var object = (value) => isObject(value) ? value : {};
|
|
94
|
+
var text = (value) => typeof value === "string" ? value : "";
|
|
95
|
+
var reference = (value) => /^[a-zA-Z0-9][a-zA-Z0-9_-]{5,127}$/.test(text(value)) ? value : void 0;
|
|
96
|
+
var technical = /https?:\/\/|<[^>]+>|\b(?:TypeError|SyntaxError|ReferenceError|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|Traceback|SQLSTATE|MongoServerError|localhost|undefined|null|NaN|CORS|stack trace|Xvfb|node:sqlite)\b|(?:\/[^\s/]+){3,}|\bat\s+\w+\s*\(/i;
|
|
97
|
+
var publicText = (value) => {
|
|
98
|
+
const s = text(value).trim();
|
|
99
|
+
return s && s.length <= 500 && !technical.test(s) && !/[\r\n{}]/.test(s) ? s : void 0;
|
|
100
|
+
};
|
|
101
|
+
var isCancellation = (error) => object(error).name === "AbortError";
|
|
102
|
+
function parseRetryAfter(value, now = Date.now()) {
|
|
103
|
+
if (!text(value).trim()) return void 0;
|
|
104
|
+
const seconds = /^\d+$/.test(value.trim()) ? Number(value) : Math.ceil((Date.parse(value) - now) / 1e3);
|
|
105
|
+
return Number.isFinite(seconds) && seconds >= 0 && seconds <= 86400 ? seconds : void 0;
|
|
106
|
+
}
|
|
107
|
+
function validationFields(body) {
|
|
108
|
+
if (!Array.isArray(body.detail)) return [];
|
|
109
|
+
return body.detail.slice(0, 20).flatMap((issue) => {
|
|
110
|
+
if (!isObject(issue) || !Array.isArray(issue.loc)) return [];
|
|
111
|
+
const path = issue.loc.filter((part) => part !== "body" && part !== "query").filter((part) => typeof part === "string" || typeof part === "number").join(".");
|
|
112
|
+
if (!/^[a-zA-Z0-9_.-]{1,150}$/.test(path)) return [];
|
|
113
|
+
return [{ path, message: issue.type === "missing" || issue.type === "value_error.missing" ? "This field is required." : "Check this value and try again." }];
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
var known = {
|
|
117
|
+
"platform.session_expired": ["Your session has expired. Sign in to continue.", "sign_in"],
|
|
118
|
+
"platform.permission_denied": ["You don't have permission to do this. Ask a workspace admin for access.", "ask_admin"],
|
|
119
|
+
"platform.insufficient_credits": ["There aren't enough credits for this action. Ask your billing admin to add credits.", "ask_admin"],
|
|
120
|
+
"platform.invalid_input": ["Check the information you entered and correct any highlighted fields.", "edit_input"],
|
|
121
|
+
"platform.not_found": ["This item is no longer available or you don't have access to it. Check that you've opened the correct workspace.", "view_status"],
|
|
122
|
+
"platform.conflict": ["This item has changed or already exists. Check its current state before continuing.", "view_status"],
|
|
123
|
+
"platform.file_too_large": ["This file is too large. Choose a smaller file and try again.", "edit_input"],
|
|
124
|
+
"platform.unsupported_file": ["This file type isn't supported. Choose one of the accepted file types.", "edit_input"],
|
|
125
|
+
"platform.content_rejected": ["This request couldn't be completed with the current input. Review the image or description and try again.", "edit_input"],
|
|
126
|
+
"platform.rate_limited": ["This service is busy. Wait a moment before trying again.", "wait"],
|
|
127
|
+
"platform.service_unavailable": ["A service is temporarily unavailable. Try again shortly; contact support if it keeps happening.", "wait"],
|
|
128
|
+
"platform.setup_required": ["There's a setup problem on our side. Contact support so we can help.", "contact_support"],
|
|
129
|
+
"platform.network_error": ["We couldn't reach the service. Check your connection and try again shortly.", "retry"],
|
|
130
|
+
"platform.unexpected": ["We couldn't complete this action. Contact support if it keeps happening.", "contact_support"]
|
|
131
|
+
};
|
|
132
|
+
function inferCode(status, rawCode, diagnostic) {
|
|
133
|
+
if (Object.hasOwn(known, rawCode)) return rawCode;
|
|
134
|
+
const signal = `${rawCode} ${diagnostic}`;
|
|
135
|
+
if (/insufficient.?credits|credits.?unavailable|insufficient.?balance/i.test(signal)) return "platform.insufficient_credits";
|
|
136
|
+
if (/content.?policy|safety.?block|content.?reject/i.test(signal)) return "platform.content_rejected";
|
|
137
|
+
if (/rate.?limit|capacity.?limit/i.test(signal)) return "platform.rate_limited";
|
|
138
|
+
if (status === 401) return "platform.session_expired";
|
|
139
|
+
if (status === 402) return "platform.insufficient_credits";
|
|
140
|
+
if (status === 403) return "platform.permission_denied";
|
|
141
|
+
if (status === 404 || status === 410) return "platform.not_found";
|
|
142
|
+
if (status === 409 || status === 412) return "platform.conflict";
|
|
143
|
+
if (status === 413) return "platform.file_too_large";
|
|
144
|
+
if (status === 415) return "platform.unsupported_file";
|
|
145
|
+
if (status === 429) return "platform.rate_limited";
|
|
146
|
+
if (status === 400 || status === 422) return "platform.invalid_input";
|
|
147
|
+
if ([408, 502, 503, 504].includes(status)) return "platform.service_unavailable";
|
|
148
|
+
if (/ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|server misbehaving|upstream unavailable/i.test(signal)) return "platform.service_unavailable";
|
|
149
|
+
if (/failed to fetch|networkerror|network request failed|load failed/i.test(signal)) return "platform.network_error";
|
|
150
|
+
return "platform.unexpected";
|
|
151
|
+
}
|
|
152
|
+
function normalizeError(failure, options = {}) {
|
|
153
|
+
if (failure instanceof UserFacingError && Object.keys(options).length === 0) return failure.publicError;
|
|
154
|
+
const error = object(failure);
|
|
155
|
+
const body = object(options.body ?? error.body ?? error.data ?? failure);
|
|
156
|
+
const envelope = object(body.publicError ?? error.publicError);
|
|
157
|
+
const declared = envelope.version === 1 ? envelope : {};
|
|
158
|
+
const status = Number(options.status ?? error.statusCode ?? (typeof error.status === "number" ? error.status : void 0)) || 0;
|
|
159
|
+
const diagnostic = [text(error.message), text(failure), text(body.detail), text(body.error)].filter(Boolean).join(" ");
|
|
160
|
+
const rawCode = text(declared.code) || text(object(body.error).code) || text(body.code) || text(error.code);
|
|
161
|
+
const category = inferCode(status, rawCode, diagnostic);
|
|
162
|
+
const code = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/.test(text(declared.code)) ? declared.code : category;
|
|
163
|
+
const method = (options.method || text(error.method) || "UNKNOWN").toUpperCase();
|
|
164
|
+
const read = ["GET", "HEAD", "OPTIONS"].includes(method);
|
|
165
|
+
const suppliedState = object(declared.operation).state;
|
|
166
|
+
const state = states.has(suppliedState) ? suppliedState : read ? "failed" : "unknown";
|
|
167
|
+
const retryAfterSeconds = parseRetryAfter(options.retryAfter) ?? (Number.isFinite(declared.recovery?.retryAfterSeconds) && declared.recovery.retryAfterSeconds >= 0 && declared.recovery.retryAfterSeconds <= 86400 ? declared.recovery.retryAfterSeconds : void 0);
|
|
168
|
+
let [message, action] = known[category];
|
|
169
|
+
message = publicText(declared.message) || message;
|
|
170
|
+
if (actions.has(declared.recovery?.action)) action = declared.recovery.action;
|
|
171
|
+
const fieldErrors = Array.isArray(declared.fieldErrors) && declared.fieldErrors.length ? declared.fieldErrors.slice(0, 20).filter((item) => /^[a-zA-Z0-9_.-]{1,150}$/.test(text(item?.path)) && publicText(item?.message)).map((item) => ({ path: item.path, message: item.message })) : validationFields(body);
|
|
172
|
+
if (fieldErrors.length) {
|
|
173
|
+
const fields = fieldErrors.slice(0, 3).map((field) => `${field.path.replace(/_/g, " ")}: ${field.message}`).join(" ");
|
|
174
|
+
message = `${fields}${fieldErrors.length > 3 ? " Check the remaining fields too." : ""}`;
|
|
175
|
+
action = "edit_input";
|
|
176
|
+
}
|
|
177
|
+
if (category === "platform.rate_limited" && retryAfterSeconds !== void 0 && !publicText(declared.message)) {
|
|
178
|
+
const unit = retryAfterSeconds >= 3600 ? "hour" : retryAfterSeconds >= 60 ? "minute" : "second";
|
|
179
|
+
const amount = Math.ceil(retryAfterSeconds / (unit === "hour" ? 3600 : unit === "minute" ? 60 : 1));
|
|
180
|
+
message = `This service is busy. Try again in ${amount} ${unit}${amount === 1 ? "" : "s"}.`;
|
|
181
|
+
}
|
|
182
|
+
const uncertain = !read && state === "unknown" && ["platform.network_error", "platform.service_unavailable", "platform.unexpected"].includes(category);
|
|
183
|
+
if (uncertain) {
|
|
184
|
+
const uncertainty = "We couldn't confirm whether your request completed. Check its status before trying again; contact support if you're unsure.";
|
|
185
|
+
const authored = publicText(declared.message);
|
|
186
|
+
message = authored ? authored.endsWith(uncertainty) ? authored : `${authored} ${uncertainty}` : uncertainty;
|
|
187
|
+
action = "view_status";
|
|
188
|
+
}
|
|
189
|
+
const operationLabel = publicText(options.operation);
|
|
190
|
+
if (operationLabel && !message.startsWith(`We couldn't ${operationLabel}.`)) message = `We couldn't ${operationLabel}. ${message}`;
|
|
191
|
+
const errorRef = reference(options.reference) || reference(declared.reference) || reference(error.errorRef) || reference(object(body.error).ref);
|
|
192
|
+
const safeToRetry = (read || declared.safeToRetry === true && ["not_started", "failed"].includes(state)) && ["wait", "retry"].includes(action);
|
|
193
|
+
return {
|
|
194
|
+
version: 1,
|
|
195
|
+
code,
|
|
196
|
+
message,
|
|
197
|
+
recovery: { action, ...retryAfterSeconds !== void 0 ? { retryAfterSeconds } : {} },
|
|
198
|
+
operation: { state, ...reference(object(declared.operation).id) ? { id: declared.operation.id } : {} },
|
|
199
|
+
safeToRetry,
|
|
200
|
+
fieldErrors,
|
|
201
|
+
...errorRef ? { reference: errorRef } : {}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
var UserFacingError = class extends Error {
|
|
205
|
+
constructor(failure, options = {}) {
|
|
206
|
+
const normalized = normalizeError(failure, options);
|
|
207
|
+
super(normalized.message, { cause: failure });
|
|
208
|
+
this.name = "UserFacingError";
|
|
209
|
+
this.publicError = normalized;
|
|
210
|
+
this.status = Number(options.status ?? object(failure).status) || 0;
|
|
211
|
+
this.statusCode = this.status;
|
|
212
|
+
this.method = (options.method || text(object(failure).method) || "UNKNOWN").toUpperCase();
|
|
213
|
+
this.code = normalized.code;
|
|
214
|
+
this.body = options.body ?? object(failure).body;
|
|
215
|
+
this.data = this.body;
|
|
216
|
+
this.errorRef = normalized.reference ?? null;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
function errorMessage(failure, options = {}) {
|
|
220
|
+
if (isCancellation(failure)) return "";
|
|
221
|
+
const normalized = normalizeError(failure, options);
|
|
222
|
+
return normalized.reference ? `${normalized.message} Reference: ${normalized.reference}` : normalized.message;
|
|
223
|
+
}
|
|
224
|
+
|
|
70
225
|
// src/managed-organization-summary.tsx
|
|
71
226
|
var import_icons = require("@streamoid/icons");
|
|
72
227
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -293,7 +448,13 @@ function SettingsAdaptersProvider({
|
|
|
293
448
|
adapters,
|
|
294
449
|
children
|
|
295
450
|
}) {
|
|
296
|
-
|
|
451
|
+
const value = (0, import_react2.useMemo)(() => {
|
|
452
|
+
const toast = quietErrorToast(adapters.toast);
|
|
453
|
+
return new Proxy(adapters, { get(target, key) {
|
|
454
|
+
return key === "toast" ? toast : Reflect.get(target, key);
|
|
455
|
+
} });
|
|
456
|
+
}, [adapters]);
|
|
457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SettingsAdaptersContext.Provider, { value, children });
|
|
297
458
|
}
|
|
298
459
|
function useSettingsAdapters() {
|
|
299
460
|
const ctx = (0, import_react2.useContext)(SettingsAdaptersContext);
|
|
@@ -2736,7 +2897,7 @@ function ToggleSwitch({
|
|
|
2736
2897
|
}
|
|
2737
2898
|
);
|
|
2738
2899
|
}
|
|
2739
|
-
function FieldLabel2({ text }) {
|
|
2900
|
+
function FieldLabel2({ text: text2 }) {
|
|
2740
2901
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2741
2902
|
"div",
|
|
2742
2903
|
{
|
|
@@ -2748,7 +2909,7 @@ function FieldLabel2({ text }) {
|
|
|
2748
2909
|
lineHeight: T6.lhSm,
|
|
2749
2910
|
color: T6.tertiary
|
|
2750
2911
|
},
|
|
2751
|
-
children:
|
|
2912
|
+
children: text2
|
|
2752
2913
|
}
|
|
2753
2914
|
) });
|
|
2754
2915
|
}
|
|
@@ -4789,7 +4950,7 @@ function TeamsContent({
|
|
|
4789
4950
|
toast.success("Invitation resent");
|
|
4790
4951
|
await fetchData();
|
|
4791
4952
|
} catch (err) {
|
|
4792
|
-
const msg = err
|
|
4953
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4793
4954
|
toast.error(msg);
|
|
4794
4955
|
}
|
|
4795
4956
|
closeModal();
|
|
@@ -4824,17 +4985,13 @@ function TeamsContent({
|
|
|
4824
4985
|
storeIds: permissions.catalogixStores || []
|
|
4825
4986
|
});
|
|
4826
4987
|
toast.success("User permissions updated");
|
|
4827
|
-
await fetchData();
|
|
4828
4988
|
} catch (err) {
|
|
4829
|
-
const msg = err
|
|
4989
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4830
4990
|
toast.error(msg);
|
|
4831
|
-
|
|
4832
|
-
(m) => m.id === modal.target?.id ? { ...m, permissions } : m
|
|
4833
|
-
);
|
|
4834
|
-
setActiveMembers(updateList);
|
|
4835
|
-
setPendingMembers(updateList);
|
|
4991
|
+
return;
|
|
4836
4992
|
}
|
|
4837
4993
|
closeModal();
|
|
4994
|
+
await fetchData();
|
|
4838
4995
|
};
|
|
4839
4996
|
const handleRemove = async () => {
|
|
4840
4997
|
if (!modal.target) {
|
|
@@ -4869,16 +5026,13 @@ function TeamsContent({
|
|
|
4869
5026
|
} else {
|
|
4870
5027
|
throw new Error("Unable to identify target to remove");
|
|
4871
5028
|
}
|
|
4872
|
-
await fetchData();
|
|
4873
5029
|
} catch (err) {
|
|
4874
|
-
const msg = err
|
|
5030
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4875
5031
|
toast.error(msg);
|
|
4876
|
-
|
|
4877
|
-
setPendingMembers(
|
|
4878
|
-
(prev) => prev.filter((m) => m.id !== modal.target?.id)
|
|
4879
|
-
);
|
|
5032
|
+
return;
|
|
4880
5033
|
}
|
|
4881
5034
|
closeModal();
|
|
5035
|
+
await fetchData();
|
|
4882
5036
|
};
|
|
4883
5037
|
const handleCancelPendingInvite = async (member) => {
|
|
4884
5038
|
if (member.kind !== "invite" || !member.invitationId) {
|
|
@@ -4904,7 +5058,7 @@ function TeamsContent({
|
|
|
4904
5058
|
toast.success("Invitation removed");
|
|
4905
5059
|
await fetchData();
|
|
4906
5060
|
} catch (err) {
|
|
4907
|
-
const msg = err
|
|
5061
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4908
5062
|
toast.error(msg);
|
|
4909
5063
|
}
|
|
4910
5064
|
};
|
|
@@ -4921,7 +5075,7 @@ function TeamsContent({
|
|
|
4921
5075
|
toast.success("Invitation resent");
|
|
4922
5076
|
await fetchData();
|
|
4923
5077
|
} catch (err) {
|
|
4924
|
-
const msg = err
|
|
5078
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4925
5079
|
toast.error(msg);
|
|
4926
5080
|
}
|
|
4927
5081
|
};
|
|
@@ -4950,7 +5104,7 @@ function TeamsContent({
|
|
|
4950
5104
|
await fetchData();
|
|
4951
5105
|
closeModal();
|
|
4952
5106
|
} catch (err) {
|
|
4953
|
-
const msg = err
|
|
5107
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4954
5108
|
toast.error(msg);
|
|
4955
5109
|
}
|
|
4956
5110
|
};
|
|
@@ -5166,7 +5320,7 @@ var T9 = {
|
|
|
5166
5320
|
r4xl: "var(--radius-4xl)",
|
|
5167
5321
|
neutral300: "var(--primitives-neutral-300)"
|
|
5168
5322
|
};
|
|
5169
|
-
function FieldLabel3({ text }) {
|
|
5323
|
+
function FieldLabel3({ text: text2 }) {
|
|
5170
5324
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5171
5325
|
"div",
|
|
5172
5326
|
{
|
|
@@ -5178,7 +5332,7 @@ function FieldLabel3({ text }) {
|
|
|
5178
5332
|
lineHeight: T9.lhSm,
|
|
5179
5333
|
color: T9.tertiary
|
|
5180
5334
|
},
|
|
5181
|
-
children:
|
|
5335
|
+
children: text2
|
|
5182
5336
|
}
|
|
5183
5337
|
) });
|
|
5184
5338
|
}
|
|
@@ -6313,7 +6467,8 @@ function OrganizationContent({
|
|
|
6313
6467
|
const current = organization.current;
|
|
6314
6468
|
const [members, setMembers] = (0, import_react12.useState)([]);
|
|
6315
6469
|
const [workspaces, setWorkspaces] = (0, import_react12.useState)([]);
|
|
6316
|
-
const
|
|
6470
|
+
const joinRole = current?.role === "admin" || current?.role === "member" ? current.role : null;
|
|
6471
|
+
const canJoin = !!joinRole && !!organization.joinWorkspaces;
|
|
6317
6472
|
const [joiningId, setJoiningId] = (0, import_react12.useState)(null);
|
|
6318
6473
|
const [joinRequests, setJoinRequests] = (0, import_react12.useState)([]);
|
|
6319
6474
|
const [highestRole, setHighestRole] = (0, import_react12.useState)("guest");
|
|
@@ -6355,9 +6510,7 @@ function OrganizationContent({
|
|
|
6355
6510
|
await workspaceAdapter.refresh?.().catch(() => void 0);
|
|
6356
6511
|
await fetchData();
|
|
6357
6512
|
} catch (err) {
|
|
6358
|
-
toast.error(
|
|
6359
|
-
err instanceof Error ? err.message : `Couldn't join ${target.name}`
|
|
6360
|
-
);
|
|
6513
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6361
6514
|
} finally {
|
|
6362
6515
|
setJoiningId(null);
|
|
6363
6516
|
}
|
|
@@ -6370,7 +6523,7 @@ function OrganizationContent({
|
|
|
6370
6523
|
toast.success("Organization updated");
|
|
6371
6524
|
return true;
|
|
6372
6525
|
} catch (err) {
|
|
6373
|
-
toast.error(err
|
|
6526
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6374
6527
|
return false;
|
|
6375
6528
|
}
|
|
6376
6529
|
};
|
|
@@ -6381,7 +6534,7 @@ function OrganizationContent({
|
|
|
6381
6534
|
toast.success("Organization deleted");
|
|
6382
6535
|
return true;
|
|
6383
6536
|
} catch (err) {
|
|
6384
|
-
toast.error(err
|
|
6537
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6385
6538
|
return false;
|
|
6386
6539
|
}
|
|
6387
6540
|
};
|
|
@@ -6413,7 +6566,7 @@ function OrganizationContent({
|
|
|
6413
6566
|
toast.success("Member updated");
|
|
6414
6567
|
await fetchData();
|
|
6415
6568
|
} catch (err) {
|
|
6416
|
-
toast.error(err
|
|
6569
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6417
6570
|
}
|
|
6418
6571
|
closeModal();
|
|
6419
6572
|
};
|
|
@@ -6443,7 +6596,7 @@ function OrganizationContent({
|
|
|
6443
6596
|
toast.success("Member removed");
|
|
6444
6597
|
await fetchData();
|
|
6445
6598
|
} catch (err) {
|
|
6446
|
-
toast.error(err
|
|
6599
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6447
6600
|
}
|
|
6448
6601
|
closeModal();
|
|
6449
6602
|
};
|
|
@@ -6455,7 +6608,7 @@ function OrganizationContent({
|
|
|
6455
6608
|
);
|
|
6456
6609
|
await fetchData();
|
|
6457
6610
|
} catch (err) {
|
|
6458
|
-
toast.error(err
|
|
6611
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6459
6612
|
}
|
|
6460
6613
|
};
|
|
6461
6614
|
const handleRejectJoinRequest = async (request) => {
|
|
@@ -6464,7 +6617,7 @@ function OrganizationContent({
|
|
|
6464
6617
|
toast.success("Request rejected");
|
|
6465
6618
|
await fetchData();
|
|
6466
6619
|
} catch (err) {
|
|
6467
|
-
toast.error(err
|
|
6620
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6468
6621
|
}
|
|
6469
6622
|
};
|
|
6470
6623
|
if (!current) {
|
|
@@ -6592,7 +6745,7 @@ function OrganizationContent({
|
|
|
6592
6745
|
{
|
|
6593
6746
|
workspace: ws,
|
|
6594
6747
|
joining: joiningId === ws._id,
|
|
6595
|
-
onJoin:
|
|
6748
|
+
onJoin: canJoin && ws.joined === false && ws.status !== "inactive" && (joinRole === "admin" || ws.orgVisibility === "shared") ? () => void handleJoinWorkspace(ws) : void 0
|
|
6596
6749
|
},
|
|
6597
6750
|
ws._id
|
|
6598
6751
|
))
|
|
@@ -6694,6 +6847,21 @@ function OrganizationContent({
|
|
|
6694
6847
|
) });
|
|
6695
6848
|
}
|
|
6696
6849
|
|
|
6850
|
+
// src/billing-errors.ts
|
|
6851
|
+
function isBillingWorkspaceMissing(failure) {
|
|
6852
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6853
|
+
const visit = (value, depth) => {
|
|
6854
|
+
if (depth > 4 || value == null || seen.has(value)) return false;
|
|
6855
|
+
if (typeof value === "string") return /workspace.*not found/i.test(value);
|
|
6856
|
+
if (typeof value !== "object") return false;
|
|
6857
|
+
seen.add(value);
|
|
6858
|
+
const error = value;
|
|
6859
|
+
if (error.code === "billing.workspace_not_found") return true;
|
|
6860
|
+
return [error.message, error.error, error.data, error.body, error.cause, error.publicError].some((child) => visit(child, depth + 1));
|
|
6861
|
+
};
|
|
6862
|
+
return visit(failure, 0);
|
|
6863
|
+
}
|
|
6864
|
+
|
|
6697
6865
|
// src/billing-content.tsx
|
|
6698
6866
|
var import_react15 = require("react");
|
|
6699
6867
|
var import_ui9 = require("@streamoid/ui");
|
|
@@ -8836,8 +9004,8 @@ function BillingContent({
|
|
|
8836
9004
|
toast.success("Plan update submitted");
|
|
8837
9005
|
await fetchBillingOverview();
|
|
8838
9006
|
} catch (err) {
|
|
8839
|
-
const message = err
|
|
8840
|
-
const shouldCreateWorkspace =
|
|
9007
|
+
const message = errorMessage(err, { method: "POST" });
|
|
9008
|
+
const shouldCreateWorkspace = isBillingWorkspaceMissing(err);
|
|
8841
9009
|
if (shouldCreateWorkspace) {
|
|
8842
9010
|
const created = await ensureWorkspaceOnBilling();
|
|
8843
9011
|
if (created && api.updateSubscription) {
|
|
@@ -8890,7 +9058,7 @@ function BillingContent({
|
|
|
8890
9058
|
toast.error("Unable to cancel downgrade");
|
|
8891
9059
|
}
|
|
8892
9060
|
} catch (err) {
|
|
8893
|
-
const msg = err
|
|
9061
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
8894
9062
|
toast.error(msg);
|
|
8895
9063
|
} finally {
|
|
8896
9064
|
setPlanActionInFlight(null);
|
|
@@ -9081,7 +9249,7 @@ function BillingContent({
|
|
|
9081
9249
|
setShowBuyCreditsModal(false);
|
|
9082
9250
|
await fetchBillingOverview();
|
|
9083
9251
|
} catch (err) {
|
|
9084
|
-
const message = err
|
|
9252
|
+
const message = errorMessage(err, { method: "POST" });
|
|
9085
9253
|
toast.error(message);
|
|
9086
9254
|
} finally {
|
|
9087
9255
|
setBuyCreditsInFlight(false);
|
|
@@ -9412,7 +9580,7 @@ function CreateTokenModal({ onClose, onCreated }) {
|
|
|
9412
9580
|
const data = await api.createToken({ name: name.trim(), expiry });
|
|
9413
9581
|
onCreated(data);
|
|
9414
9582
|
} catch (err) {
|
|
9415
|
-
toast.error(err
|
|
9583
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9416
9584
|
} finally {
|
|
9417
9585
|
setLoading(false);
|
|
9418
9586
|
}
|
|
@@ -9767,7 +9935,7 @@ function TokensContent({
|
|
|
9767
9935
|
setTokens((prev) => prev.filter((t) => t._id !== tokenId));
|
|
9768
9936
|
}
|
|
9769
9937
|
} catch (err) {
|
|
9770
|
-
toast.error(err
|
|
9938
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9771
9939
|
} finally {
|
|
9772
9940
|
setDeletingId(null);
|
|
9773
9941
|
}
|
|
@@ -9779,7 +9947,7 @@ function TokensContent({
|
|
|
9779
9947
|
toast.success("Token permanently deleted.");
|
|
9780
9948
|
setTokens((prev) => prev.filter((t) => t._id !== tokenId));
|
|
9781
9949
|
} catch (err) {
|
|
9782
|
-
toast.error(err
|
|
9950
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9783
9951
|
} finally {
|
|
9784
9952
|
setDeletingId(null);
|
|
9785
9953
|
}
|
|
@@ -10617,7 +10785,7 @@ function ProfileTab() {
|
|
|
10617
10785
|
await auth.refreshProfile();
|
|
10618
10786
|
toast.success("Profile updated");
|
|
10619
10787
|
} catch (err) {
|
|
10620
|
-
const msg = err
|
|
10788
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10621
10789
|
toast.error(msg);
|
|
10622
10790
|
} finally {
|
|
10623
10791
|
setSaving(false);
|
|
@@ -10650,7 +10818,7 @@ function ProfileTab() {
|
|
|
10650
10818
|
toast.success("Profile image updated");
|
|
10651
10819
|
} catch (err) {
|
|
10652
10820
|
setImagePreview(void 0);
|
|
10653
|
-
const msg = err
|
|
10821
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10654
10822
|
toast.error(msg);
|
|
10655
10823
|
} finally {
|
|
10656
10824
|
URL.revokeObjectURL(localPreviewUrl);
|
|
@@ -10670,7 +10838,7 @@ function ProfileTab() {
|
|
|
10670
10838
|
await auth.refreshProfile();
|
|
10671
10839
|
toast.success("Profile image removed");
|
|
10672
10840
|
} catch (err) {
|
|
10673
|
-
const msg = err
|
|
10841
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10674
10842
|
toast.error(msg);
|
|
10675
10843
|
} finally {
|
|
10676
10844
|
setImageSaving(false);
|
|
@@ -10961,9 +11129,9 @@ function groupWorkspaceList(workspaces, organizations = []) {
|
|
|
10961
11129
|
});
|
|
10962
11130
|
}
|
|
10963
11131
|
}
|
|
10964
|
-
const
|
|
11132
|
+
const known2 = new Set(organizations.map((org) => org._id));
|
|
10965
11133
|
const ungrouped = workspaces.filter(
|
|
10966
|
-
(ws) => !ws.organizationId || !
|
|
11134
|
+
(ws) => !ws.organizationId || !known2.has(ws.organizationId)
|
|
10967
11135
|
);
|
|
10968
11136
|
if (ungrouped.length) {
|
|
10969
11137
|
groups.push({
|
|
@@ -11514,17 +11682,6 @@ function SettingsContentInner({
|
|
|
11514
11682
|
imageRemoved
|
|
11515
11683
|
});
|
|
11516
11684
|
};
|
|
11517
|
-
const getErrorMessage = (err, fallback) => {
|
|
11518
|
-
if (err instanceof Error && err.message.trim()) return err.message;
|
|
11519
|
-
if (err && typeof err === "object" && "body" in err && err.body && typeof err.body === "object" && "status" in err.body && err.body.status && typeof err.body.status === "object" && "message" in err.body.status && typeof err.body.status.message === "string") {
|
|
11520
|
-
return err.body.status.message;
|
|
11521
|
-
}
|
|
11522
|
-
return fallback;
|
|
11523
|
-
};
|
|
11524
|
-
const isSingleAdminError = (message) => {
|
|
11525
|
-
const normalized = message.toLowerCase();
|
|
11526
|
-
return normalized.includes("single admin") || normalized.includes("only admin");
|
|
11527
|
-
};
|
|
11528
11685
|
const getSettingsPath = (nextWorkspaceId) => `/dashboard/${nextWorkspaceId}/settings`;
|
|
11529
11686
|
const getNextWorkspaceId = async (excludedWorkspaceId) => {
|
|
11530
11687
|
try {
|
|
@@ -11608,7 +11765,7 @@ function SettingsContentInner({
|
|
|
11608
11765
|
toast.success("Workspace updated");
|
|
11609
11766
|
return true;
|
|
11610
11767
|
} catch (err) {
|
|
11611
|
-
toast.error(
|
|
11768
|
+
toast.error(errorMessage(err, { method: "PATCH" }));
|
|
11612
11769
|
return false;
|
|
11613
11770
|
} finally {
|
|
11614
11771
|
setUpdatingWorkspace(false);
|
|
@@ -11676,7 +11833,7 @@ function SettingsContentInner({
|
|
|
11676
11833
|
toast.success("Workspace created");
|
|
11677
11834
|
return true;
|
|
11678
11835
|
} catch (err) {
|
|
11679
|
-
const msg = err
|
|
11836
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
11680
11837
|
toast.error(msg);
|
|
11681
11838
|
return false;
|
|
11682
11839
|
} finally {
|
|
@@ -11723,7 +11880,7 @@ function SettingsContentInner({
|
|
|
11723
11880
|
toast.success("Workspace updated");
|
|
11724
11881
|
return true;
|
|
11725
11882
|
} catch (err) {
|
|
11726
|
-
const msg = err
|
|
11883
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
11727
11884
|
toast.error(msg);
|
|
11728
11885
|
return false;
|
|
11729
11886
|
} finally {
|
|
@@ -12199,11 +12356,10 @@ function SettingsContentInner({
|
|
|
12199
12356
|
setLeavingWorkspace(null);
|
|
12200
12357
|
await completeWorkspaceRemoval(wsId, `You left ${wsName}`);
|
|
12201
12358
|
} catch (err) {
|
|
12202
|
-
|
|
12203
|
-
if (isSingleAdminError(message)) {
|
|
12359
|
+
if (isOnlyWorkspaceAdmin(err)) {
|
|
12204
12360
|
toast.error("You are the only admin. Promote another admin before leaving.");
|
|
12205
12361
|
} else {
|
|
12206
|
-
toast.error(
|
|
12362
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
12207
12363
|
}
|
|
12208
12364
|
}
|
|
12209
12365
|
},
|
|
@@ -12233,7 +12389,7 @@ function SettingsContentInner({
|
|
|
12233
12389
|
setDeletingWorkspace(null);
|
|
12234
12390
|
await completeWorkspaceRemoval(wsId, `Workspace ${wsName} deleted`);
|
|
12235
12391
|
} catch (err) {
|
|
12236
|
-
toast.error(
|
|
12392
|
+
toast.error(errorMessage(err, { method: "DELETE" }));
|
|
12237
12393
|
}
|
|
12238
12394
|
}
|
|
12239
12395
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,158 @@
|
|
|
1
|
+
// src/settings-errors.ts
|
|
2
|
+
function quietErrorToast(toast) {
|
|
3
|
+
return { ...toast, error(message) {
|
|
4
|
+
if (message.trim()) toast.error(message);
|
|
5
|
+
} };
|
|
6
|
+
}
|
|
7
|
+
function isOnlyWorkspaceAdmin(failure) {
|
|
8
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9
|
+
const visit = (value, depth) => {
|
|
10
|
+
if (depth > 4 || value == null || seen.has(value)) return false;
|
|
11
|
+
if (typeof value === "string") return /single admin|only admin/i.test(value);
|
|
12
|
+
if (typeof value !== "object") return false;
|
|
13
|
+
seen.add(value);
|
|
14
|
+
const error = value;
|
|
15
|
+
return [error.body, error.data, error.status, error.message, error.error, error.cause].some((child) => visit(child, depth + 1));
|
|
16
|
+
};
|
|
17
|
+
return visit(failure, 0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ../errors/index.js
|
|
21
|
+
var actions = /* @__PURE__ */ new Set(["edit_input", "sign_in", "ask_admin", "wait", "view_status", "retry", "contact_support"]);
|
|
22
|
+
var states = /* @__PURE__ */ new Set(["not_started", "failed", "partial", "in_progress", "unknown"]);
|
|
23
|
+
var isObject = (value) => value !== null && typeof value === "object";
|
|
24
|
+
var object = (value) => isObject(value) ? value : {};
|
|
25
|
+
var text = (value) => typeof value === "string" ? value : "";
|
|
26
|
+
var reference = (value) => /^[a-zA-Z0-9][a-zA-Z0-9_-]{5,127}$/.test(text(value)) ? value : void 0;
|
|
27
|
+
var technical = /https?:\/\/|<[^>]+>|\b(?:TypeError|SyntaxError|ReferenceError|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|Traceback|SQLSTATE|MongoServerError|localhost|undefined|null|NaN|CORS|stack trace|Xvfb|node:sqlite)\b|(?:\/[^\s/]+){3,}|\bat\s+\w+\s*\(/i;
|
|
28
|
+
var publicText = (value) => {
|
|
29
|
+
const s = text(value).trim();
|
|
30
|
+
return s && s.length <= 500 && !technical.test(s) && !/[\r\n{}]/.test(s) ? s : void 0;
|
|
31
|
+
};
|
|
32
|
+
var isCancellation = (error) => object(error).name === "AbortError";
|
|
33
|
+
function parseRetryAfter(value, now = Date.now()) {
|
|
34
|
+
if (!text(value).trim()) return void 0;
|
|
35
|
+
const seconds = /^\d+$/.test(value.trim()) ? Number(value) : Math.ceil((Date.parse(value) - now) / 1e3);
|
|
36
|
+
return Number.isFinite(seconds) && seconds >= 0 && seconds <= 86400 ? seconds : void 0;
|
|
37
|
+
}
|
|
38
|
+
function validationFields(body) {
|
|
39
|
+
if (!Array.isArray(body.detail)) return [];
|
|
40
|
+
return body.detail.slice(0, 20).flatMap((issue) => {
|
|
41
|
+
if (!isObject(issue) || !Array.isArray(issue.loc)) return [];
|
|
42
|
+
const path = issue.loc.filter((part) => part !== "body" && part !== "query").filter((part) => typeof part === "string" || typeof part === "number").join(".");
|
|
43
|
+
if (!/^[a-zA-Z0-9_.-]{1,150}$/.test(path)) return [];
|
|
44
|
+
return [{ path, message: issue.type === "missing" || issue.type === "value_error.missing" ? "This field is required." : "Check this value and try again." }];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
var known = {
|
|
48
|
+
"platform.session_expired": ["Your session has expired. Sign in to continue.", "sign_in"],
|
|
49
|
+
"platform.permission_denied": ["You don't have permission to do this. Ask a workspace admin for access.", "ask_admin"],
|
|
50
|
+
"platform.insufficient_credits": ["There aren't enough credits for this action. Ask your billing admin to add credits.", "ask_admin"],
|
|
51
|
+
"platform.invalid_input": ["Check the information you entered and correct any highlighted fields.", "edit_input"],
|
|
52
|
+
"platform.not_found": ["This item is no longer available or you don't have access to it. Check that you've opened the correct workspace.", "view_status"],
|
|
53
|
+
"platform.conflict": ["This item has changed or already exists. Check its current state before continuing.", "view_status"],
|
|
54
|
+
"platform.file_too_large": ["This file is too large. Choose a smaller file and try again.", "edit_input"],
|
|
55
|
+
"platform.unsupported_file": ["This file type isn't supported. Choose one of the accepted file types.", "edit_input"],
|
|
56
|
+
"platform.content_rejected": ["This request couldn't be completed with the current input. Review the image or description and try again.", "edit_input"],
|
|
57
|
+
"platform.rate_limited": ["This service is busy. Wait a moment before trying again.", "wait"],
|
|
58
|
+
"platform.service_unavailable": ["A service is temporarily unavailable. Try again shortly; contact support if it keeps happening.", "wait"],
|
|
59
|
+
"platform.setup_required": ["There's a setup problem on our side. Contact support so we can help.", "contact_support"],
|
|
60
|
+
"platform.network_error": ["We couldn't reach the service. Check your connection and try again shortly.", "retry"],
|
|
61
|
+
"platform.unexpected": ["We couldn't complete this action. Contact support if it keeps happening.", "contact_support"]
|
|
62
|
+
};
|
|
63
|
+
function inferCode(status, rawCode, diagnostic) {
|
|
64
|
+
if (Object.hasOwn(known, rawCode)) return rawCode;
|
|
65
|
+
const signal = `${rawCode} ${diagnostic}`;
|
|
66
|
+
if (/insufficient.?credits|credits.?unavailable|insufficient.?balance/i.test(signal)) return "platform.insufficient_credits";
|
|
67
|
+
if (/content.?policy|safety.?block|content.?reject/i.test(signal)) return "platform.content_rejected";
|
|
68
|
+
if (/rate.?limit|capacity.?limit/i.test(signal)) return "platform.rate_limited";
|
|
69
|
+
if (status === 401) return "platform.session_expired";
|
|
70
|
+
if (status === 402) return "platform.insufficient_credits";
|
|
71
|
+
if (status === 403) return "platform.permission_denied";
|
|
72
|
+
if (status === 404 || status === 410) return "platform.not_found";
|
|
73
|
+
if (status === 409 || status === 412) return "platform.conflict";
|
|
74
|
+
if (status === 413) return "platform.file_too_large";
|
|
75
|
+
if (status === 415) return "platform.unsupported_file";
|
|
76
|
+
if (status === 429) return "platform.rate_limited";
|
|
77
|
+
if (status === 400 || status === 422) return "platform.invalid_input";
|
|
78
|
+
if ([408, 502, 503, 504].includes(status)) return "platform.service_unavailable";
|
|
79
|
+
if (/ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|server misbehaving|upstream unavailable/i.test(signal)) return "platform.service_unavailable";
|
|
80
|
+
if (/failed to fetch|networkerror|network request failed|load failed/i.test(signal)) return "platform.network_error";
|
|
81
|
+
return "platform.unexpected";
|
|
82
|
+
}
|
|
83
|
+
function normalizeError(failure, options = {}) {
|
|
84
|
+
if (failure instanceof UserFacingError && Object.keys(options).length === 0) return failure.publicError;
|
|
85
|
+
const error = object(failure);
|
|
86
|
+
const body = object(options.body ?? error.body ?? error.data ?? failure);
|
|
87
|
+
const envelope = object(body.publicError ?? error.publicError);
|
|
88
|
+
const declared = envelope.version === 1 ? envelope : {};
|
|
89
|
+
const status = Number(options.status ?? error.statusCode ?? (typeof error.status === "number" ? error.status : void 0)) || 0;
|
|
90
|
+
const diagnostic = [text(error.message), text(failure), text(body.detail), text(body.error)].filter(Boolean).join(" ");
|
|
91
|
+
const rawCode = text(declared.code) || text(object(body.error).code) || text(body.code) || text(error.code);
|
|
92
|
+
const category = inferCode(status, rawCode, diagnostic);
|
|
93
|
+
const code = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/.test(text(declared.code)) ? declared.code : category;
|
|
94
|
+
const method = (options.method || text(error.method) || "UNKNOWN").toUpperCase();
|
|
95
|
+
const read = ["GET", "HEAD", "OPTIONS"].includes(method);
|
|
96
|
+
const suppliedState = object(declared.operation).state;
|
|
97
|
+
const state = states.has(suppliedState) ? suppliedState : read ? "failed" : "unknown";
|
|
98
|
+
const retryAfterSeconds = parseRetryAfter(options.retryAfter) ?? (Number.isFinite(declared.recovery?.retryAfterSeconds) && declared.recovery.retryAfterSeconds >= 0 && declared.recovery.retryAfterSeconds <= 86400 ? declared.recovery.retryAfterSeconds : void 0);
|
|
99
|
+
let [message, action] = known[category];
|
|
100
|
+
message = publicText(declared.message) || message;
|
|
101
|
+
if (actions.has(declared.recovery?.action)) action = declared.recovery.action;
|
|
102
|
+
const fieldErrors = Array.isArray(declared.fieldErrors) && declared.fieldErrors.length ? declared.fieldErrors.slice(0, 20).filter((item) => /^[a-zA-Z0-9_.-]{1,150}$/.test(text(item?.path)) && publicText(item?.message)).map((item) => ({ path: item.path, message: item.message })) : validationFields(body);
|
|
103
|
+
if (fieldErrors.length) {
|
|
104
|
+
const fields = fieldErrors.slice(0, 3).map((field) => `${field.path.replace(/_/g, " ")}: ${field.message}`).join(" ");
|
|
105
|
+
message = `${fields}${fieldErrors.length > 3 ? " Check the remaining fields too." : ""}`;
|
|
106
|
+
action = "edit_input";
|
|
107
|
+
}
|
|
108
|
+
if (category === "platform.rate_limited" && retryAfterSeconds !== void 0 && !publicText(declared.message)) {
|
|
109
|
+
const unit = retryAfterSeconds >= 3600 ? "hour" : retryAfterSeconds >= 60 ? "minute" : "second";
|
|
110
|
+
const amount = Math.ceil(retryAfterSeconds / (unit === "hour" ? 3600 : unit === "minute" ? 60 : 1));
|
|
111
|
+
message = `This service is busy. Try again in ${amount} ${unit}${amount === 1 ? "" : "s"}.`;
|
|
112
|
+
}
|
|
113
|
+
const uncertain = !read && state === "unknown" && ["platform.network_error", "platform.service_unavailable", "platform.unexpected"].includes(category);
|
|
114
|
+
if (uncertain) {
|
|
115
|
+
const uncertainty = "We couldn't confirm whether your request completed. Check its status before trying again; contact support if you're unsure.";
|
|
116
|
+
const authored = publicText(declared.message);
|
|
117
|
+
message = authored ? authored.endsWith(uncertainty) ? authored : `${authored} ${uncertainty}` : uncertainty;
|
|
118
|
+
action = "view_status";
|
|
119
|
+
}
|
|
120
|
+
const operationLabel = publicText(options.operation);
|
|
121
|
+
if (operationLabel && !message.startsWith(`We couldn't ${operationLabel}.`)) message = `We couldn't ${operationLabel}. ${message}`;
|
|
122
|
+
const errorRef = reference(options.reference) || reference(declared.reference) || reference(error.errorRef) || reference(object(body.error).ref);
|
|
123
|
+
const safeToRetry = (read || declared.safeToRetry === true && ["not_started", "failed"].includes(state)) && ["wait", "retry"].includes(action);
|
|
124
|
+
return {
|
|
125
|
+
version: 1,
|
|
126
|
+
code,
|
|
127
|
+
message,
|
|
128
|
+
recovery: { action, ...retryAfterSeconds !== void 0 ? { retryAfterSeconds } : {} },
|
|
129
|
+
operation: { state, ...reference(object(declared.operation).id) ? { id: declared.operation.id } : {} },
|
|
130
|
+
safeToRetry,
|
|
131
|
+
fieldErrors,
|
|
132
|
+
...errorRef ? { reference: errorRef } : {}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
var UserFacingError = class extends Error {
|
|
136
|
+
constructor(failure, options = {}) {
|
|
137
|
+
const normalized = normalizeError(failure, options);
|
|
138
|
+
super(normalized.message, { cause: failure });
|
|
139
|
+
this.name = "UserFacingError";
|
|
140
|
+
this.publicError = normalized;
|
|
141
|
+
this.status = Number(options.status ?? object(failure).status) || 0;
|
|
142
|
+
this.statusCode = this.status;
|
|
143
|
+
this.method = (options.method || text(object(failure).method) || "UNKNOWN").toUpperCase();
|
|
144
|
+
this.code = normalized.code;
|
|
145
|
+
this.body = options.body ?? object(failure).body;
|
|
146
|
+
this.data = this.body;
|
|
147
|
+
this.errorRef = normalized.reference ?? null;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
function errorMessage(failure, options = {}) {
|
|
151
|
+
if (isCancellation(failure)) return "";
|
|
152
|
+
const normalized = normalizeError(failure, options);
|
|
153
|
+
return normalized.reference ? `${normalized.message} Reference: ${normalized.reference}` : normalized.message;
|
|
154
|
+
}
|
|
155
|
+
|
|
1
156
|
// src/managed-organization-summary.tsx
|
|
2
157
|
import { SiconExternalLink } from "@streamoid/icons";
|
|
3
158
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -168,7 +323,7 @@ import {
|
|
|
168
323
|
useEffect as useEffect13,
|
|
169
324
|
useRef as useRef7,
|
|
170
325
|
useCallback as useCallback7,
|
|
171
|
-
useMemo as
|
|
326
|
+
useMemo as useMemo4
|
|
172
327
|
} from "react";
|
|
173
328
|
import {
|
|
174
329
|
ScSidebarMenu,
|
|
@@ -249,14 +404,20 @@ function userLanguageLabel(code) {
|
|
|
249
404
|
import { useState as useState2, useRef as useRef2, useEffect as useEffect3 } from "react";
|
|
250
405
|
|
|
251
406
|
// src/settings-adapters-context.tsx
|
|
252
|
-
import { createContext, useContext } from "react";
|
|
407
|
+
import { createContext, useContext, useMemo } from "react";
|
|
253
408
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
254
409
|
var SettingsAdaptersContext = createContext(null);
|
|
255
410
|
function SettingsAdaptersProvider({
|
|
256
411
|
adapters,
|
|
257
412
|
children
|
|
258
413
|
}) {
|
|
259
|
-
|
|
414
|
+
const value = useMemo(() => {
|
|
415
|
+
const toast = quietErrorToast(adapters.toast);
|
|
416
|
+
return new Proxy(adapters, { get(target, key) {
|
|
417
|
+
return key === "toast" ? toast : Reflect.get(target, key);
|
|
418
|
+
} });
|
|
419
|
+
}, [adapters]);
|
|
420
|
+
return /* @__PURE__ */ jsx4(SettingsAdaptersContext.Provider, { value, children });
|
|
260
421
|
}
|
|
261
422
|
function useSettingsAdapters() {
|
|
262
423
|
const ctx = useContext(SettingsAdaptersContext);
|
|
@@ -2713,7 +2874,7 @@ function ToggleSwitch({
|
|
|
2713
2874
|
}
|
|
2714
2875
|
);
|
|
2715
2876
|
}
|
|
2716
|
-
function FieldLabel2({ text }) {
|
|
2877
|
+
function FieldLabel2({ text: text2 }) {
|
|
2717
2878
|
return /* @__PURE__ */ jsx12("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ jsx12(
|
|
2718
2879
|
"div",
|
|
2719
2880
|
{
|
|
@@ -2725,7 +2886,7 @@ function FieldLabel2({ text }) {
|
|
|
2725
2886
|
lineHeight: T6.lhSm,
|
|
2726
2887
|
color: T6.tertiary
|
|
2727
2888
|
},
|
|
2728
|
-
children:
|
|
2889
|
+
children: text2
|
|
2729
2890
|
}
|
|
2730
2891
|
) });
|
|
2731
2892
|
}
|
|
@@ -4766,7 +4927,7 @@ function TeamsContent({
|
|
|
4766
4927
|
toast.success("Invitation resent");
|
|
4767
4928
|
await fetchData();
|
|
4768
4929
|
} catch (err) {
|
|
4769
|
-
const msg = err
|
|
4930
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4770
4931
|
toast.error(msg);
|
|
4771
4932
|
}
|
|
4772
4933
|
closeModal();
|
|
@@ -4801,17 +4962,13 @@ function TeamsContent({
|
|
|
4801
4962
|
storeIds: permissions.catalogixStores || []
|
|
4802
4963
|
});
|
|
4803
4964
|
toast.success("User permissions updated");
|
|
4804
|
-
await fetchData();
|
|
4805
4965
|
} catch (err) {
|
|
4806
|
-
const msg = err
|
|
4966
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4807
4967
|
toast.error(msg);
|
|
4808
|
-
|
|
4809
|
-
(m) => m.id === modal.target?.id ? { ...m, permissions } : m
|
|
4810
|
-
);
|
|
4811
|
-
setActiveMembers(updateList);
|
|
4812
|
-
setPendingMembers(updateList);
|
|
4968
|
+
return;
|
|
4813
4969
|
}
|
|
4814
4970
|
closeModal();
|
|
4971
|
+
await fetchData();
|
|
4815
4972
|
};
|
|
4816
4973
|
const handleRemove = async () => {
|
|
4817
4974
|
if (!modal.target) {
|
|
@@ -4846,16 +5003,13 @@ function TeamsContent({
|
|
|
4846
5003
|
} else {
|
|
4847
5004
|
throw new Error("Unable to identify target to remove");
|
|
4848
5005
|
}
|
|
4849
|
-
await fetchData();
|
|
4850
5006
|
} catch (err) {
|
|
4851
|
-
const msg = err
|
|
5007
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4852
5008
|
toast.error(msg);
|
|
4853
|
-
|
|
4854
|
-
setPendingMembers(
|
|
4855
|
-
(prev) => prev.filter((m) => m.id !== modal.target?.id)
|
|
4856
|
-
);
|
|
5009
|
+
return;
|
|
4857
5010
|
}
|
|
4858
5011
|
closeModal();
|
|
5012
|
+
await fetchData();
|
|
4859
5013
|
};
|
|
4860
5014
|
const handleCancelPendingInvite = async (member) => {
|
|
4861
5015
|
if (member.kind !== "invite" || !member.invitationId) {
|
|
@@ -4881,7 +5035,7 @@ function TeamsContent({
|
|
|
4881
5035
|
toast.success("Invitation removed");
|
|
4882
5036
|
await fetchData();
|
|
4883
5037
|
} catch (err) {
|
|
4884
|
-
const msg = err
|
|
5038
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4885
5039
|
toast.error(msg);
|
|
4886
5040
|
}
|
|
4887
5041
|
};
|
|
@@ -4898,7 +5052,7 @@ function TeamsContent({
|
|
|
4898
5052
|
toast.success("Invitation resent");
|
|
4899
5053
|
await fetchData();
|
|
4900
5054
|
} catch (err) {
|
|
4901
|
-
const msg = err
|
|
5055
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4902
5056
|
toast.error(msg);
|
|
4903
5057
|
}
|
|
4904
5058
|
};
|
|
@@ -4927,7 +5081,7 @@ function TeamsContent({
|
|
|
4927
5081
|
await fetchData();
|
|
4928
5082
|
closeModal();
|
|
4929
5083
|
} catch (err) {
|
|
4930
|
-
const msg = err
|
|
5084
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
4931
5085
|
toast.error(msg);
|
|
4932
5086
|
}
|
|
4933
5087
|
};
|
|
@@ -5143,7 +5297,7 @@ var T9 = {
|
|
|
5143
5297
|
r4xl: "var(--radius-4xl)",
|
|
5144
5298
|
neutral300: "var(--primitives-neutral-300)"
|
|
5145
5299
|
};
|
|
5146
|
-
function FieldLabel3({ text }) {
|
|
5300
|
+
function FieldLabel3({ text: text2 }) {
|
|
5147
5301
|
return /* @__PURE__ */ jsx15("div", { className: "flex items-center shrink-0 w-full", style: { height: 24 }, children: /* @__PURE__ */ jsx15(
|
|
5148
5302
|
"div",
|
|
5149
5303
|
{
|
|
@@ -5155,7 +5309,7 @@ function FieldLabel3({ text }) {
|
|
|
5155
5309
|
lineHeight: T9.lhSm,
|
|
5156
5310
|
color: T9.tertiary
|
|
5157
5311
|
},
|
|
5158
|
-
children:
|
|
5312
|
+
children: text2
|
|
5159
5313
|
}
|
|
5160
5314
|
) });
|
|
5161
5315
|
}
|
|
@@ -6290,7 +6444,8 @@ function OrganizationContent({
|
|
|
6290
6444
|
const current = organization.current;
|
|
6291
6445
|
const [members, setMembers] = useState10([]);
|
|
6292
6446
|
const [workspaces, setWorkspaces] = useState10([]);
|
|
6293
|
-
const
|
|
6447
|
+
const joinRole = current?.role === "admin" || current?.role === "member" ? current.role : null;
|
|
6448
|
+
const canJoin = !!joinRole && !!organization.joinWorkspaces;
|
|
6294
6449
|
const [joiningId, setJoiningId] = useState10(null);
|
|
6295
6450
|
const [joinRequests, setJoinRequests] = useState10([]);
|
|
6296
6451
|
const [highestRole, setHighestRole] = useState10("guest");
|
|
@@ -6332,9 +6487,7 @@ function OrganizationContent({
|
|
|
6332
6487
|
await workspaceAdapter.refresh?.().catch(() => void 0);
|
|
6333
6488
|
await fetchData();
|
|
6334
6489
|
} catch (err) {
|
|
6335
|
-
toast.error(
|
|
6336
|
-
err instanceof Error ? err.message : `Couldn't join ${target.name}`
|
|
6337
|
-
);
|
|
6490
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6338
6491
|
} finally {
|
|
6339
6492
|
setJoiningId(null);
|
|
6340
6493
|
}
|
|
@@ -6347,7 +6500,7 @@ function OrganizationContent({
|
|
|
6347
6500
|
toast.success("Organization updated");
|
|
6348
6501
|
return true;
|
|
6349
6502
|
} catch (err) {
|
|
6350
|
-
toast.error(err
|
|
6503
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6351
6504
|
return false;
|
|
6352
6505
|
}
|
|
6353
6506
|
};
|
|
@@ -6358,7 +6511,7 @@ function OrganizationContent({
|
|
|
6358
6511
|
toast.success("Organization deleted");
|
|
6359
6512
|
return true;
|
|
6360
6513
|
} catch (err) {
|
|
6361
|
-
toast.error(err
|
|
6514
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6362
6515
|
return false;
|
|
6363
6516
|
}
|
|
6364
6517
|
};
|
|
@@ -6390,7 +6543,7 @@ function OrganizationContent({
|
|
|
6390
6543
|
toast.success("Member updated");
|
|
6391
6544
|
await fetchData();
|
|
6392
6545
|
} catch (err) {
|
|
6393
|
-
toast.error(err
|
|
6546
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6394
6547
|
}
|
|
6395
6548
|
closeModal();
|
|
6396
6549
|
};
|
|
@@ -6420,7 +6573,7 @@ function OrganizationContent({
|
|
|
6420
6573
|
toast.success("Member removed");
|
|
6421
6574
|
await fetchData();
|
|
6422
6575
|
} catch (err) {
|
|
6423
|
-
toast.error(err
|
|
6576
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6424
6577
|
}
|
|
6425
6578
|
closeModal();
|
|
6426
6579
|
};
|
|
@@ -6432,7 +6585,7 @@ function OrganizationContent({
|
|
|
6432
6585
|
);
|
|
6433
6586
|
await fetchData();
|
|
6434
6587
|
} catch (err) {
|
|
6435
|
-
toast.error(err
|
|
6588
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6436
6589
|
}
|
|
6437
6590
|
};
|
|
6438
6591
|
const handleRejectJoinRequest = async (request) => {
|
|
@@ -6441,7 +6594,7 @@ function OrganizationContent({
|
|
|
6441
6594
|
toast.success("Request rejected");
|
|
6442
6595
|
await fetchData();
|
|
6443
6596
|
} catch (err) {
|
|
6444
|
-
toast.error(err
|
|
6597
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
6445
6598
|
}
|
|
6446
6599
|
};
|
|
6447
6600
|
if (!current) {
|
|
@@ -6569,7 +6722,7 @@ function OrganizationContent({
|
|
|
6569
6722
|
{
|
|
6570
6723
|
workspace: ws,
|
|
6571
6724
|
joining: joiningId === ws._id,
|
|
6572
|
-
onJoin:
|
|
6725
|
+
onJoin: canJoin && ws.joined === false && ws.status !== "inactive" && (joinRole === "admin" || ws.orgVisibility === "shared") ? () => void handleJoinWorkspace(ws) : void 0
|
|
6573
6726
|
},
|
|
6574
6727
|
ws._id
|
|
6575
6728
|
))
|
|
@@ -6671,12 +6824,27 @@ function OrganizationContent({
|
|
|
6671
6824
|
) });
|
|
6672
6825
|
}
|
|
6673
6826
|
|
|
6827
|
+
// src/billing-errors.ts
|
|
6828
|
+
function isBillingWorkspaceMissing(failure) {
|
|
6829
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6830
|
+
const visit = (value, depth) => {
|
|
6831
|
+
if (depth > 4 || value == null || seen.has(value)) return false;
|
|
6832
|
+
if (typeof value === "string") return /workspace.*not found/i.test(value);
|
|
6833
|
+
if (typeof value !== "object") return false;
|
|
6834
|
+
seen.add(value);
|
|
6835
|
+
const error = value;
|
|
6836
|
+
if (error.code === "billing.workspace_not_found") return true;
|
|
6837
|
+
return [error.message, error.error, error.data, error.body, error.cause, error.publicError].some((child) => visit(child, depth + 1));
|
|
6838
|
+
};
|
|
6839
|
+
return visit(failure, 0);
|
|
6840
|
+
}
|
|
6841
|
+
|
|
6674
6842
|
// src/billing-content.tsx
|
|
6675
6843
|
import {
|
|
6676
6844
|
useState as useState13,
|
|
6677
6845
|
useEffect as useEffect11,
|
|
6678
6846
|
useCallback as useCallback5,
|
|
6679
|
-
useMemo as
|
|
6847
|
+
useMemo as useMemo3,
|
|
6680
6848
|
useRef as useRef6
|
|
6681
6849
|
} from "react";
|
|
6682
6850
|
import {
|
|
@@ -6782,7 +6950,7 @@ var PLAN_TAGLINES = {
|
|
|
6782
6950
|
};
|
|
6783
6951
|
|
|
6784
6952
|
// src/export-date-modal.tsx
|
|
6785
|
-
import { useState as useState11, useMemo, useCallback as useCallback4 } from "react";
|
|
6953
|
+
import { useState as useState11, useMemo as useMemo2, useCallback as useCallback4 } from "react";
|
|
6786
6954
|
import { SiconClose as SiconClose4, SiconLeft, SiconRight } from "@streamoid/icons";
|
|
6787
6955
|
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6788
6956
|
var PRIMARY_COLOR = "var(--alias-text---icons-primary)";
|
|
@@ -6837,7 +7005,7 @@ function ExportDateModal({
|
|
|
6837
7005
|
const [rangeEnd, setRangeEnd] = useState11(null);
|
|
6838
7006
|
const isFuture = (date) => date.getTime() > today.getTime();
|
|
6839
7007
|
const isCurrentMonthView = viewMonth === now.getMonth() && viewYear === now.getFullYear();
|
|
6840
|
-
const cells =
|
|
7008
|
+
const cells = useMemo2(() => {
|
|
6841
7009
|
const result = [];
|
|
6842
7010
|
const daysInMonth = getDaysInMonth(viewYear, viewMonth);
|
|
6843
7011
|
const firstDay = new Date(viewYear, viewMonth, 1).getDay();
|
|
@@ -8000,7 +8168,7 @@ function PlansView({
|
|
|
8000
8168
|
const workspaceCurrencySymbol = getCurrencySymbolByCountry(
|
|
8001
8169
|
workspace?.country
|
|
8002
8170
|
);
|
|
8003
|
-
const allPlans =
|
|
8171
|
+
const allPlans = useMemo3(() => {
|
|
8004
8172
|
if (products.length > 0) {
|
|
8005
8173
|
return products.flatMap(
|
|
8006
8174
|
(product) => product.prices.filter((price) => Boolean(price.metadata?.credits)).map((price) => ({
|
|
@@ -8018,7 +8186,7 @@ function PlansView({
|
|
|
8018
8186
|
}
|
|
8019
8187
|
return [];
|
|
8020
8188
|
}, [products, currentPlanId]);
|
|
8021
|
-
const sortedPlans =
|
|
8189
|
+
const sortedPlans = useMemo3(
|
|
8022
8190
|
() => [...allPlans].sort((a, b) => a.amount - b.amount),
|
|
8023
8191
|
[allPlans]
|
|
8024
8192
|
);
|
|
@@ -8834,8 +9002,8 @@ function BillingContent({
|
|
|
8834
9002
|
toast.success("Plan update submitted");
|
|
8835
9003
|
await fetchBillingOverview();
|
|
8836
9004
|
} catch (err) {
|
|
8837
|
-
const message = err
|
|
8838
|
-
const shouldCreateWorkspace =
|
|
9005
|
+
const message = errorMessage(err, { method: "POST" });
|
|
9006
|
+
const shouldCreateWorkspace = isBillingWorkspaceMissing(err);
|
|
8839
9007
|
if (shouldCreateWorkspace) {
|
|
8840
9008
|
const created = await ensureWorkspaceOnBilling();
|
|
8841
9009
|
if (created && api.updateSubscription) {
|
|
@@ -8888,7 +9056,7 @@ function BillingContent({
|
|
|
8888
9056
|
toast.error("Unable to cancel downgrade");
|
|
8889
9057
|
}
|
|
8890
9058
|
} catch (err) {
|
|
8891
|
-
const msg = err
|
|
9059
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
8892
9060
|
toast.error(msg);
|
|
8893
9061
|
} finally {
|
|
8894
9062
|
setPlanActionInFlight(null);
|
|
@@ -9079,7 +9247,7 @@ function BillingContent({
|
|
|
9079
9247
|
setShowBuyCreditsModal(false);
|
|
9080
9248
|
await fetchBillingOverview();
|
|
9081
9249
|
} catch (err) {
|
|
9082
|
-
const message = err
|
|
9250
|
+
const message = errorMessage(err, { method: "POST" });
|
|
9083
9251
|
toast.error(message);
|
|
9084
9252
|
} finally {
|
|
9085
9253
|
setBuyCreditsInFlight(false);
|
|
@@ -9416,7 +9584,7 @@ function CreateTokenModal({ onClose, onCreated }) {
|
|
|
9416
9584
|
const data = await api.createToken({ name: name.trim(), expiry });
|
|
9417
9585
|
onCreated(data);
|
|
9418
9586
|
} catch (err) {
|
|
9419
|
-
toast.error(err
|
|
9587
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9420
9588
|
} finally {
|
|
9421
9589
|
setLoading(false);
|
|
9422
9590
|
}
|
|
@@ -9771,7 +9939,7 @@ function TokensContent({
|
|
|
9771
9939
|
setTokens((prev) => prev.filter((t) => t._id !== tokenId));
|
|
9772
9940
|
}
|
|
9773
9941
|
} catch (err) {
|
|
9774
|
-
toast.error(err
|
|
9942
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9775
9943
|
} finally {
|
|
9776
9944
|
setDeletingId(null);
|
|
9777
9945
|
}
|
|
@@ -9783,7 +9951,7 @@ function TokensContent({
|
|
|
9783
9951
|
toast.success("Token permanently deleted.");
|
|
9784
9952
|
setTokens((prev) => prev.filter((t) => t._id !== tokenId));
|
|
9785
9953
|
} catch (err) {
|
|
9786
|
-
toast.error(err
|
|
9954
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
9787
9955
|
} finally {
|
|
9788
9956
|
setDeletingId(null);
|
|
9789
9957
|
}
|
|
@@ -10621,7 +10789,7 @@ function ProfileTab() {
|
|
|
10621
10789
|
await auth.refreshProfile();
|
|
10622
10790
|
toast.success("Profile updated");
|
|
10623
10791
|
} catch (err) {
|
|
10624
|
-
const msg = err
|
|
10792
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10625
10793
|
toast.error(msg);
|
|
10626
10794
|
} finally {
|
|
10627
10795
|
setSaving(false);
|
|
@@ -10654,7 +10822,7 @@ function ProfileTab() {
|
|
|
10654
10822
|
toast.success("Profile image updated");
|
|
10655
10823
|
} catch (err) {
|
|
10656
10824
|
setImagePreview(void 0);
|
|
10657
|
-
const msg = err
|
|
10825
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10658
10826
|
toast.error(msg);
|
|
10659
10827
|
} finally {
|
|
10660
10828
|
URL.revokeObjectURL(localPreviewUrl);
|
|
@@ -10674,7 +10842,7 @@ function ProfileTab() {
|
|
|
10674
10842
|
await auth.refreshProfile();
|
|
10675
10843
|
toast.success("Profile image removed");
|
|
10676
10844
|
} catch (err) {
|
|
10677
|
-
const msg = err
|
|
10845
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
10678
10846
|
toast.error(msg);
|
|
10679
10847
|
} finally {
|
|
10680
10848
|
setImageSaving(false);
|
|
@@ -10965,9 +11133,9 @@ function groupWorkspaceList(workspaces, organizations = []) {
|
|
|
10965
11133
|
});
|
|
10966
11134
|
}
|
|
10967
11135
|
}
|
|
10968
|
-
const
|
|
11136
|
+
const known2 = new Set(organizations.map((org) => org._id));
|
|
10969
11137
|
const ungrouped = workspaces.filter(
|
|
10970
|
-
(ws) => !ws.organizationId || !
|
|
11138
|
+
(ws) => !ws.organizationId || !known2.has(ws.organizationId)
|
|
10971
11139
|
);
|
|
10972
11140
|
if (ungrouped.length) {
|
|
10973
11141
|
groups.push({
|
|
@@ -11387,7 +11555,7 @@ function SettingsContentInner({
|
|
|
11387
11555
|
void refreshWorkspaceList();
|
|
11388
11556
|
}, [refreshWorkspaceList]);
|
|
11389
11557
|
const hostListPage = workspace.listPage;
|
|
11390
|
-
const listWorkspacePage =
|
|
11558
|
+
const listWorkspacePage = useMemo4(
|
|
11391
11559
|
() => hostListPage ? async (params) => {
|
|
11392
11560
|
const result = await hostListPage(params);
|
|
11393
11561
|
return {
|
|
@@ -11518,17 +11686,6 @@ function SettingsContentInner({
|
|
|
11518
11686
|
imageRemoved
|
|
11519
11687
|
});
|
|
11520
11688
|
};
|
|
11521
|
-
const getErrorMessage = (err, fallback) => {
|
|
11522
|
-
if (err instanceof Error && err.message.trim()) return err.message;
|
|
11523
|
-
if (err && typeof err === "object" && "body" in err && err.body && typeof err.body === "object" && "status" in err.body && err.body.status && typeof err.body.status === "object" && "message" in err.body.status && typeof err.body.status.message === "string") {
|
|
11524
|
-
return err.body.status.message;
|
|
11525
|
-
}
|
|
11526
|
-
return fallback;
|
|
11527
|
-
};
|
|
11528
|
-
const isSingleAdminError = (message) => {
|
|
11529
|
-
const normalized = message.toLowerCase();
|
|
11530
|
-
return normalized.includes("single admin") || normalized.includes("only admin");
|
|
11531
|
-
};
|
|
11532
11689
|
const getSettingsPath = (nextWorkspaceId) => `/dashboard/${nextWorkspaceId}/settings`;
|
|
11533
11690
|
const getNextWorkspaceId = async (excludedWorkspaceId) => {
|
|
11534
11691
|
try {
|
|
@@ -11612,7 +11769,7 @@ function SettingsContentInner({
|
|
|
11612
11769
|
toast.success("Workspace updated");
|
|
11613
11770
|
return true;
|
|
11614
11771
|
} catch (err) {
|
|
11615
|
-
toast.error(
|
|
11772
|
+
toast.error(errorMessage(err, { method: "PATCH" }));
|
|
11616
11773
|
return false;
|
|
11617
11774
|
} finally {
|
|
11618
11775
|
setUpdatingWorkspace(false);
|
|
@@ -11680,7 +11837,7 @@ function SettingsContentInner({
|
|
|
11680
11837
|
toast.success("Workspace created");
|
|
11681
11838
|
return true;
|
|
11682
11839
|
} catch (err) {
|
|
11683
|
-
const msg = err
|
|
11840
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
11684
11841
|
toast.error(msg);
|
|
11685
11842
|
return false;
|
|
11686
11843
|
} finally {
|
|
@@ -11727,7 +11884,7 @@ function SettingsContentInner({
|
|
|
11727
11884
|
toast.success("Workspace updated");
|
|
11728
11885
|
return true;
|
|
11729
11886
|
} catch (err) {
|
|
11730
|
-
const msg = err
|
|
11887
|
+
const msg = errorMessage(err, { method: "POST" });
|
|
11731
11888
|
toast.error(msg);
|
|
11732
11889
|
return false;
|
|
11733
11890
|
} finally {
|
|
@@ -12203,11 +12360,10 @@ function SettingsContentInner({
|
|
|
12203
12360
|
setLeavingWorkspace(null);
|
|
12204
12361
|
await completeWorkspaceRemoval(wsId, `You left ${wsName}`);
|
|
12205
12362
|
} catch (err) {
|
|
12206
|
-
|
|
12207
|
-
if (isSingleAdminError(message)) {
|
|
12363
|
+
if (isOnlyWorkspaceAdmin(err)) {
|
|
12208
12364
|
toast.error("You are the only admin. Promote another admin before leaving.");
|
|
12209
12365
|
} else {
|
|
12210
|
-
toast.error(
|
|
12366
|
+
toast.error(errorMessage(err, { method: "POST" }));
|
|
12211
12367
|
}
|
|
12212
12368
|
}
|
|
12213
12369
|
},
|
|
@@ -12237,7 +12393,7 @@ function SettingsContentInner({
|
|
|
12237
12393
|
setDeletingWorkspace(null);
|
|
12238
12394
|
await completeWorkspaceRemoval(wsId, `Workspace ${wsName} deleted`);
|
|
12239
12395
|
} catch (err) {
|
|
12240
|
-
toast.error(
|
|
12396
|
+
toast.error(errorMessage(err, { method: "DELETE" }));
|
|
12241
12397
|
}
|
|
12242
12398
|
}
|
|
12243
12399
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamoid/settings",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -36,5 +36,8 @@
|
|
|
36
36
|
"react-dom": "^19.0.0",
|
|
37
37
|
"tsup": "^8.0.0",
|
|
38
38
|
"typescript": "^5.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@streamoid/errors": "0.1.0"
|
|
39
42
|
}
|
|
40
43
|
}
|