@stigmer/sdk 3.12.4 → 3.12.5

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 (59) hide show
  1. package/__tests__/mcpserver-connect.test.d.ts +2 -0
  2. package/__tests__/mcpserver-connect.test.d.ts.map +1 -0
  3. package/__tests__/mcpserver-connect.test.js +146 -0
  4. package/__tests__/mcpserver-connect.test.js.map +1 -0
  5. package/__tests__/update-input.test.d.ts +2 -0
  6. package/__tests__/update-input.test.d.ts.map +1 -0
  7. package/__tests__/update-input.test.js +169 -0
  8. package/__tests__/update-input.test.js.map +1 -0
  9. package/gen/agentexecution.d.ts +6 -0
  10. package/gen/agentexecution.d.ts.map +1 -1
  11. package/gen/agentexecution.js +9 -1
  12. package/gen/agentexecution.js.map +1 -1
  13. package/gen/client.d.ts +3 -3
  14. package/gen/client.d.ts.map +1 -1
  15. package/gen/identityaccount.d.ts +8 -0
  16. package/gen/identityaccount.d.ts.map +1 -1
  17. package/gen/identityaccount.js +11 -1
  18. package/gen/identityaccount.js.map +1 -1
  19. package/gen/mcpserver.d.ts +1 -0
  20. package/gen/mcpserver.d.ts.map +1 -1
  21. package/gen/mcpserver.js +8 -0
  22. package/gen/mcpserver.js.map +1 -1
  23. package/gen/oauthapp.d.ts +2 -1
  24. package/gen/oauthapp.d.ts.map +1 -1
  25. package/gen/oauthapp.js +1 -0
  26. package/gen/oauthapp.js.map +1 -1
  27. package/gen/organization.d.ts +5 -0
  28. package/gen/organization.d.ts.map +1 -1
  29. package/gen/organization.js +8 -1
  30. package/gen/organization.js.map +1 -1
  31. package/gen/platformclient.d.ts +1 -0
  32. package/gen/platformclient.d.ts.map +1 -1
  33. package/gen/platformclient.js +2 -0
  34. package/gen/platformclient.js.map +1 -1
  35. package/index.d.ts +2 -0
  36. package/index.d.ts.map +1 -1
  37. package/index.js +3 -0
  38. package/index.js.map +1 -1
  39. package/mcpserver-connect.d.ts +79 -0
  40. package/mcpserver-connect.d.ts.map +1 -0
  41. package/mcpserver-connect.js +114 -0
  42. package/mcpserver-connect.js.map +1 -0
  43. package/package.json +2 -2
  44. package/src/__tests__/mcpserver-connect.test.ts +181 -0
  45. package/src/__tests__/update-input.test.ts +219 -0
  46. package/src/gen/agentexecution.ts +17 -1
  47. package/src/gen/client.ts +3 -3
  48. package/src/gen/identityaccount.ts +21 -1
  49. package/src/gen/mcpserver.ts +6 -0
  50. package/src/gen/oauthapp.ts +3 -1
  51. package/src/gen/organization.ts +15 -1
  52. package/src/gen/platformclient.ts +3 -0
  53. package/src/index.ts +14 -0
  54. package/src/mcpserver-connect.ts +159 -0
  55. package/src/update-input.ts +168 -0
  56. package/update-input.d.ts +24 -0
  57. package/update-input.d.ts.map +1 -0
  58. package/update-input.js +126 -0
  59. package/update-input.js.map +1 -0
@@ -0,0 +1,159 @@
1
+ import { Code, ConnectError } from "@connectrpc/connect";
2
+ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
3
+ import type { ConnectInput } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
4
+ import { ConnectPhase } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/status_pb";
5
+ import { isUnimplemented, wrapError } from "./gen/errors.js";
6
+
7
+ /**
8
+ * The slice of {@link McpServerClient} the connect protocol needs — the
9
+ * async-lane pair plus the blocking fallback. Structural on purpose: the
10
+ * full client satisfies it, and tests can hand in three functions.
11
+ */
12
+ export interface McpServerConnectLane {
13
+ startConnect(input: ConnectInput): Promise<McpServer>;
14
+ connect(input: ConnectInput): Promise<McpServer>;
15
+ get(id: string): Promise<McpServer>;
16
+ }
17
+
18
+ /**
19
+ * How often {@link connectAndWait} re-reads the resource while a connect
20
+ * operation runs. Discovery legitimately takes tens of seconds to minutes;
21
+ * a few seconds of staleness is invisible next to that, and each poll is
22
+ * one cheap get.
23
+ */
24
+ export const CONNECT_POLL_INTERVAL_MS = 2_500;
25
+
26
+ /**
27
+ * Absolute bound on waiting for a connect to settle: the backend's async
28
+ * connect ceiling (its asyncConnectTimeout, 60 min) plus margin. Every
29
+ * operation settles within the ceiling by construction; only a
30
+ * connect_status orphaned by a backend restart can still read CONNECTING
31
+ * past it, and this bound turns that into a typed error instead of an
32
+ * infinite wait.
33
+ */
34
+ export const CONNECT_SETTLE_BOUND_MS = 65 * 60_000;
35
+
36
+ /**
37
+ * Thrown by {@link connectAndWait} when it stopped waiting while the
38
+ * server-side operation was still running. NOT a failure: the backend
39
+ * finishes the connect on its own and persists the result — re-read the
40
+ * resource (or re-run the connect) to observe the outcome.
41
+ */
42
+ export class ConnectStillRunningError extends Error {
43
+ readonly mcpServerId: string;
44
+
45
+ constructor(mcpServerId: string, waitedMs: number) {
46
+ super(
47
+ `the connect of MCP server '${mcpServerId}' is still running server-side after ${Math.round(waitedMs / 1000)}s — ` +
48
+ "it will persist its result on its own; re-read the server to observe the outcome",
49
+ );
50
+ this.name = "ConnectStillRunningError";
51
+ this.mcpServerId = mcpServerId;
52
+ }
53
+ }
54
+
55
+ /** Options for {@link connectAndWait}. */
56
+ export interface ConnectAndWaitOptions {
57
+ /** Poll cadence. Defaults to {@link CONNECT_POLL_INTERVAL_MS}. */
58
+ readonly pollIntervalMs?: number;
59
+ /**
60
+ * Stop waiting after this long (soft bound — the server-side operation
61
+ * keeps running). Defaults to {@link CONNECT_SETTLE_BOUND_MS}, and is
62
+ * capped by it: waiting longer than the backend's own ceiling can only
63
+ * ever observe an orphaned record.
64
+ */
65
+ readonly deadlineMs?: number;
66
+ /**
67
+ * Observe the CONNECTING snapshot the moment the operation is accepted —
68
+ * the place to read `status.connect_status.warning` (the dead-runner
69
+ * advisory) before the wait begins. Not called on the blocking fallback,
70
+ * which has no start-time snapshot.
71
+ */
72
+ readonly onStarted?: (started: McpServer) => void;
73
+ }
74
+
75
+ /**
76
+ * Connect an MCP server and wait for the operation to settle, without any
77
+ * long-lived RPC (stigmer/stigmer#425).
78
+ *
79
+ * Uses the async lane — `startConnect` returns immediately with
80
+ * `status.connect_status = CONNECTING`, then the resource is polled until
81
+ * the operation settles — so the wait survives transport limits that kill
82
+ * a long-blocking unary call (browsers drop no-bytes responses around
83
+ * ~300s, below the server's discovery ceiling). Callers never see the
84
+ * mechanics: the promise resolves with the updated server exactly as the
85
+ * blocking `connect` RPC resolved, and a failed operation rejects with the
86
+ * same {@link StigmerError} classification the blocking RPC would have
87
+ * thrown (`connect_status.failure_code` is the Go gRPC code name, which
88
+ * matches connect-es `Code` member names — rehydration is lossless).
89
+ *
90
+ * Backends that predate the async lane answer UNIMPLEMENTED for
91
+ * `startConnect`; this falls back to the blocking `connect` RPC — the same
92
+ * edition capability-probe idiom as the skill artifact-transfer lane
93
+ * (skill.ts) and the org-OAuth-app surface.
94
+ */
95
+ export async function connectAndWait(
96
+ client: McpServerConnectLane,
97
+ input: ConnectInput,
98
+ options?: ConnectAndWaitOptions,
99
+ ): Promise<McpServer> {
100
+ const pollIntervalMs = options?.pollIntervalMs ?? CONNECT_POLL_INTERVAL_MS;
101
+ const waitMs = Math.min(options?.deadlineMs ?? CONNECT_SETTLE_BOUND_MS, CONNECT_SETTLE_BOUND_MS);
102
+
103
+ let started: McpServer;
104
+ try {
105
+ started = await client.startConnect(input);
106
+ } catch (err) {
107
+ if (!isUnimplemented(err)) throw err;
108
+ return blockingConnect(client, input, waitMs);
109
+ }
110
+ options?.onStarted?.(started);
111
+
112
+ const deadline = Date.now() + waitMs;
113
+ for (;;) {
114
+ if (Date.now() >= deadline) {
115
+ throw new ConnectStillRunningError(input.mcpServerId, waitMs);
116
+ }
117
+ await sleep(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
118
+
119
+ const current = await client.get(input.mcpServerId);
120
+ const cs = current.status?.connectStatus;
121
+ if (cs?.phase === ConnectPhase.succeeded) return current;
122
+ if (cs?.phase === ConnectPhase.failed) {
123
+ throw rehydrateConnectFailure(cs.failureCode, cs.failureMessage);
124
+ }
125
+ }
126
+ }
127
+
128
+ // The pre-async-lane path, kept behaviorally identical for old backends: one
129
+ // blocking RPC, raced (not cancelled — the server finishes and persists on
130
+ // its own) against the caller's soft bound.
131
+ async function blockingConnect(client: McpServerConnectLane, input: ConnectInput, waitMs: number): Promise<McpServer> {
132
+ const push = client.connect(input);
133
+ // The losing push may settle after the caller has moved on; swallow its
134
+ // late rejection so it cannot surface as an unhandled-rejection crash.
135
+ void push.catch(() => {});
136
+
137
+ let timer: ReturnType<typeof setTimeout> | undefined;
138
+ const timeout = new Promise<never>((_, reject) => {
139
+ timer = setTimeout(() => reject(new ConnectStillRunningError(input.mcpServerId, waitMs)), waitMs);
140
+ });
141
+ try {
142
+ return await Promise.race([push, timeout]);
143
+ } finally {
144
+ if (timer !== undefined) clearTimeout(timer);
145
+ }
146
+ }
147
+
148
+ // Rebuild the failure the blocking connect RPC would have thrown, from the
149
+ // classification the backend persisted on connect_status. Routing the
150
+ // rehydrated ConnectError through wrapError makes the result byte-identical
151
+ // to a live RPC failure (same StigmerError code mapping, same raw message).
152
+ function rehydrateConnectFailure(failureCode: string, failureMessage: string) {
153
+ const code = (Code as Record<string, unknown>)[failureCode];
154
+ return wrapError(new ConnectError(failureMessage, typeof code === "number" ? (code as Code) : Code.Unknown));
155
+ }
156
+
157
+ function sleep(ms: number): Promise<void> {
158
+ return new Promise((resolve) => setTimeout(resolve, ms));
159
+ }
@@ -0,0 +1,168 @@
1
+ // Complete update-input mappers.
2
+ //
3
+ // The platform's update RPCs are FULL-SPEC REPLACEMENTS: the request spec
4
+ // wholesale overwrites the stored spec (both editions; only a small
5
+ // server-side preserve list of immutable identifiers survives). A client
6
+ // that sends only the fields it edits therefore silently WIPES every other
7
+ // mutable spec field — a data-loss bug class, not a single bug
8
+ // (stigmer/stigmer#293 Phase 1 surfaced it when `spec.preferences` set via
9
+ // CLI was dropped by a console profile save).
10
+ //
11
+ // These mappers are the structural fix: they convert a LOADED resource into
12
+ // a complete `*Input` for the generated update builders. Editors spread the
13
+ // mapper output and override only the fields they edit:
14
+ //
15
+ // await update({ ...toOrganizationUpdateInput(org), description: next });
16
+ //
17
+ // The `CompleteInput` mapped type removes optionality from every Input key,
18
+ // so when codegen adds a new Input field, compilation fails HERE — the one
19
+ // place a human must decide how the new field round-trips — instead of the
20
+ // field silently wiping in every subset-editing form.
21
+ //
22
+ // NESTED MESSAGE RULE: `CompleteInput` only sees TOP-LEVEL keys — a nested
23
+ // message (e.g. `preferences`) is one key whose object literal would keep
24
+ // compiling when codegen adds fields INSIDE it, recreating the wipe bug one
25
+ // level down. Every nested-message literal in this file must therefore be
26
+ // built by a dedicated `toXxxInput` helper whose return literal is itself
27
+ // typed `CompleteInput<XxxInput>`. Editors that override a nested message
28
+ // must spread the mapper's complete value and override only their fields:
29
+ //
30
+ // preferences: { ...mapped.preferences, standingContext: next }
31
+
32
+ import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
33
+ import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
34
+ import type { IdentityAccountPreferences } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/spec_pb";
35
+ import type { Organization } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
36
+ import type { OrganizationPreferences } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/spec_pb";
37
+ import type {
38
+ IdentityAccountInput,
39
+ IdentityAccountPreferencesInput,
40
+ } from "./gen/identityaccount.js";
41
+ import type {
42
+ OrganizationInput,
43
+ OrganizationPreferencesInput,
44
+ } from "./gen/organization.js";
45
+ import type { ResourceRef } from "./gen/types.js";
46
+
47
+ /**
48
+ * Every key of `T`, required to be present. Optional keys keep their
49
+ * `| undefined` value type (explicit `undefined` is stripped by the proto
50
+ * builders), so a mapper cannot compile while omitting an Input field.
51
+ *
52
+ * Mapping over `keyof Required<T>` (instead of a homomorphic `-?` map)
53
+ * is deliberate: `-?` would also strip `undefined` from optional value
54
+ * types, forcing fake values for genuinely absent fields.
55
+ */
56
+ type CompleteInput<T> = { [K in keyof Required<T>]: T[K] };
57
+
58
+ /**
59
+ * Maps a loaded {@link Organization} to a complete {@link OrganizationInput}
60
+ * for `organization.update()`.
61
+ *
62
+ * Proto3 scalar defaults (empty string, `false`, enum `0`) are normalized to
63
+ * `undefined` — omitting them is wire-identical to sending the default, and
64
+ * it keeps the built proto in the builders' canonical shape.
65
+ */
66
+ export function toOrganizationUpdateInput(
67
+ org: Organization,
68
+ ): OrganizationInput {
69
+ const input: CompleteInput<OrganizationInput> = {
70
+ name: org.metadata?.name ?? "",
71
+ slug: org.metadata?.slug || undefined,
72
+ org: org.metadata?.org || org.metadata?.slug || "",
73
+ labels: nonEmptyLabels(org.metadata?.labels),
74
+ visibility: org.metadata?.visibility || undefined,
75
+ description: org.spec?.description || undefined,
76
+ logoUrl: org.spec?.logoUrl || undefined,
77
+ managementMode: org.spec?.managementMode || undefined,
78
+ identityProviderRef: toResourceRef(org.spec?.identityProviderRef),
79
+ externalOrgId: org.spec?.externalOrgId || undefined,
80
+ isPersonal: org.spec?.isPersonal || undefined,
81
+ preferences: org.spec?.preferences
82
+ ? toOrganizationPreferencesInput(org.spec.preferences)
83
+ : undefined,
84
+ };
85
+ return input;
86
+ }
87
+
88
+ /**
89
+ * Maps loaded {@link OrganizationPreferences} to a complete
90
+ * {@link OrganizationPreferencesInput} (nested-message rule above).
91
+ */
92
+ function toOrganizationPreferencesInput(
93
+ preferences: OrganizationPreferences,
94
+ ): OrganizationPreferencesInput {
95
+ const input: CompleteInput<OrganizationPreferencesInput> = {
96
+ standingContext: preferences.standingContext || undefined,
97
+ };
98
+ return input;
99
+ }
100
+
101
+ /**
102
+ * Maps a loaded {@link IdentityAccount} to a complete
103
+ * {@link IdentityAccountInput} for `identityAccount.update()`.
104
+ *
105
+ * The generated builder never sets `metadata.id`; the update pipeline
106
+ * locates the resource by org + slug instead (and authorizes against the
107
+ * loaded resource's id), so carrying `org` and `slug` here is what makes
108
+ * the update addressable.
109
+ */
110
+ export function toIdentityAccountUpdateInput(
111
+ account: IdentityAccount,
112
+ ): IdentityAccountInput {
113
+ const input: CompleteInput<IdentityAccountInput> = {
114
+ name: account.metadata?.name ?? "",
115
+ slug: account.metadata?.slug || undefined,
116
+ org: account.metadata?.org ?? "",
117
+ labels: nonEmptyLabels(account.metadata?.labels),
118
+ visibility: account.metadata?.visibility || undefined,
119
+ idpId: account.spec?.idpId ?? "",
120
+ email: account.spec?.email || undefined,
121
+ firstName: account.spec?.firstName || undefined,
122
+ lastName: account.spec?.lastName || undefined,
123
+ pictureUrl: account.spec?.pictureUrl || undefined,
124
+ isMachineAccount: account.spec?.isMachineAccount || undefined,
125
+ provisioningMode: account.spec?.provisioningMode || undefined,
126
+ identityProviderRef: toResourceRef(account.spec?.identityProviderRef),
127
+ preferences: account.spec?.preferences
128
+ ? toIdentityAccountPreferencesInput(account.spec.preferences)
129
+ : undefined,
130
+ };
131
+ return input;
132
+ }
133
+
134
+ /**
135
+ * Maps loaded {@link IdentityAccountPreferences} to a complete
136
+ * {@link IdentityAccountPreferencesInput} (nested-message rule above).
137
+ */
138
+ function toIdentityAccountPreferencesInput(
139
+ preferences: IdentityAccountPreferences,
140
+ ): IdentityAccountPreferencesInput {
141
+ const input: CompleteInput<IdentityAccountPreferencesInput> = {
142
+ standingContext: preferences.standingContext || undefined,
143
+ defaultHarness: preferences.defaultHarness || undefined,
144
+ defaultNativeModel: preferences.defaultNativeModel || undefined,
145
+ defaultCursorModel: preferences.defaultCursorModel || undefined,
146
+ };
147
+ return input;
148
+ }
149
+
150
+ function nonEmptyLabels(
151
+ labels: Record<string, string> | undefined,
152
+ ): Record<string, string> | undefined {
153
+ return labels && Object.keys(labels).length > 0 ? labels : undefined;
154
+ }
155
+
156
+ function toResourceRef(
157
+ ref: ApiResourceReference | undefined,
158
+ ): ResourceRef | undefined {
159
+ // The builders treat a ref without org and slug as absent; mirror that so
160
+ // an empty message round-trips to "no reference".
161
+ if (!ref || (!ref.org && !ref.slug)) return undefined;
162
+ return {
163
+ org: ref.org,
164
+ slug: ref.slug,
165
+ ...(ref.version && { version: ref.version }),
166
+ ...(ref.kind && { kind: ref.kind }),
167
+ };
168
+ }
@@ -0,0 +1,24 @@
1
+ import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
2
+ import type { Organization } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
3
+ import type { IdentityAccountInput } from "./gen/identityaccount.js";
4
+ import type { OrganizationInput } from "./gen/organization.js";
5
+ /**
6
+ * Maps a loaded {@link Organization} to a complete {@link OrganizationInput}
7
+ * for `organization.update()`.
8
+ *
9
+ * Proto3 scalar defaults (empty string, `false`, enum `0`) are normalized to
10
+ * `undefined` — omitting them is wire-identical to sending the default, and
11
+ * it keeps the built proto in the builders' canonical shape.
12
+ */
13
+ export declare function toOrganizationUpdateInput(org: Organization): OrganizationInput;
14
+ /**
15
+ * Maps a loaded {@link IdentityAccount} to a complete
16
+ * {@link IdentityAccountInput} for `identityAccount.update()`.
17
+ *
18
+ * The generated builder never sets `metadata.id`; the update pipeline
19
+ * locates the resource by org + slug instead (and authorizes against the
20
+ * loaded resource's id), so carrying `org` and `slug` here is what makes
21
+ * the update addressable.
22
+ */
23
+ export declare function toIdentityAccountUpdateInput(account: IdentityAccount): IdentityAccountInput;
24
+ //# sourceMappingURL=update-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-input.d.ts","sourceRoot":"","sources":["../src/update-input.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAEhG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2DAA2D,CAAC;AAE9F,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,uBAAuB,CAAC;AAc/B;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,YAAY,GAChB,iBAAiB,CAkBnB;AAeD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,eAAe,GACvB,oBAAoB,CAoBtB"}
@@ -0,0 +1,126 @@
1
+ // Complete update-input mappers.
2
+ //
3
+ // The platform's update RPCs are FULL-SPEC REPLACEMENTS: the request spec
4
+ // wholesale overwrites the stored spec (both editions; only a small
5
+ // server-side preserve list of immutable identifiers survives). A client
6
+ // that sends only the fields it edits therefore silently WIPES every other
7
+ // mutable spec field — a data-loss bug class, not a single bug
8
+ // (stigmer/stigmer#293 Phase 1 surfaced it when `spec.preferences` set via
9
+ // CLI was dropped by a console profile save).
10
+ //
11
+ // These mappers are the structural fix: they convert a LOADED resource into
12
+ // a complete `*Input` for the generated update builders. Editors spread the
13
+ // mapper output and override only the fields they edit:
14
+ //
15
+ // await update({ ...toOrganizationUpdateInput(org), description: next });
16
+ //
17
+ // The `CompleteInput` mapped type removes optionality from every Input key,
18
+ // so when codegen adds a new Input field, compilation fails HERE — the one
19
+ // place a human must decide how the new field round-trips — instead of the
20
+ // field silently wiping in every subset-editing form.
21
+ //
22
+ // NESTED MESSAGE RULE: `CompleteInput` only sees TOP-LEVEL keys — a nested
23
+ // message (e.g. `preferences`) is one key whose object literal would keep
24
+ // compiling when codegen adds fields INSIDE it, recreating the wipe bug one
25
+ // level down. Every nested-message literal in this file must therefore be
26
+ // built by a dedicated `toXxxInput` helper whose return literal is itself
27
+ // typed `CompleteInput<XxxInput>`. Editors that override a nested message
28
+ // must spread the mapper's complete value and override only their fields:
29
+ //
30
+ // preferences: { ...mapped.preferences, standingContext: next }
31
+ /**
32
+ * Maps a loaded {@link Organization} to a complete {@link OrganizationInput}
33
+ * for `organization.update()`.
34
+ *
35
+ * Proto3 scalar defaults (empty string, `false`, enum `0`) are normalized to
36
+ * `undefined` — omitting them is wire-identical to sending the default, and
37
+ * it keeps the built proto in the builders' canonical shape.
38
+ */
39
+ export function toOrganizationUpdateInput(org) {
40
+ const input = {
41
+ name: org.metadata?.name ?? "",
42
+ slug: org.metadata?.slug || undefined,
43
+ org: org.metadata?.org || org.metadata?.slug || "",
44
+ labels: nonEmptyLabels(org.metadata?.labels),
45
+ visibility: org.metadata?.visibility || undefined,
46
+ description: org.spec?.description || undefined,
47
+ logoUrl: org.spec?.logoUrl || undefined,
48
+ managementMode: org.spec?.managementMode || undefined,
49
+ identityProviderRef: toResourceRef(org.spec?.identityProviderRef),
50
+ externalOrgId: org.spec?.externalOrgId || undefined,
51
+ isPersonal: org.spec?.isPersonal || undefined,
52
+ preferences: org.spec?.preferences
53
+ ? toOrganizationPreferencesInput(org.spec.preferences)
54
+ : undefined,
55
+ };
56
+ return input;
57
+ }
58
+ /**
59
+ * Maps loaded {@link OrganizationPreferences} to a complete
60
+ * {@link OrganizationPreferencesInput} (nested-message rule above).
61
+ */
62
+ function toOrganizationPreferencesInput(preferences) {
63
+ const input = {
64
+ standingContext: preferences.standingContext || undefined,
65
+ };
66
+ return input;
67
+ }
68
+ /**
69
+ * Maps a loaded {@link IdentityAccount} to a complete
70
+ * {@link IdentityAccountInput} for `identityAccount.update()`.
71
+ *
72
+ * The generated builder never sets `metadata.id`; the update pipeline
73
+ * locates the resource by org + slug instead (and authorizes against the
74
+ * loaded resource's id), so carrying `org` and `slug` here is what makes
75
+ * the update addressable.
76
+ */
77
+ export function toIdentityAccountUpdateInput(account) {
78
+ const input = {
79
+ name: account.metadata?.name ?? "",
80
+ slug: account.metadata?.slug || undefined,
81
+ org: account.metadata?.org ?? "",
82
+ labels: nonEmptyLabels(account.metadata?.labels),
83
+ visibility: account.metadata?.visibility || undefined,
84
+ idpId: account.spec?.idpId ?? "",
85
+ email: account.spec?.email || undefined,
86
+ firstName: account.spec?.firstName || undefined,
87
+ lastName: account.spec?.lastName || undefined,
88
+ pictureUrl: account.spec?.pictureUrl || undefined,
89
+ isMachineAccount: account.spec?.isMachineAccount || undefined,
90
+ provisioningMode: account.spec?.provisioningMode || undefined,
91
+ identityProviderRef: toResourceRef(account.spec?.identityProviderRef),
92
+ preferences: account.spec?.preferences
93
+ ? toIdentityAccountPreferencesInput(account.spec.preferences)
94
+ : undefined,
95
+ };
96
+ return input;
97
+ }
98
+ /**
99
+ * Maps loaded {@link IdentityAccountPreferences} to a complete
100
+ * {@link IdentityAccountPreferencesInput} (nested-message rule above).
101
+ */
102
+ function toIdentityAccountPreferencesInput(preferences) {
103
+ const input = {
104
+ standingContext: preferences.standingContext || undefined,
105
+ defaultHarness: preferences.defaultHarness || undefined,
106
+ defaultNativeModel: preferences.defaultNativeModel || undefined,
107
+ defaultCursorModel: preferences.defaultCursorModel || undefined,
108
+ };
109
+ return input;
110
+ }
111
+ function nonEmptyLabels(labels) {
112
+ return labels && Object.keys(labels).length > 0 ? labels : undefined;
113
+ }
114
+ function toResourceRef(ref) {
115
+ // The builders treat a ref without org and slug as absent; mirror that so
116
+ // an empty message round-trips to "no reference".
117
+ if (!ref || (!ref.org && !ref.slug))
118
+ return undefined;
119
+ return {
120
+ org: ref.org,
121
+ slug: ref.slug,
122
+ ...(ref.version && { version: ref.version }),
123
+ ...(ref.kind && { kind: ref.kind }),
124
+ };
125
+ }
126
+ //# sourceMappingURL=update-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-input.js","sourceRoot":"","sources":["../src/update-input.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,EAAE;AACF,0EAA0E;AAC1E,oEAAoE;AACpE,yEAAyE;AACzE,2EAA2E;AAC3E,+DAA+D;AAC/D,2EAA2E;AAC3E,8CAA8C;AAC9C,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,wDAAwD;AACxD,EAAE;AACF,4EAA4E;AAC5E,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,sDAAsD;AACtD,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,4EAA4E;AAC5E,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,EAAE;AACF,kEAAkE;AA4BlE;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACvC,GAAiB;IAEjB,MAAM,KAAK,GAAqC;QAC9C,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;QAC9B,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS;QACrC,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;QAClD,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC5C,UAAU,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,IAAI,SAAS;QACjD,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,SAAS;QAC/C,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,SAAS;QACvC,cAAc,EAAE,GAAG,CAAC,IAAI,EAAE,cAAc,IAAI,SAAS;QACrD,mBAAmB,EAAE,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,mBAAmB,CAAC;QACjE,aAAa,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,IAAI,SAAS;QACnD,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;QAC7C,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW;YAChC,CAAC,CAAC,8BAA8B,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC;YACtD,CAAC,CAAC,SAAS;KACd,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,8BAA8B,CACrC,WAAoC;IAEpC,MAAM,KAAK,GAAgD;QACzD,eAAe,EAAE,WAAW,CAAC,eAAe,IAAI,SAAS;KAC1D,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAC1C,OAAwB;IAExB,MAAM,KAAK,GAAwC;QACjD,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;QAClC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,SAAS;QACzC,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE;QAChC,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC;QAChD,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,IAAI,SAAS;QACrD,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;QAChC,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI,SAAS;QACvC,SAAS,EAAE,OAAO,CAAC,IAAI,EAAE,SAAS,IAAI,SAAS;QAC/C,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,IAAI,SAAS;QAC7C,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,SAAS;QACjD,gBAAgB,EAAE,OAAO,CAAC,IAAI,EAAE,gBAAgB,IAAI,SAAS;QAC7D,gBAAgB,EAAE,OAAO,CAAC,IAAI,EAAE,gBAAgB,IAAI,SAAS;QAC7D,mBAAmB,EAAE,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC;QACrE,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,WAAW;YACpC,CAAC,CAAC,iCAAiC,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;YAC7D,CAAC,CAAC,SAAS;KACd,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,iCAAiC,CACxC,WAAuC;IAEvC,MAAM,KAAK,GAAmD;QAC5D,eAAe,EAAE,WAAW,CAAC,eAAe,IAAI,SAAS;QACzD,cAAc,EAAE,WAAW,CAAC,cAAc,IAAI,SAAS;QACvD,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,IAAI,SAAS;QAC/D,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,IAAI,SAAS;KAChE,CAAC;IACF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CACrB,MAA0C;IAE1C,OAAO,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CACpB,GAAqC;IAErC,0EAA0E;IAC1E,kDAAkD;IAClD,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAC5C,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;KACpC,CAAC;AACJ,CAAC"}