@skaile/forge-settings 0.0.0-stage → 1.0.1

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 (89) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +94 -2
  4. package/dist/module.d.mts +17 -0
  5. package/dist/module.json +9 -0
  6. package/dist/module.mjs +23 -0
  7. package/dist/runtime/ai-sdk/index.d.ts +46 -0
  8. package/dist/runtime/ai-sdk/index.js +31 -0
  9. package/dist/runtime/components/ForgeProvidersPanel.d.vue.ts +21 -0
  10. package/dist/runtime/components/ForgeProvidersPanel.vue +435 -0
  11. package/dist/runtime/components/ForgeProvidersPanel.vue.d.ts +21 -0
  12. package/dist/runtime/editor/index.d.ts +58 -0
  13. package/dist/runtime/editor/index.js +72 -0
  14. package/dist/runtime/model/errors.d.ts +32 -0
  15. package/dist/runtime/model/errors.js +19 -0
  16. package/dist/runtime/server/credential-policy.d.ts +61 -0
  17. package/dist/runtime/server/credential-policy.js +65 -0
  18. package/dist/runtime/server/credential-store.d.ts +184 -0
  19. package/dist/runtime/server/credential-store.js +234 -0
  20. package/dist/runtime/server/env-layers.d.ts +62 -0
  21. package/dist/runtime/server/env-layers.js +183 -0
  22. package/dist/runtime/server/env.d.ts +30 -0
  23. package/dist/runtime/server/env.js +15 -0
  24. package/dist/runtime/server/harness-settings.d.ts +150 -0
  25. package/dist/runtime/server/harness-settings.js +166 -0
  26. package/dist/runtime/server/index.d.ts +23 -0
  27. package/dist/runtime/server/index.js +14 -0
  28. package/dist/runtime/server/provider-discovery.d.ts +73 -0
  29. package/dist/runtime/server/provider-discovery.js +77 -0
  30. package/dist/runtime/server/provider-layers.d.ts +27 -0
  31. package/dist/runtime/server/provider-layers.js +35 -0
  32. package/dist/runtime/server/provider-service.d.ts +126 -0
  33. package/dist/runtime/server/provider-service.js +87 -0
  34. package/dist/runtime/server/provider-settings.d.ts +78 -0
  35. package/dist/runtime/server/provider-settings.js +81 -0
  36. package/dist/runtime/server/provider-write.d.ts +154 -0
  37. package/dist/runtime/server/provider-write.js +221 -0
  38. package/dist/runtime/server/settings-defaults.d.ts +26 -0
  39. package/dist/runtime/server/settings-defaults.js +46 -0
  40. package/dist/runtime/shared/env-vars.d.ts +55 -0
  41. package/dist/runtime/shared/env-vars.js +22 -0
  42. package/dist/runtime/shared/guards.d.ts +2 -0
  43. package/dist/runtime/shared/guards.js +3 -0
  44. package/dist/runtime/shared/harness-providers.d.ts +62 -0
  45. package/dist/runtime/shared/harness-providers.js +38 -0
  46. package/dist/runtime/shared/harnesses.d.ts +19 -0
  47. package/dist/runtime/shared/harnesses.js +15 -0
  48. package/dist/runtime/shared/provider-registry.d.ts +255 -0
  49. package/dist/runtime/shared/provider-registry.js +112 -0
  50. package/dist/runtime/shared/settings-types.d.ts +84 -0
  51. package/dist/runtime/shared/settings-types.js +0 -0
  52. package/dist/runtime/shims-vue.d.ts +8 -0
  53. package/dist/runtime/vue/index.d.ts +14 -0
  54. package/dist/runtime/vue/index.js +6 -0
  55. package/dist/runtime/vue/providers-panel-model.d.ts +147 -0
  56. package/dist/runtime/vue/providers-panel-model.js +37 -0
  57. package/dist/runtime/vue/settings-modal-scope.d.ts +62 -0
  58. package/dist/runtime/vue/settings-modal-scope.js +2 -0
  59. package/dist/runtime/vue/useProvidersPanel.d.ts +115 -0
  60. package/dist/runtime/vue/useProvidersPanel.js +633 -0
  61. package/dist/types.d.mts +9 -0
  62. package/package.json +117 -4
  63. package/src/runtime/ai-sdk/index.ts +88 -0
  64. package/src/runtime/components/ForgeProvidersPanel.vue +449 -0
  65. package/src/runtime/editor/index.ts +146 -0
  66. package/src/runtime/model/errors.ts +52 -0
  67. package/src/runtime/server/credential-policy.ts +139 -0
  68. package/src/runtime/server/credential-store.ts +473 -0
  69. package/src/runtime/server/env-layers.ts +287 -0
  70. package/src/runtime/server/env.ts +46 -0
  71. package/src/runtime/server/harness-settings.ts +373 -0
  72. package/src/runtime/server/index.ts +24 -0
  73. package/src/runtime/server/provider-discovery.ts +164 -0
  74. package/src/runtime/server/provider-layers.ts +67 -0
  75. package/src/runtime/server/provider-service.ts +244 -0
  76. package/src/runtime/server/provider-settings.ts +192 -0
  77. package/src/runtime/server/provider-write.ts +433 -0
  78. package/src/runtime/server/settings-defaults.ts +87 -0
  79. package/src/runtime/shared/env-vars.ts +82 -0
  80. package/src/runtime/shared/guards.ts +4 -0
  81. package/src/runtime/shared/harness-providers.ts +118 -0
  82. package/src/runtime/shared/harnesses.ts +34 -0
  83. package/src/runtime/shared/provider-registry.ts +391 -0
  84. package/src/runtime/shared/settings-types.ts +87 -0
  85. package/src/runtime/shims-vue.d.ts +8 -0
  86. package/src/runtime/vue/index.ts +15 -0
  87. package/src/runtime/vue/providers-panel-model.ts +203 -0
  88. package/src/runtime/vue/settings-modal-scope.ts +66 -0
  89. package/src/runtime/vue/useProvidersPanel.ts +930 -0
@@ -0,0 +1,203 @@
1
+ /**
2
+ * The providers panel's vocabulary: the types the panel and its composable
3
+ * share, the constants of its form, and the pure reference / error helpers.
4
+ * No Vue, no requests — testable on their own. The public types and constants
5
+ * are re-exported by `useProvidersPanel`; the rest is internal to the package.
6
+ */
7
+
8
+ import type { EnvLayerId } from "../shared/env-vars";
9
+ import type {
10
+ AIProviderCredentialKind,
11
+ AIProviderKind,
12
+ AIProviderSurface,
13
+ } from "../shared/provider-registry";
14
+
15
+ /** Registry document a provider entry is defined in. */
16
+ export type ProvidersPanelLayer = "instance" | "workspace";
17
+
18
+ /** Props both `ForgeProvidersPanel` variants declare. */
19
+ export interface ProvidersPanelProps {
20
+ /** `GET` merged view for this scope (`/api/providers` | `/api/workspaces/:id/providers`). */
21
+ providersUrl: string;
22
+ /** `PUT|DELETE ${providersWriteUrl}/:id`; `GET ${providersWriteUrl}/detected`. */
23
+ providersWriteUrl: string;
24
+ /** Catalog preset summaries. Default `/api/providers/presets`. */
25
+ presetsUrl?: string;
26
+ /**
27
+ * The scope's `.env` route. `GET` on load and after every write; keys typed
28
+ * into the panel write through it. Omitted, no key can be entered.
29
+ */
30
+ environmentUrl?: string;
31
+ /** The scope's own registry document. */
32
+ layer: ProvidersPanelLayer;
33
+ /** Disables every write (non-admin at instance scope; provider lock). */
34
+ readOnly?: boolean;
35
+ }
36
+
37
+ /** Emits both variants declare. */
38
+ export type ProvidersPanelEmit = (event: "changed") => void;
39
+
40
+ /** One entry of `GET ${providersUrl}?all=1`. */
41
+ export interface ProvidersPanelEntry {
42
+ id: string;
43
+ /** The entry's label, else its id. */
44
+ name: string;
45
+ kind: AIProviderKind;
46
+ /** Whether the credential reference resolved on the server. */
47
+ configured: boolean;
48
+ /** Why it did not resolve. Secret-free. */
49
+ error?: string;
50
+ credentialRef?: string;
51
+ credentialKind?: AIProviderCredentialKind;
52
+ hasEnvKey: boolean;
53
+ envKeyName?: string;
54
+ baseUrl?: string;
55
+ preset?: string;
56
+ surface?: AIProviderSurface;
57
+ enabled: boolean;
58
+ locked: boolean;
59
+ /** Registry documents holding the id, lowest first: `["instance"]`, `["workspace"]` or both. */
60
+ layers: ProvidersPanelLayer[];
61
+ /** The scope's own document's values for the editable fields the dialog does not show. */
62
+ layerFields?: Record<string, unknown>;
63
+ }
64
+
65
+ /** One catalog preset, as `GET /api/providers/presets` and `.../detected` list it. */
66
+ export interface ProvidersPanelPreset {
67
+ id: string;
68
+ label: string;
69
+ kind: AIProviderKind;
70
+ surface?: AIProviderSurface;
71
+ base_url?: string;
72
+ base_url_env?: string;
73
+ credential: { kind: AIProviderCredentialKind; env?: string };
74
+ }
75
+
76
+ /** Where a row's entry lives relative to the scope's own document. */
77
+ export type ProvidersPanelRowState = "own" | "inherited" | "patched";
78
+
79
+ /** One entry of a row's credential select. */
80
+ export interface ProvidersPanelCredentialOption {
81
+ /** An env var NAME, a literal non-env ref, {@link CREDENTIAL_ENTER_KEY} or {@link CREDENTIAL_OTHER_REF}. */
82
+ value: string;
83
+ /** `NAME ••••hint` | `NAME (not set)` | the literal ref | `Enter a key…` | `Other reference…`. */
84
+ label: string;
85
+ defined?: boolean;
86
+ hint?: string;
87
+ source?: EnvLayerId;
88
+ action?: "enter-key" | "other-ref";
89
+ }
90
+
91
+ /** A table row: the entry plus what the panel derives for it. */
92
+ export interface ProvidersPanelRow extends ProvidersPanelEntry {
93
+ /** Own entry, an inherited one, or an inherited one this scope patched. */
94
+ state: ProvidersPanelRowState;
95
+ /** `instance` | `workspace` | `instance · overridden here`. */
96
+ badge: string;
97
+ /** Set on inherited rows. */
98
+ inheritedNote?: string;
99
+ /** Edit/Delete offered: the scope's document defines it and the panel is writable. */
100
+ editable: boolean;
101
+ /** Reset offered: a patched row of a writable panel. */
102
+ canReset: boolean;
103
+ /** The enabled switch is live. */
104
+ canToggle: boolean;
105
+ /** The entry takes a credential (its kind is not `none`). */
106
+ needsCredential: boolean;
107
+ /** The credential picker is live. */
108
+ canEditCredential: boolean;
109
+ /** The select's model: the env var NAME of an `env:` ref, else the literal ref, else `""`. */
110
+ credentialValue: string;
111
+ credentialOptions: ProvidersPanelCredentialOption[];
112
+ /** The preset it inherits, else its surface, else its kind. */
113
+ origin: string;
114
+ /** `configured · <source>`, `missing <VAR>`, the resolver's reason, or `No credential needed.`. */
115
+ status: string;
116
+ /** Which other layer defines or overrides the credential; see the panel contract. */
117
+ overrideNotices: string[];
118
+ }
119
+
120
+ /** The add/edit dialog's fields. */
121
+ export interface ProvidersPanelForm {
122
+ /** A preset id, or {@link CUSTOM_PRESET}. */
123
+ preset: string;
124
+ id: string;
125
+ /** Custom entries only. */
126
+ surface: string;
127
+ /** Empty: the preset's endpoint. */
128
+ baseUrl: string;
129
+ /** Adding only: the `env:` variable the credential references. */
130
+ envName: string;
131
+ /** Adding only, "Set value now": written to the scope's `.env`, never to the provider route. */
132
+ secret: string;
133
+ }
134
+
135
+ // ── Constants ─────────────────────────────────────────────────────────────────
136
+
137
+ /** The preset select's value for an entry that names no preset. */
138
+ export const CUSTOM_PRESET = "__custom__";
139
+
140
+ /** Credential select value: open the inline key editor. */
141
+ export const CREDENTIAL_ENTER_KEY = "__enter_key__";
142
+
143
+ /** Credential select value: open the inline reference editor. */
144
+ export const CREDENTIAL_OTHER_REF = "__other_ref__";
145
+
146
+ /** Registry ids the write routes accept (`isSafeProviderId` upstream). */
147
+ export const PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
148
+
149
+ export const DEFAULT_PRESETS_URL = "/api/providers/presets";
150
+
151
+ /** An `env:NAME` credential reference; group 1 is the variable name. */
152
+ export const ENV_REF_PATTERN = /^env:(.+)$/;
153
+
154
+ /** The credential kind a written reference gets when the row states none. */
155
+ export const FALLBACK_CREDENTIAL_KIND: AIProviderCredentialKind = "api_key_header";
156
+
157
+ export const ENV_SOURCE_LABEL: Record<EnvLayerId, string> = {
158
+ instance: "instance .env",
159
+ workspace: "workspace .env",
160
+ process: "boot environment",
161
+ };
162
+
163
+ export const OVERRIDES_INSTANCE_NOTICE =
164
+ "Entering a key here stores it in this workspace's .env and overrides that value for this workspace.";
165
+
166
+ /**
167
+ * The server's refusal for a failed request, else `fallback`. A registry
168
+ * rejection (`400` with `data.diagnostics`) reads as its diagnostics' messages.
169
+ */
170
+ export function requestErrorMessage(err: unknown, fallback: string): string {
171
+ const e = err as {
172
+ data?: { statusMessage?: unknown; data?: { diagnostics?: Array<{ message?: unknown }> } };
173
+ statusMessage?: unknown;
174
+ } | null;
175
+ const details = (e?.data?.data?.diagnostics ?? [])
176
+ .map((d) => d.message)
177
+ .filter((m): m is string => typeof m === "string" && m !== "");
178
+ if (details.length > 0) return details.join("; ");
179
+ const message = e?.data?.statusMessage ?? e?.statusMessage;
180
+ return typeof message === "string" && message ? message : fallback;
181
+ }
182
+
183
+ /** The variable name of an `env:NAME` reference. */
184
+ export function envNameOfRef(ref: string | undefined): string | undefined {
185
+ return ref ? ENV_REF_PATTERN.exec(ref)?.[1] : undefined;
186
+ }
187
+
188
+ /** `configured · …` for a reference that is not an env var. */
189
+ export function nonEnvSourceLabel(ref: string): string | undefined {
190
+ if (ref.startsWith("keyring:")) return "keyring";
191
+ if (ref.startsWith("cmd:")) return "runtime-owned (cmd)";
192
+ if (ref.startsWith("platform:")) return "control-plane-owned (platform)";
193
+ return undefined;
194
+ }
195
+
196
+ export const EMPTY_FORM: Readonly<ProvidersPanelForm> = {
197
+ preset: "",
198
+ id: "",
199
+ surface: "",
200
+ baseUrl: "",
201
+ envName: "",
202
+ secret: "",
203
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The tier a settings modal edits, and the URLs of its routes.
3
+ *
4
+ * The URL protocol is the host's: every field names a route the host serves,
5
+ * and no component builds a URL from an id or a slug. `ForgeProvidersPanel`
6
+ * takes the `providers*` / `environmentUrl` / `providersLayer` fields of this
7
+ * record as its props; the rest belong to the host's own modal tabs (harness,
8
+ * voice, workspace), which stay in the host.
9
+ */
10
+
11
+ /** Which settings tier a modal edits. */
12
+ export type SettingsModalSettingsScope = "instance" | "workspace";
13
+
14
+ /**
15
+ * The tier the modal edits: the instance (app-wide defaults) or one
16
+ * workspace. The caller owns every route: the modal never builds a URL from an
17
+ * id or slug.
18
+ */
19
+ export interface SettingsModalScope {
20
+ /** Dialog header text, e.g. the workspace name. */
21
+ label: string;
22
+ /**
23
+ * `"instance"`: the Harness tab edits the instance defaults
24
+ * (`PUT /api/settings?scope=instance`); `"workspace"`: it edits this
25
+ * workspace's overrides through {@link settingsUrl}.
26
+ */
27
+ settingsScope: SettingsModalSettingsScope;
28
+ /**
29
+ * `GET`/`PUT` endpoint of this scope's settings: `/api/settings` for the
30
+ * instance, the workspace's override row (`{ harness, model }`) otherwise.
31
+ */
32
+ settingsUrl: string;
33
+ /** Base URL for the Workspace + Connectors tabs' config API calls. */
34
+ workspaceApiBaseUrl: string;
35
+ /** `GET` model catalog of this scope's registry, queried with `?harness=<id>`. */
36
+ modelsUrl: string;
37
+ /** Provider registry write base: `PUT|DELETE <url>/:id`, `GET <url>/detected`. */
38
+ providersWriteUrl: string;
39
+ /**
40
+ * `GET` endpoint of this scope's `.env` layer, which the Providers tab reads and
41
+ * writes. Defaults to the instance layer, `/api/settings/env`.
42
+ */
43
+ environmentUrl?: string;
44
+ /**
45
+ * `GET` endpoint listing registry entries with their credential status
46
+ * resolved against this scope's environment. Defaults to `/api/providers`.
47
+ */
48
+ providersUrl?: string;
49
+ /**
50
+ * The registry document the Providers tab edits, when it differs from
51
+ * {@link settingsScope}. A single-workspace app keeps instance settings but
52
+ * writes the workspace registry over a user-level one: `"workspace"` there
53
+ * makes the lower document's entries inherited and patchable.
54
+ */
55
+ providersLayer?: SettingsModalSettingsScope;
56
+ /** Workspace name for workspace-scope copy (the harness-change confirm); defaults to {@link label}. */
57
+ workspaceName?: string;
58
+ /** The caller may read but not write this scope (e.g. a `readonly` user, another owner's workspace). */
59
+ readOnly?: boolean;
60
+ }
61
+
62
+ /** Default `GET` route of the merged provider list. */
63
+ export const DEFAULT_PROVIDERS_URL = "/api/providers";
64
+
65
+ /** Default `GET`/`PUT` route of the instance `.env` layer. */
66
+ export const DEFAULT_ENVIRONMENT_URL = "/api/settings/env";