@stackframe/stack 2.8.1 → 2.8.3

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/api-key-dialogs.js +184 -0
  3. package/dist/components/api-key-dialogs.js.map +1 -0
  4. package/dist/components/api-key-table.js +149 -0
  5. package/dist/components/api-key-table.js.map +1 -0
  6. package/dist/components-page/account-settings.js +134 -15
  7. package/dist/components-page/account-settings.js.map +1 -1
  8. package/dist/esm/components/api-key-dialogs.js +157 -0
  9. package/dist/esm/components/api-key-dialogs.js.map +1 -0
  10. package/dist/esm/components/api-key-table.js +125 -0
  11. package/dist/esm/components/api-key-table.js.map +1 -0
  12. package/dist/esm/components-page/account-settings.js +132 -15
  13. package/dist/esm/components-page/account-settings.js.map +1 -1
  14. package/dist/esm/lib/auth.js +6 -6
  15. package/dist/esm/lib/auth.js.map +1 -1
  16. package/dist/esm/lib/stack-app/api-keys/index.js +14 -6
  17. package/dist/esm/lib/stack-app/api-keys/index.js.map +1 -1
  18. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +26 -23
  19. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  20. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +106 -19
  21. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  22. package/dist/esm/lib/stack-app/apps/implementations/common.js +1 -1
  23. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  24. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +150 -16
  25. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  26. package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  27. package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  28. package/dist/esm/lib/stack-app/index.js.map +1 -1
  29. package/dist/esm/lib/stack-app/internal-api-keys/index.js +14 -0
  30. package/dist/esm/lib/stack-app/internal-api-keys/index.js.map +1 -0
  31. package/dist/esm/lib/stack-app/projects/index.js +3 -1
  32. package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
  33. package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
  34. package/dist/esm/lib/stack-app/users/index.js.map +1 -1
  35. package/dist/esm/utils/url.js +2 -2
  36. package/dist/esm/utils/url.js.map +1 -1
  37. package/dist/index.d.mts +100 -35
  38. package/dist/index.d.ts +100 -35
  39. package/dist/lib/auth.js +6 -6
  40. package/dist/lib/auth.js.map +1 -1
  41. package/dist/lib/stack-app/api-keys/index.js +16 -7
  42. package/dist/lib/stack-app/api-keys/index.js.map +1 -1
  43. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +25 -22
  44. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  45. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +106 -19
  46. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  47. package/dist/lib/stack-app/apps/implementations/common.js +1 -1
  48. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  49. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +150 -16
  50. package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  51. package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
  52. package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
  53. package/dist/lib/stack-app/index.js.map +1 -1
  54. package/dist/lib/stack-app/internal-api-keys/index.js +39 -0
  55. package/dist/lib/stack-app/internal-api-keys/index.js.map +1 -0
  56. package/dist/lib/stack-app/project-configs/index.js.map +1 -1
  57. package/dist/lib/stack-app/projects/index.js +3 -1
  58. package/dist/lib/stack-app/projects/index.js.map +1 -1
  59. package/dist/lib/stack-app/teams/index.js.map +1 -1
  60. package/dist/lib/stack-app/users/index.js.map +1 -1
  61. package/dist/utils/url.js +2 -2
  62. package/dist/utils/url.js.map +1 -1
  63. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @stackframe/stack
2
2
 
3
+ ## 2.8.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Various changes
8
+ - Updated dependencies
9
+ - @stackframe/stack-shared@2.8.3
10
+ - @stackframe/stack-ui@2.8.3
11
+ - @stackframe/stack-sc@2.8.3
12
+
13
+ ## 2.8.2
14
+
15
+ ### Patch Changes
16
+
17
+ - Various changes
18
+ - Updated dependencies
19
+ - @stackframe/stack-shared@2.8.2
20
+ - @stackframe/stack-ui@2.8.2
21
+ - @stackframe/stack-sc@2.8.2
22
+
3
23
  ## 2.8.1
4
24
 
5
25
  ### Patch Changes
@@ -0,0 +1,184 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/components/api-key-dialogs.tsx
23
+ var api_key_dialogs_exports = {};
24
+ __export(api_key_dialogs_exports, {
25
+ CreateApiKeyDialog: () => CreateApiKeyDialog,
26
+ ShowApiKeyDialog: () => ShowApiKeyDialog,
27
+ expiresInOptions: () => expiresInOptions,
28
+ neverInMs: () => neverInMs
29
+ });
30
+ module.exports = __toCommonJS(api_key_dialogs_exports);
31
+ var import_yup = require("@hookform/resolvers/yup");
32
+ var import_schema_fields = require("@stackframe/stack-shared/dist/schema-fields");
33
+ var import_errors = require("@stackframe/stack-shared/dist/utils/errors");
34
+ var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
35
+ var import_stack_ui = require("@stackframe/stack-ui");
36
+ var import_react = require("react");
37
+ var import_react_hook_form = require("react-hook-form");
38
+ var import__ = require("..");
39
+ var import_form_warning = require("../components/elements/form-warning");
40
+ var import_translations = require("../lib/translations");
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var neverInMs = 1e3 * 60 * 60 * 24 * 365 * 200;
43
+ var expiresInOptions = {
44
+ [1e3 * 60 * 60 * 24 * 1]: "1 day",
45
+ [1e3 * 60 * 60 * 24 * 7]: "7 days",
46
+ [1e3 * 60 * 60 * 24 * 30]: "30 days",
47
+ [1e3 * 60 * 60 * 24 * 90]: "90 days",
48
+ [1e3 * 60 * 60 * 24 * 365]: "1 year",
49
+ [neverInMs]: "Never"
50
+ };
51
+ function CreateApiKeyDialog(props) {
52
+ const { t } = (0, import_translations.useTranslation)();
53
+ const user = (0, import__.useUser)({ or: "redirect" });
54
+ const [loading, setLoading] = (0, import_react.useState)(false);
55
+ const apiKeySchema = (0, import_schema_fields.yupObject)({
56
+ description: (0, import_schema_fields.yupString)().defined().nonEmpty(t("Description is required")),
57
+ expiresIn: (0, import_schema_fields.yupString)().defined()
58
+ });
59
+ const { register, handleSubmit, formState: { errors }, reset } = (0, import_react_hook_form.useForm)({
60
+ resolver: (0, import_yup.yupResolver)(apiKeySchema),
61
+ defaultValues: {
62
+ description: "",
63
+ expiresIn: Object.keys(expiresInOptions)[2]
64
+ // Default to 30 days
65
+ }
66
+ });
67
+ const onSubmit = async (data) => {
68
+ setLoading(true);
69
+ try {
70
+ const expiresAt = new Date(Date.now() + parseInt(data.expiresIn));
71
+ const apiKey = await props.createApiKey({
72
+ description: data.description,
73
+ expiresAt
74
+ });
75
+ if (props.onKeyCreated) {
76
+ props.onKeyCreated(apiKey);
77
+ }
78
+ reset();
79
+ props.onOpenChange(false);
80
+ } catch (error) {
81
+ (0, import_errors.captureError)("Failed to create API key", { error });
82
+ } finally {
83
+ setLoading(false);
84
+ }
85
+ };
86
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
87
+ import_stack_ui.ActionDialog,
88
+ {
89
+ open: props.open,
90
+ onOpenChange: props.onOpenChange,
91
+ title: t("Create API Key"),
92
+ description: t("API keys grant programmatic access to your account."),
93
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
94
+ "form",
95
+ {
96
+ onSubmit: (e) => {
97
+ e.preventDefault();
98
+ (0, import_promises.runAsynchronously)(handleSubmit(onSubmit));
99
+ },
100
+ className: "space-y-4",
101
+ children: [
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "description", children: t("Description") }),
104
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
105
+ import_stack_ui.Input,
106
+ {
107
+ id: "description",
108
+ placeholder: t("e.g. Development, Production, CI/CD"),
109
+ ...register("description")
110
+ }
111
+ ),
112
+ errors.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.description.message })
113
+ ] }),
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Label, { htmlFor: "expiresIn", children: t("Expires In") }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
117
+ "select",
118
+ {
119
+ id: "expiresIn",
120
+ className: "w-full p-2 border border-input rounded-md bg-background",
121
+ ...register("expiresIn"),
122
+ children: Object.entries(expiresInOptions).map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value, children: t(label) }, value))
123
+ }
124
+ ),
125
+ errors.expiresIn && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.expiresIn.message })
126
+ ] }),
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-end gap-2 pt-4", children: [
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
129
+ import_stack_ui.Button,
130
+ {
131
+ type: "button",
132
+ variant: "secondary",
133
+ onClick: () => {
134
+ reset();
135
+ props.onOpenChange(false);
136
+ },
137
+ children: t("Cancel")
138
+ }
139
+ ),
140
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, children: t("Create") })
141
+ ] })
142
+ ]
143
+ }
144
+ )
145
+ }
146
+ );
147
+ }
148
+ function ShowApiKeyDialog(props) {
149
+ const { t } = (0, import_translations.useTranslation)();
150
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
151
+ import_stack_ui.ActionDialog,
152
+ {
153
+ open: !!props.apiKey,
154
+ title: t("API Key"),
155
+ okButton: { label: t("Close") },
156
+ onClose: props.onClose,
157
+ preventClose: true,
158
+ confirmText: t("I understand that I will not be able to view this key again."),
159
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-4", children: [
160
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { children: [
161
+ t("Here is your API key."),
162
+ " ",
163
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-bold", children: t("Copy it to a safe place. You will not be able to view it again.") })
164
+ ] }),
165
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
166
+ import_stack_ui.CopyField,
167
+ {
168
+ monospace: true,
169
+ value: props.apiKey?.value ?? "",
170
+ label: t("Secret API Key")
171
+ }
172
+ )
173
+ ] })
174
+ }
175
+ );
176
+ }
177
+ // Annotate the CommonJS export names for ESM import in node:
178
+ 0 && (module.exports = {
179
+ CreateApiKeyDialog,
180
+ ShowApiKeyDialog,
181
+ expiresInOptions,
182
+ neverInMs
183
+ });
184
+ //# sourceMappingURL=api-key-dialogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/api-key-dialogs.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { captureError } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously } from '@stackframe/stack-shared/dist/utils/promises';\nimport { ActionDialog, Button, CopyField, Input, Label, Typography } from '@stackframe/stack-ui';\nimport { useState } from \"react\";\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { ApiKey, ApiKeyCreationOptions, ApiKeyType } from \"../lib/stack-app/api-keys\";\nimport { useTranslation } from \"../lib/translations\";\n\n// Constants for expiration options\nexport const neverInMs = 1000 * 60 * 60 * 24 * 365 * 200;\nexport const expiresInOptions = {\n [1000 * 60 * 60 * 24 * 1]: \"1 day\",\n [1000 * 60 * 60 * 24 * 7]: \"7 days\",\n [1000 * 60 * 60 * 24 * 30]: \"30 days\",\n [1000 * 60 * 60 * 24 * 90]: \"90 days\",\n [1000 * 60 * 60 * 24 * 365]: \"1 year\",\n [neverInMs]: \"Never\",\n} as const;\n\n/**\n * Dialog for creating a new API key\n */\nexport function CreateApiKeyDialog<Type extends ApiKeyType = ApiKeyType>(props: {\n open: boolean,\n onOpenChange: (open: boolean) => void,\n onKeyCreated?: (key: ApiKey<Type, true>) => void,\n createApiKey: (data: ApiKeyCreationOptions<Type>) => Promise<ApiKey<Type, true>>,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n const apiKeySchema = yupObject({\n description: yupString().defined().nonEmpty(t('Description is required')),\n expiresIn: yupString().defined(),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(apiKeySchema),\n defaultValues: {\n description: '',\n expiresIn: Object.keys(expiresInOptions)[2], // Default to 30 days\n }\n });\n\n const onSubmit = async (data: yup.InferType<typeof apiKeySchema>) => {\n setLoading(true);\n try {\n const expiresAt = new Date(Date.now() + parseInt(data.expiresIn));\n const apiKey = await props.createApiKey({\n description: data.description,\n expiresAt,\n });\n\n if (props.onKeyCreated) {\n props.onKeyCreated(apiKey);\n }\n\n reset();\n props.onOpenChange(false);\n } catch (error) {\n captureError(\"Failed to create API key\", { error });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <ActionDialog\n open={props.open}\n onOpenChange={props.onOpenChange}\n title={t('Create API Key')}\n description={t('API keys grant programmatic access to your account.')}\n >\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className=\"space-y-4\"\n >\n <div className=\"space-y-2\">\n <Label htmlFor=\"description\">{t('Description')}</Label>\n <Input\n id=\"description\"\n placeholder={t('e.g. Development, Production, CI/CD')}\n {...register('description')}\n />\n {errors.description && <FormWarningText text={errors.description.message} />}\n </div>\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"expiresIn\">{t('Expires In')}</Label>\n <select\n id=\"expiresIn\"\n className=\"w-full p-2 border border-input rounded-md bg-background\"\n {...register('expiresIn')}\n >\n {Object.entries(expiresInOptions).map(([value, label]) => (\n <option key={value} value={value}>{t(label)}</option>\n ))}\n </select>\n {errors.expiresIn && <FormWarningText text={errors.expiresIn.message} />}\n </div>\n\n <div className=\"flex justify-end gap-2 pt-4\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n reset();\n props.onOpenChange(false);\n }}\n >\n {t('Cancel')}\n </Button>\n <Button type=\"submit\" loading={loading}>\n {t('Create')}\n </Button>\n </div>\n </form>\n </ActionDialog>\n );\n}\n\n/**\n * Dialog for showing the newly created API key\n */\nexport function ShowApiKeyDialog<Type extends ApiKeyType = ApiKeyType>(props: {\n apiKey: ApiKey<Type, true> | null,\n onClose?: () => void,\n}) {\n const { t } = useTranslation();\n\n return (\n <ActionDialog\n open={!!props.apiKey}\n title={t(\"API Key\")}\n okButton={{ label: t(\"Close\") }}\n onClose={props.onClose}\n preventClose\n confirmText={t(\"I understand that I will not be able to view this key again.\")}\n >\n <div className=\"flex flex-col gap-4\">\n <Typography>\n {t(\"Here is your API key.\")}{\" \"}\n <span className=\"font-bold\">\n {t(\"Copy it to a safe place. You will not be able to view it again.\")}\n </span>\n </Typography>\n <CopyField\n monospace\n value={props.apiKey?.value ?? ''}\n label={t(\"Secret API Key\")}\n />\n </div>\n </ActionDialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,149 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/components/api-key-table.tsx
23
+ var api_key_table_exports = {};
24
+ __export(api_key_table_exports, {
25
+ ApiKeyTable: () => ApiKeyTable
26
+ });
27
+ module.exports = __toCommonJS(api_key_table_exports);
28
+ var import_stack_ui = require("@stackframe/stack-ui");
29
+ var import_react = require("react");
30
+ var import_jsx_runtime = require("react/jsx-runtime");
31
+ function toolbarRender(table) {
32
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
33
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.SearchToolbarItem, { table, placeholder: "Search table" }),
34
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
35
+ import_stack_ui.DataTableFacetedFilter,
36
+ {
37
+ column: table.getColumn("status"),
38
+ title: "Status",
39
+ options: ["valid", "expired", "revoked"].map((provider) => ({
40
+ value: provider,
41
+ label: provider
42
+ }))
43
+ }
44
+ )
45
+ ] });
46
+ }
47
+ function RevokeDialog(props) {
48
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
49
+ import_stack_ui.ActionDialog,
50
+ {
51
+ open: props.open,
52
+ onOpenChange: props.onOpenChange,
53
+ title: "Revoke API Key",
54
+ danger: true,
55
+ cancelButton: true,
56
+ okButton: { label: "Revoke Key", onClick: async () => {
57
+ await props.apiKey.revoke();
58
+ } },
59
+ confirmText: "I understand this will unlink all the apps using this API key",
60
+ children: `Are you sure you want to revoke API key *****${props.apiKey.value.lastFour}?`
61
+ }
62
+ );
63
+ }
64
+ function Actions({ row }) {
65
+ const [isRevokeModalOpen, setIsRevokeModalOpen] = (0, import_react.useState)(false);
66
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
67
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RevokeDialog, { apiKey: row.original, open: isRevokeModalOpen, onOpenChange: setIsRevokeModalOpen }),
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
69
+ import_stack_ui.ActionCell,
70
+ {
71
+ invisible: row.original.status !== "valid",
72
+ items: [{
73
+ item: "Revoke",
74
+ danger: true,
75
+ onClick: () => setIsRevokeModalOpen(true)
76
+ }]
77
+ }
78
+ )
79
+ ] });
80
+ }
81
+ var columns = [
82
+ {
83
+ accessorKey: "description",
84
+ header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Description" }),
85
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { size: 100, children: row.original.description })
86
+ },
87
+ {
88
+ accessorKey: "status",
89
+ header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Status" }),
90
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.BadgeCell, { badges: [row.original.status] }),
91
+ filterFn: import_stack_ui.standardFilterFn
92
+ },
93
+ {
94
+ id: "value",
95
+ accessorFn: (row) => row.value.lastFour,
96
+ header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Client Key" }),
97
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TextCell, { children: [
98
+ "*******",
99
+ row.original.value.lastFour
100
+ ] }),
101
+ enableSorting: false
102
+ },
103
+ {
104
+ accessorKey: "expiresAt",
105
+ header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Expires At" }),
106
+ cell: ({ row }) => {
107
+ if (row.original.status === "revoked") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { children: "-" });
108
+ return row.original.expiresAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DateCell, { date: row.original.expiresAt, ignoreAfterYears: 50 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TextCell, { children: "Never" });
109
+ }
110
+ },
111
+ {
112
+ accessorKey: "createdAt",
113
+ header: ({ column }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DataTableColumnHeader, { column, columnTitle: "Created At" }),
114
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DateCell, { date: row.original.createdAt, ignoreAfterYears: 50 })
115
+ },
116
+ {
117
+ id: "actions",
118
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Actions, { row })
119
+ }
120
+ ];
121
+ function ApiKeyTable(props) {
122
+ const extendedApiKeys = (0, import_react.useMemo)(() => {
123
+ const keys = props.apiKeys.map((apiKey) => ({
124
+ ...apiKey,
125
+ status: { "valid": "valid", "manually-revoked": "revoked", "expired": "expired" }[apiKey.whyInvalid() || "valid"]
126
+ }));
127
+ return keys.sort((a, b) => {
128
+ if (a.status === b.status) {
129
+ return a.createdAt < b.createdAt ? 1 : -1;
130
+ }
131
+ return a.status === "valid" ? -1 : 1;
132
+ });
133
+ }, [props.apiKeys]);
134
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
135
+ import_stack_ui.DataTable,
136
+ {
137
+ data: extendedApiKeys,
138
+ columns,
139
+ toolbarRender,
140
+ defaultColumnFilters: [],
141
+ defaultSorting: []
142
+ }
143
+ );
144
+ }
145
+ // Annotate the CommonJS export names for ESM import in node:
146
+ 0 && (module.exports = {
147
+ ApiKeyTable
148
+ });
149
+ //# sourceMappingURL=api-key-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/api-key-table.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { ActionCell, ActionDialog, BadgeCell, DataTable, DataTableColumnHeader, DataTableFacetedFilter, DateCell, SearchToolbarItem, TextCell, standardFilterFn } from \"@stackframe/stack-ui\";\nimport { ColumnDef, Row, Table } from \"@tanstack/react-table\";\nimport { useMemo, useState } from \"react\";\nimport { ApiKey } from \"../lib/stack-app/api-keys\";\n\ntype ExtendedApiKey = ApiKey & {\n status: 'valid' | 'expired' | 'revoked',\n};\n\nfunction toolbarRender<TData>(table: Table<TData>) {\n return (\n <>\n <SearchToolbarItem table={table} placeholder=\"Search table\" />\n <DataTableFacetedFilter\n column={table.getColumn(\"status\")}\n title=\"Status\"\n options={['valid', 'expired', 'revoked'].map((provider) => ({\n value: provider,\n label: provider,\n }))}\n />\n </>\n );\n}\n\nfunction RevokeDialog(props: {\n apiKey: ExtendedApiKey,\n open: boolean,\n onOpenChange: (open: boolean) => void,\n}) {\n return <ActionDialog\n open={props.open}\n onOpenChange={props.onOpenChange}\n title=\"Revoke API Key\"\n danger\n cancelButton\n okButton={{ label: \"Revoke Key\", onClick: async () => { await props.apiKey.revoke(); } }}\n confirmText=\"I understand this will unlink all the apps using this API key\"\n >\n {`Are you sure you want to revoke API key *****${props.apiKey.value.lastFour}?`}\n </ActionDialog>;\n}\n\nfunction Actions({ row }: { row: Row<ExtendedApiKey> }) {\n const [isRevokeModalOpen, setIsRevokeModalOpen] = useState(false);\n return (\n <>\n <RevokeDialog apiKey={row.original} open={isRevokeModalOpen} onOpenChange={setIsRevokeModalOpen} />\n <ActionCell\n invisible={row.original.status !== 'valid'}\n items={[{\n item: \"Revoke\",\n danger: true,\n onClick: () => setIsRevokeModalOpen(true),\n }]}\n />\n </>\n );\n}\n\nconst columns: ColumnDef<ExtendedApiKey>[] = [\n {\n accessorKey: \"description\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Description\" />,\n cell: ({ row }) => <TextCell size={100}>{row.original.description}</TextCell>,\n },\n {\n accessorKey: \"status\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Status\" />,\n cell: ({ row }) => <BadgeCell badges={[row.original.status]} />,\n filterFn: standardFilterFn,\n },\n {\n id: \"value\",\n accessorFn: (row) => row.value.lastFour,\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Client Key\" />,\n cell: ({ row }) => <TextCell>*******{row.original.value.lastFour}</TextCell>,\n enableSorting: false,\n },\n {\n accessorKey: \"expiresAt\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Expires At\" />,\n cell: ({ row }) => {\n if (row.original.status === 'revoked') return <TextCell>-</TextCell>;\n return row.original.expiresAt ? <DateCell date={row.original.expiresAt} ignoreAfterYears={50} /> : <TextCell>Never</TextCell>;\n },\n },\n {\n accessorKey: \"createdAt\",\n header: ({ column }) => <DataTableColumnHeader column={column} columnTitle=\"Created At\" />,\n cell: ({ row }) => <DateCell date={row.original.createdAt} ignoreAfterYears={50} />\n },\n {\n id: \"actions\",\n cell: ({ row }) => <Actions row={row} />,\n },\n];\n\nexport function ApiKeyTable(props: { apiKeys: ApiKey[] }) {\n const extendedApiKeys = useMemo(() => {\n const keys = props.apiKeys.map((apiKey) => ({\n ...apiKey,\n status: ({ 'valid': 'valid', 'manually-revoked': 'revoked', 'expired': 'expired' } as const)[apiKey.whyInvalid() || 'valid'],\n } satisfies ExtendedApiKey));\n // first sort based on status, then by createdAt\n return keys.sort((a, b) => {\n if (a.status === b.status) {\n return a.createdAt < b.createdAt ? 1 : -1;\n }\n return a.status === 'valid' ? -1 : 1;\n });\n }, [props.apiKeys]);\n\n return <DataTable\n data={extendedApiKeys}\n columns={columns}\n toolbarRender={toolbarRender}\n defaultColumnFilters={[]}\n defaultSorting={[]}\n />;\n}\n"],"mappings":"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","names":[]}
@@ -33,7 +33,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
33
33
  var account_settings_exports = {};
34
34
  __export(account_settings_exports, {
35
35
  AccountSettings: () => AccountSettings,
36
- EditableText: () => EditableText
36
+ ApiKeysPage: () => ApiKeysPage,
37
+ EditableText: () => EditableText,
38
+ TeamApiKeysSection: () => TeamApiKeysSection
37
39
  });
38
40
  module.exports = __toCommonJS(account_settings_exports);
39
41
  var import_yup = require("@hookform/resolvers/yup");
@@ -53,6 +55,8 @@ var import_react = require("react");
53
55
  var import_react_hook_form = require("react-hook-form");
54
56
  var yup = __toESM(require("yup"));
55
57
  var import__ = require("..");
58
+ var import_api_key_dialogs = require("../components/api-key-dialogs");
59
+ var import_api_key_table = require("../components/api-key-table");
56
60
  var import_form_warning = require("../components/elements/form-warning");
57
61
  var import_maybe_full_page = require("../components/elements/maybe-full-page");
58
62
  var import_sidebar_layout = require("../components/elements/sidebar-layout");
@@ -96,6 +100,13 @@ function AccountSettings(props) {
96
100
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Monitor" }),
97
101
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ActiveSessionsPage, {}) })
98
102
  },
103
+ ...project.config.allowUserApiKeys ? [{
104
+ title: t("API Keys"),
105
+ type: "item",
106
+ id: "api-keys",
107
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Key" }),
108
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiKeysPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiKeysPage, {}) })
109
+ }] : [],
99
110
  {
100
111
  title: t("Settings"),
101
112
  type: "item",
@@ -129,14 +140,14 @@ function AccountSettings(props) {
129
140
  ] }),
130
141
  type: "item",
131
142
  id: `team-${team.id}`,
132
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team })
143
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamPage, { team }) })
133
144
  })),
134
145
  ...project.config.clientTeamCreationEnabled ? [{
135
146
  title: t("Create a team"),
136
147
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "CirclePlus" }),
137
148
  type: "item",
138
149
  id: "team-creation",
139
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {})
150
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreationSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamCreation, {}) })
140
151
  }] : []
141
152
  ].filter((p) => p.type === "divider" || p.content),
142
153
  title: t("Account Settings")
@@ -158,6 +169,88 @@ function Section(props) {
158
169
  function PageLayout(props) {
159
170
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-6", children: props.children });
160
171
  }
172
+ function ApiKeysPage() {
173
+ const { t } = (0, import_translations.useTranslation)();
174
+ const user = (0, import__.useUser)({ or: "redirect" });
175
+ const apiKeys = user.useApiKeys();
176
+ const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = (0, import_react.useState)(false);
177
+ const [returnedApiKey, setReturnedApiKey] = (0, import_react.useState)(null);
178
+ const CreateDialog = import_api_key_dialogs.CreateApiKeyDialog;
179
+ const ShowDialog = import_api_key_dialogs.ShowApiKeyDialog;
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
181
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setIsNewApiKeyDialogOpen(true), children: t("Create API Key") }),
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_key_table.ApiKeyTable, { apiKeys }),
183
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
184
+ CreateDialog,
185
+ {
186
+ open: isNewApiKeyDialogOpen,
187
+ onOpenChange: setIsNewApiKeyDialogOpen,
188
+ onKeyCreated: setReturnedApiKey,
189
+ createApiKey: async (data) => {
190
+ const apiKey = await user.createApiKey(data);
191
+ return apiKey;
192
+ }
193
+ }
194
+ ),
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
196
+ ShowDialog,
197
+ {
198
+ apiKey: returnedApiKey,
199
+ onClose: () => setReturnedApiKey(null)
200
+ }
201
+ )
202
+ ] });
203
+ }
204
+ function TeamApiKeysSection(props) {
205
+ const user = (0, import__.useUser)({ or: "redirect" });
206
+ const team = user.useTeam(props.team.id);
207
+ if (!team) {
208
+ throw new import_errors.StackAssertionError("Team not found");
209
+ }
210
+ const manageApiKeysPermission = user.usePermission(props.team, "$manage_api_keys");
211
+ if (!manageApiKeysPermission) {
212
+ return null;
213
+ }
214
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamApiKeysSectionInner, { team: props.team });
215
+ }
216
+ function TeamApiKeysSectionInner(props) {
217
+ const { t } = (0, import_translations.useTranslation)();
218
+ const [isNewApiKeyDialogOpen, setIsNewApiKeyDialogOpen] = (0, import_react.useState)(false);
219
+ const [returnedApiKey, setReturnedApiKey] = (0, import_react.useState)(null);
220
+ const apiKeys = props.team.useApiKeys();
221
+ const CreateDialog = import_api_key_dialogs.CreateApiKeyDialog;
222
+ const ShowDialog = import_api_key_dialogs.ShowApiKeyDialog;
223
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
224
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
225
+ Section,
226
+ {
227
+ title: t("API Keys"),
228
+ description: t("API keys grant programmatic access to your team."),
229
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setIsNewApiKeyDialogOpen(true), children: t("Create API Key") })
230
+ }
231
+ ),
232
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_key_table.ApiKeyTable, { apiKeys }),
233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
234
+ CreateDialog,
235
+ {
236
+ open: isNewApiKeyDialogOpen,
237
+ onOpenChange: setIsNewApiKeyDialogOpen,
238
+ onKeyCreated: setReturnedApiKey,
239
+ createApiKey: async (data) => {
240
+ const apiKey = await props.team.createApiKey(data);
241
+ return apiKey;
242
+ }
243
+ }
244
+ ),
245
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
246
+ ShowDialog,
247
+ {
248
+ apiKey: returnedApiKey,
249
+ onClose: () => setReturnedApiKey(null)
250
+ }
251
+ )
252
+ ] });
253
+ }
161
254
  function ProfilePage() {
162
255
  const { t } = (0, import_translations.useTranslation)();
163
256
  const user = (0, import__.useUser)({ or: "redirect" });
@@ -835,12 +928,13 @@ function SignOutSection() {
835
928
  }
836
929
  function TeamPage(props) {
837
930
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
838
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamUserProfileSection, { team: props.team }),
839
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberListSection, { team: props.team }),
840
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberInvitationSection, { team: props.team }),
841
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamProfileImageSection, { team: props.team }),
842
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamDisplayNameSection, { team: props.team }),
843
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LeaveTeamSection, { team: props.team })
931
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamUserProfileSection, { team: props.team }, `user-profile-${props.team.id}`),
932
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamProfileImageSection, { team: props.team }, `profile-image-${props.team.id}`),
933
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamDisplayNameSection, { team: props.team }, `display-name-${props.team.id}`),
934
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberListSection, { team: props.team }, `member-list-${props.team.id}`),
935
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MemberInvitationSection, { team: props.team }, `member-invitation-${props.team.id}`),
936
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TeamApiKeysSection, { team: props.team }, `api-keys-${props.team.id}`),
937
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LeaveTeamSection, { team: props.team }, `leave-team-${props.team.id}`)
844
938
  ] });
845
939
  }
846
940
  function LeaveTeamSection(props) {
@@ -972,11 +1066,14 @@ function MemberInvitationsSectionInvitationsList(props) {
972
1066
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[60px]", children: t("Expires") }),
973
1067
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableHead, { className: "w-[36px] max-w-[36px]" })
974
1068
  ] }) }),
975
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableBody, { children: invitationsToShow.map((invitation, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
976
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: invitation.recipientEmail }) }),
977
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: invitation.expiresAt.toLocaleString() }) }),
978
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { align: "right", className: "max-w-[36px]", children: removeMemberPermission && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: async () => await invitation.revoke(), size: "icon", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Trash, { className: "w-4 h-4" }) }) })
979
- ] }, invitation.id)) })
1069
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableBody, { children: [
1070
+ invitationsToShow.map((invitation, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.TableRow, { children: [
1071
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: invitation.recipientEmail }) }),
1072
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: invitation.expiresAt.toLocaleString() }) }),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { align: "right", className: "max-w-[36px]", children: removeMemberPermission && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: async () => await invitation.revoke(), size: "icon", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Trash, { className: "w-4 h-4" }) }) })
1074
+ ] }, invitation.id)),
1075
+ invitationsToShow.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.TableCell, { colSpan: 3, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "secondary", children: t("No outstanding invitations") }) }) })
1076
+ ] })
980
1077
  ] }) });
981
1078
  }
982
1079
  function MemberInvitationSectionInner(props) {
@@ -1205,9 +1302,31 @@ function EditableText(props) {
1205
1302
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { onClick: () => setEditing(true), size: "icon", variant: "ghost", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Edit, { className: "w-4 h-4" }) })
1206
1303
  ] }) });
1207
1304
  }
1305
+ function ApiKeysPageSkeleton() {
1306
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
1307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
1308
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[200px] w-full mt-1 rounded-md" })
1309
+ ] });
1310
+ }
1311
+ function TeamPageSkeleton() {
1312
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
1313
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
1314
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
1316
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-[200px] w-full mt-1 rounded-md" })
1317
+ ] });
1318
+ }
1319
+ function TeamCreationSkeleton() {
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(PageLayout, { children: [
1321
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" }),
1322
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Skeleton, { className: "h-9 w-full mt-1" })
1323
+ ] });
1324
+ }
1208
1325
  // Annotate the CommonJS export names for ESM import in node:
1209
1326
  0 && (module.exports = {
1210
1327
  AccountSettings,
1211
- EditableText
1328
+ ApiKeysPage,
1329
+ EditableText,
1330
+ TeamApiKeysSection
1212
1331
  });
1213
1332
  //# sourceMappingURL=account-settings.js.map