@uluops/ops-sdk 6.3.1 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +273 -2
  3. package/dist/client.d.ts +110 -3
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +94 -5
  6. package/dist/client.js.map +1 -1
  7. package/dist/config/constants.d.ts +1 -1
  8. package/dist/config/generated-version.d.ts +1 -1
  9. package/dist/config/generated-version.js +1 -1
  10. package/dist/config/validators.d.ts +25 -1
  11. package/dist/config/validators.d.ts.map +1 -1
  12. package/dist/config/validators.js +31 -1
  13. package/dist/config/validators.js.map +1 -1
  14. package/dist/config/workspace-org.d.ts +25 -4
  15. package/dist/config/workspace-org.d.ts.map +1 -1
  16. package/dist/config/workspace-org.js +71 -18
  17. package/dist/config/workspace-org.js.map +1 -1
  18. package/dist/errors/errors.d.ts +71 -0
  19. package/dist/errors/errors.d.ts.map +1 -1
  20. package/dist/errors/errors.js +99 -0
  21. package/dist/errors/errors.js.map +1 -1
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/operations/admin.d.ts +100 -0
  27. package/dist/operations/admin.d.ts.map +1 -0
  28. package/dist/operations/admin.js +130 -0
  29. package/dist/operations/admin.js.map +1 -0
  30. package/dist/operations/auth.d.ts +21 -1
  31. package/dist/operations/auth.d.ts.map +1 -1
  32. package/dist/operations/auth.js +49 -3
  33. package/dist/operations/auth.js.map +1 -1
  34. package/dist/operations/orgs.d.ts +45 -0
  35. package/dist/operations/orgs.d.ts.map +1 -0
  36. package/dist/operations/orgs.js +57 -0
  37. package/dist/operations/orgs.js.map +1 -0
  38. package/dist/operations/projects.d.ts +74 -0
  39. package/dist/operations/projects.d.ts.map +1 -1
  40. package/dist/operations/projects.js +115 -1
  41. package/dist/operations/projects.js.map +1 -1
  42. package/dist/types/auth.d.ts +10 -0
  43. package/dist/types/auth.d.ts.map +1 -1
  44. package/dist/types/index.d.ts +2 -0
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/types/index.js +2 -0
  47. package/dist/types/index.js.map +1 -1
  48. package/dist/types/log.d.ts +410 -0
  49. package/dist/types/log.d.ts.map +1 -0
  50. package/dist/types/log.js +191 -0
  51. package/dist/types/log.js.map +1 -0
  52. package/dist/types/rehome.d.ts +234 -0
  53. package/dist/types/rehome.d.ts.map +1 -0
  54. package/dist/types/rehome.js +171 -0
  55. package/dist/types/rehome.js.map +1 -0
  56. package/dist/types/response-schemas.d.ts +19 -0
  57. package/dist/types/response-schemas.d.ts.map +1 -1
  58. package/dist/types/response-schemas.js +19 -0
  59. package/dist/types/response-schemas.js.map +1 -1
  60. package/dist/types/schemas.d.ts +20 -0
  61. package/dist/types/schemas.d.ts.map +1 -1
  62. package/dist/types/schemas.js +22 -0
  63. package/dist/types/schemas.js.map +1 -1
  64. package/package.json +1 -1
@@ -100,4 +100,75 @@ export declare function isOrgAccessDeniedError(err: unknown): err is _SdkApiErro
100
100
  export declare function isProjectRehomedError(err: unknown): err is _SdkApiError & {
101
101
  details: ProjectRehomedDetails;
102
102
  };
103
+ /**
104
+ * 403 — the route is session-only (D20): platform-admin writes that mint or
105
+ * re-point identity, and the two cross-tenant project moves, refuse a `ulr_`
106
+ * key even when its user is a platform admin. Terminal for a key-authenticated
107
+ * client: log in (`OpsClient.login`, completing MFA with `loginWithTotp` if
108
+ * challenged) and retry with the session — never by minting another key.
109
+ */
110
+ export declare const SESSION_REQUIRED: "SESSION_REQUIRED";
111
+ /** 403 — the caller lacks the PLATFORM role (`users.role`) the admin path requires; distinct from the org-role codes above. */
112
+ export declare const INSUFFICIENT_ROLE: "INSUFFICIENT_ROLE";
113
+ /** Type guard: session-only route refused an API key (403 `SESSION_REQUIRED`). Terminal for key auth. */
114
+ export declare function isSessionRequiredError(err: unknown): err is _SdkApiError;
115
+ /** Type guard: the caller's PLATFORM role is below what the admin path requires (403 `INSUFFICIENT_ROLE`). Terminal — no org argument changes it. */
116
+ export declare function isInsufficientRoleError(err: unknown): err is _SdkApiError;
117
+ /**
118
+ * The refusal reasons a re-home can answer with, as `details.reason` on a
119
+ * 400 (`VALIDATION_ERROR`) or 409 (`CONFLICT`). Enumerated here because the
120
+ * Phase 4 runbook (spec §4.7 item 3) assigns each a disposition, and a script
121
+ * that switches on a string it typed itself will misspell one:
122
+ *
123
+ * - `same_org` — already there. Idempotent re-run over a finished row; count as done.
124
+ * - `moved_during_request` / `deadlock_retry` / `concurrent_modification` — re-read and retry once.
125
+ * - `name_collision` / `soft_deleted_conflict` / `rehomed_away_conflict` — skip and report.
126
+ * - `export_in_progress` — an export job holds either org; wait, then retry.
127
+ * - `project_soft_deleted` / `project_has_no_org` — the source row is not movable as-is; stop and look.
128
+ */
129
+ export declare const REHOME_REFUSAL_REASONS: readonly ["same_org", "moved_during_request", "deadlock_retry", "concurrent_modification", "name_collision", "soft_deleted_conflict", "rehomed_away_conflict", "export_in_progress", "project_soft_deleted", "project_has_no_org"];
130
+ export type RehomeRefusalReason = (typeof REHOME_REFUSAL_REASONS)[number];
131
+ /**
132
+ * The re-home refusal reason carried by a rejection, or `null` when the error
133
+ * is not one of the enumerated re-home refusals (a 403 org code, a 402
134
+ * `PROJECT_LIMIT`, a network failure). Reads `details.reason`; an unknown
135
+ * reason string returns null rather than a widened type — a new server reason
136
+ * should reach the caller as "not one I know", not as a silently-handled case.
137
+ *
138
+ * `null` therefore means "not a re-home refusal I can name", NOT "safe to
139
+ * retry": a `TimeoutError` / `NetworkError` after the server committed the
140
+ * move also reads `null`, and a blind retry on the admin path answers
141
+ * `same_org` (fine) while on the member path it answers 404 (see
142
+ * `projects.rehome`). Branch on `isTimeoutError` / `isNetworkError` first.
143
+ */
144
+ export declare function rehomeRefusalReason(err: unknown): RehomeRefusalReason | null;
145
+ /**
146
+ * Thrown by `OpsClient.login` / `auth.login` when the account has MFA enabled:
147
+ * the API answers `200 { mfa_required: true, mfa_challenge_token, ... }` and no
148
+ * session. Until 6.4.0 this surfaced as a raw `ZodError` on `sessionToken`,
149
+ * which made the SDK unable to log in ANY MFA account. Complete the login with
150
+ * `OpsClient.loginWithTotp(err.mfaChallengeToken, code)` before the challenge
151
+ * expires (`expiresAt`). WebAuthn completion is not offered by this SDK.
152
+ *
153
+ * **The token is single-use and is consumed before the code is verified** —
154
+ * a mistyped code burns it; do not loop on `loginWithTotp` with the same
155
+ * token, call `login()` again for a new challenge. And this error is raised
156
+ * only by `login()` / `auth.login()`: a client constructed with
157
+ * `{ email, password }` (or autoloaded credentials) logs in inside sdk-core,
158
+ * which cannot see the challenge and surfaces a generic `UnauthorizedError`
159
+ * — MFA accounts must use the two-step `login()` → `loginWithTotp()` path.
160
+ */
161
+ export declare class MfaRequiredError extends Error {
162
+ readonly name = "MfaRequiredError";
163
+ readonly mfaChallengeToken: string;
164
+ readonly expiresAt: string;
165
+ readonly mfaMethods: readonly string[];
166
+ constructor(challenge: {
167
+ mfaChallengeToken: string;
168
+ expiresAt: string;
169
+ mfaMethods: readonly string[];
170
+ });
171
+ }
172
+ /** Type guard for {@link MfaRequiredError}. */
173
+ export declare function isMfaRequiredError(err: unknown): err is MfaRequiredError;
103
174
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,WAAW,IAAI,WAAW,EAC1B,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,IAAI,aAAa,EAC9B,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,GAAG,uBAAuB,CAAC;IAC5E,kFAAkF;IAClF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;gBAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QACpC,MAAM,EAAE,cAAc,GAAG,eAAe,GAAG,uBAAuB,CAAC;QACnE,kBAAkB,EAAE,MAAM,CAAC;QAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,GAAG,EAAE,OAAO,CAAC;QACb,aAAa,EAAE,OAAO,CAAC;KACxB;CASF;AAMD,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEtE;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,EAAG,uBAAgC,CAAC;AACtE,sHAAsH;AACtH,eAAO,MAAM,iBAAiB,EAAG,mBAA4B,CAAC;AAC9D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAG,iBAA0B,CAAC;AAE1D,8EAA8E;AAC9E,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,+DAA+D;AAC/D,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAMD,8HAA8H;AAC9H,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,YAAY,GAAG;IAAE,OAAO,CAAC,EAAE,0BAA0B,CAAA;CAAE,CAEvH;AAED,oHAAoH;AACpH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,YAAY,CAExE;AAED,sHAAsH;AACtH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,YAAY,GAAG;IAAE,OAAO,EAAE,qBAAqB,CAAA;CAAE,CAI5G"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"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"}
@@ -95,4 +95,103 @@ export function isProjectRehomedError(err) {
95
95
  const d = err.details;
96
96
  return typeof d?.target_org?.slug === 'string' && typeof d.project_id === 'string';
97
97
  }
98
+ // ---------------------------------------------------------------------------
99
+ // Re-home surfaces (spec §4, 6.4.0)
100
+ // ---------------------------------------------------------------------------
101
+ /**
102
+ * 403 — the route is session-only (D20): platform-admin writes that mint or
103
+ * re-point identity, and the two cross-tenant project moves, refuse a `ulr_`
104
+ * key even when its user is a platform admin. Terminal for a key-authenticated
105
+ * client: log in (`OpsClient.login`, completing MFA with `loginWithTotp` if
106
+ * challenged) and retry with the session — never by minting another key.
107
+ */
108
+ export const SESSION_REQUIRED = 'SESSION_REQUIRED';
109
+ /** 403 — the caller lacks the PLATFORM role (`users.role`) the admin path requires; distinct from the org-role codes above. */
110
+ export const INSUFFICIENT_ROLE = 'INSUFFICIENT_ROLE';
111
+ /** Type guard: session-only route refused an API key (403 `SESSION_REQUIRED`). Terminal for key auth. */
112
+ export function isSessionRequiredError(err) {
113
+ return hasCode(err, SESSION_REQUIRED);
114
+ }
115
+ /** Type guard: the caller's PLATFORM role is below what the admin path requires (403 `INSUFFICIENT_ROLE`). Terminal — no org argument changes it. */
116
+ export function isInsufficientRoleError(err) {
117
+ return hasCode(err, INSUFFICIENT_ROLE);
118
+ }
119
+ /**
120
+ * The refusal reasons a re-home can answer with, as `details.reason` on a
121
+ * 400 (`VALIDATION_ERROR`) or 409 (`CONFLICT`). Enumerated here because the
122
+ * Phase 4 runbook (spec §4.7 item 3) assigns each a disposition, and a script
123
+ * that switches on a string it typed itself will misspell one:
124
+ *
125
+ * - `same_org` — already there. Idempotent re-run over a finished row; count as done.
126
+ * - `moved_during_request` / `deadlock_retry` / `concurrent_modification` — re-read and retry once.
127
+ * - `name_collision` / `soft_deleted_conflict` / `rehomed_away_conflict` — skip and report.
128
+ * - `export_in_progress` — an export job holds either org; wait, then retry.
129
+ * - `project_soft_deleted` / `project_has_no_org` — the source row is not movable as-is; stop and look.
130
+ */
131
+ export const REHOME_REFUSAL_REASONS = [
132
+ 'same_org',
133
+ 'moved_during_request',
134
+ 'deadlock_retry',
135
+ 'concurrent_modification',
136
+ 'name_collision',
137
+ 'soft_deleted_conflict',
138
+ 'rehomed_away_conflict',
139
+ 'export_in_progress',
140
+ 'project_soft_deleted',
141
+ 'project_has_no_org',
142
+ ];
143
+ /**
144
+ * The re-home refusal reason carried by a rejection, or `null` when the error
145
+ * is not one of the enumerated re-home refusals (a 403 org code, a 402
146
+ * `PROJECT_LIMIT`, a network failure). Reads `details.reason`; an unknown
147
+ * reason string returns null rather than a widened type — a new server reason
148
+ * should reach the caller as "not one I know", not as a silently-handled case.
149
+ *
150
+ * `null` therefore means "not a re-home refusal I can name", NOT "safe to
151
+ * retry": a `TimeoutError` / `NetworkError` after the server committed the
152
+ * move also reads `null`, and a blind retry on the admin path answers
153
+ * `same_org` (fine) while on the member path it answers 404 (see
154
+ * `projects.rehome`). Branch on `isTimeoutError` / `isNetworkError` first.
155
+ */
156
+ export function rehomeRefusalReason(err) {
157
+ if (!(err instanceof _SdkApiError))
158
+ return null;
159
+ const reason = err.details?.reason;
160
+ return typeof reason === 'string' && REHOME_REFUSAL_REASONS.includes(reason)
161
+ ? reason
162
+ : null;
163
+ }
164
+ /**
165
+ * Thrown by `OpsClient.login` / `auth.login` when the account has MFA enabled:
166
+ * the API answers `200 { mfa_required: true, mfa_challenge_token, ... }` and no
167
+ * session. Until 6.4.0 this surfaced as a raw `ZodError` on `sessionToken`,
168
+ * which made the SDK unable to log in ANY MFA account. Complete the login with
169
+ * `OpsClient.loginWithTotp(err.mfaChallengeToken, code)` before the challenge
170
+ * expires (`expiresAt`). WebAuthn completion is not offered by this SDK.
171
+ *
172
+ * **The token is single-use and is consumed before the code is verified** —
173
+ * a mistyped code burns it; do not loop on `loginWithTotp` with the same
174
+ * token, call `login()` again for a new challenge. And this error is raised
175
+ * only by `login()` / `auth.login()`: a client constructed with
176
+ * `{ email, password }` (or autoloaded credentials) logs in inside sdk-core,
177
+ * which cannot see the challenge and surfaces a generic `UnauthorizedError`
178
+ * — MFA accounts must use the two-step `login()` → `loginWithTotp()` path.
179
+ */
180
+ export class MfaRequiredError extends Error {
181
+ name = 'MfaRequiredError';
182
+ mfaChallengeToken;
183
+ expiresAt;
184
+ mfaMethods;
185
+ constructor(challenge) {
186
+ super(`Login requires a second factor (${challenge.mfaMethods.join(', ') || 'unknown method'}); ` +
187
+ 'complete it with loginWithTotp(mfaChallengeToken, code) before the challenge expires');
188
+ this.mfaChallengeToken = challenge.mfaChallengeToken;
189
+ this.expiresAt = challenge.expiresAt;
190
+ this.mfaMethods = challenge.mfaMethods;
191
+ }
192
+ }
193
+ /** Type guard for {@link MfaRequiredError}. */
194
+ export function isMfaRequiredError(err) {
195
+ return err instanceof MfaRequiredError;
196
+ }
98
197
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,WAAW,IAAI,WAAW,EAC1B,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,aAAa,IAAI,aAAa,EAC9B,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,sBAAsB;AACtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,mFAAmF;IAC1E,MAAM,CAA6D;IAC5E,kFAAkF;IACzE,kBAAkB,CAAS;IACpC,0EAA0E;IACjE,gBAAgB,CAAgB;IACzC,yEAAyE;IAChE,GAAG,CAAU;IACtB,qEAAqE;IAC5D,aAAa,CAAU;IAEhC,YAAY,OAAe,EAAE,OAM5B;QACC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACrD,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACjD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC7C,CAAC;CACF;AAED,8EAA8E;AAC9E,2DAA2D;AAC3D,8EAA8E;AAE9E,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAgC,CAAC;AACtE,sHAAsH;AACtH,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAA4B,CAAC;AAC9D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,iBAA0B,CAAC;AAoB1D,SAAS,OAAO,CAAC,GAAY,EAAE,IAAY;IACzC,OAAO,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC;AAC1D,CAAC;AAED,8HAA8H;AAC9H,MAAM,UAAU,0BAA0B,CAAC,GAAY;IACrD,OAAO,OAAO,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;AAC7C,CAAC;AAED,oHAAoH;AACpH,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,OAAO,OAAO,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;AACzC,CAAC;AAED,sHAAsH;AACtH,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAChD,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,CAAC,GAAG,GAAG,CAAC,OAAqD,CAAC;IACpE,OAAO,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC;AACrF,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors/errors.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * - Types: All domain interfaces (Run, Issue, AgentInput, SaveRunInput, etc.)
8
8
  * - Config: Credential loading and environment variable helpers
9
9
  */
10
- export { OpsClient, type OpsClientConfig } from './client.js';
10
+ export { OpsClient, type OpsClientConfig, type LoginOptions } from './client.js';
11
11
  export { OpsHttpClient, type HttpClientConfig, type QueryParams, type QueryParamValue } from './http/http-client.js';
12
12
  export type { SecurityEvent, SecurityEventType, SecurityEventHandler, AuthType, AuthFailureEvent, RedirectRejectedEvent, TokenRefreshFailedEvent, AuthStrategyReplacedEvent, } from './http/http-client.js';
13
13
  export { ApiKeyAuth, JwtSessionAuth, createAuthStrategy, type AuthStrategy, type AuthConfig } from './http/auth-strategy.js';
@@ -16,5 +16,5 @@ export * from './types/index.js';
16
16
  export { isValidMetric, ANALYTICS_METRICS, type AnalyticsMetric } from './operations/analytics.js';
17
17
  export { loadCredentials, loadConfig, loadEnvFiles, type Credentials, type SdkConfig } from './config/loaders.js';
18
18
  export { DEFAULT_BASE_URL, API_KEY_PREFIX, ENV_VARS } from './config/constants.js';
19
- export { resolveWorkspaceOrg, findWorkspaceOrgFile, readWorkspaceOrgFile, WORKSPACE_ORG_FILE, PERSONAL_ORG_SENTINEL, type WorkspaceOrgResolution, type WorkspaceOrgSource, type ResolveWorkspaceOrgOptions, } from './config/workspace-org.js';
19
+ export { resolveWorkspaceOrg, findWorkspaceOrgFile, readWorkspaceOrgFile, readWorkspaceFile, WORKSPACE_ORG_FILE, PERSONAL_ORG_SENTINEL, type WorkspaceFile, type WorkspaceOrgResolution, type WorkspaceOrgSource, type ResolveWorkspaceOrgOptions, } from './config/workspace-org.js';
20
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACrH,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG7H,cAAc,oBAAoB,CAAC;AAGnC,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGnG,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACrH,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG7H,cAAc,oBAAoB,CAAC;AAGnC,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGnG,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,GAChC,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -21,5 +21,5 @@ export { isValidMetric, ANALYTICS_METRICS } from './operations/analytics.js';
21
21
  // Config — credential loading from env vars, .env files, and ~/.uluops/credentials.json
22
22
  export { loadCredentials, loadConfig, loadEnvFiles } from './config/loaders.js';
23
23
  export { DEFAULT_BASE_URL, API_KEY_PREFIX, ENV_VARS } from './config/constants.js';
24
- export { resolveWorkspaceOrg, findWorkspaceOrgFile, readWorkspaceOrgFile, WORKSPACE_ORG_FILE, PERSONAL_ORG_SENTINEL, } from './config/workspace-org.js';
24
+ export { resolveWorkspaceOrg, findWorkspaceOrgFile, readWorkspaceOrgFile, readWorkspaceFile, WORKSPACE_ORG_FILE, PERSONAL_ORG_SENTINEL, } from './config/workspace-org.js';
25
25
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,2DAA2D;AAC3D,OAAO,EAAE,SAAS,EAAwB,MAAM,aAAa,CAAC;AAE9D,oFAAoF;AACpF,OAAO,EAAE,aAAa,EAAiE,MAAM,uBAAuB,CAAC;AAWrH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAsC,MAAM,yBAAyB,CAAC;AAE7H,0EAA0E;AAC1E,cAAc,oBAAoB,CAAC;AAEnC,gEAAgE;AAChE,cAAc,kBAAkB,CAAC;AAEjC,mEAAmE;AACnE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AAEnG,wFAAwF;AACxF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAoC,MAAM,qBAAqB,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,GAItB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,2DAA2D;AAC3D,OAAO,EAAE,SAAS,EAA2C,MAAM,aAAa,CAAC;AAEjF,oFAAoF;AACpF,OAAO,EAAE,aAAa,EAAiE,MAAM,uBAAuB,CAAC;AAWrH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAsC,MAAM,yBAAyB,CAAC;AAE7H,0EAA0E;AAC1E,cAAc,oBAAoB,CAAC;AAEnC,gEAAgE;AAChE,cAAc,kBAAkB,CAAC;AAEjC,mEAAmE;AACnE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AAEnG,wFAAwF;AACxF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAoC,MAAM,qBAAqB,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,GAKtB,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,100 @@
1
+ import type { OpsHttpClient } from '../http/http-client.js';
2
+ import type { AdminRehomeProjectInput, RehomeResponse, ProjectRehomeList, ProjectRehomeListQuery, ProjectRehomeEventList, ProjectRehomeEventListQuery } from '../types/rehome.js';
3
+ /**
4
+ * Platform-admin project re-home surface (project-org-routing-and-rehome spec
5
+ * §4.1 D8, §4.7, D20, D21). Every call here requires `users.role = 'admin'` —
6
+ * a PLATFORM role, not an org role — and the two writes additionally require
7
+ * a login-issued SESSION (D20): a `ulr_` key, even an admin's, gets
8
+ * `403 SESSION_REQUIRED` (`isSessionRequiredError`). Log in with
9
+ * `OpsClient.login` (completing MFA via `loginWithTotp` if challenged) and the
10
+ * session bearer is what these calls send. There is deliberately no MCP tool
11
+ * for any of this.
12
+ *
13
+ * `admin.` is a namespace, not an escalation: the same client, the same auth
14
+ * strategy. If the credential cannot do it the server says so.
15
+ */
16
+ /**
17
+ * Move ANY project between ANY two orgs — `POST /admin/projects/:id/rehome`.
18
+ * No source-membership and no target-membership requirement (the platform role
19
+ * is the authority), so `reason` is REQUIRED: on this path the target org's
20
+ * only standing is the `rehome_in` audit row plus that text. Resolves the
21
+ * project by id UNSCOPED (the admin router has no org context) — the route
22
+ * takes a UUID and answers 400 to anything else, so unlike `projects.*` a
23
+ * NAME is refused here, client-side, before the request.
24
+ *
25
+ * Session-only (D20). Phase 4 of the spec runs this once per row of the OQ-4
26
+ * table, sequentially, with the row reference as `reason`. On THIS path a
27
+ * re-run over a finished row answers `same_org` (the lookup is by id, so the
28
+ * moved project is found wherever it is) — read it as "already done" via
29
+ * `rehomeRefusalReason`. That is not true of the member path, whose lookup is
30
+ * source-scoped (see `projects.rehome`).
31
+ *
32
+ * @param client - HTTP client instance carrying a SESSION
33
+ * @param projectId - Project UUID (a name is an `InputValidationError`)
34
+ * @param input - `{ targetOrg, reason }` — both required
35
+ * @returns The project after the move (`orgId` is the target) plus the `rehome` block
36
+ * @throws {InputValidationError} If `projectId` is not a UUID, `targetOrg` is not a slug, or `reason` is missing
37
+ * @example
38
+ * ```typescript
39
+ * await client.login(email, password); // or loginWithTotp after an MfaRequiredError
40
+ * const moved = await client.admin.rehomeProject(projectId, { targetOrg: 'ulu-labs', reason: 'OQ-4 row 7' });
41
+ * moved.rehome.to_org.slug; // 'ulu-labs'
42
+ * ```
43
+ */
44
+ export declare function rehomeProject(client: OpsHttpClient, projectId: string, input: AdminRehomeProjectInput): Promise<RehomeResponse>;
45
+ /**
46
+ * The reservation table — `GET /admin/projects/rehomes`: every vacated
47
+ * `(org, name)` address and where it redirects. Key-readable. This is the
48
+ * CURRENT redirect state, not the history — a reversal annihilates its row and
49
+ * a release deletes it; for "what happened" read {@link listProjectRehomeEvents}.
50
+ *
51
+ * `org` takes a UUID or a slug; `total` is the matching count, `returned` the page.
52
+ *
53
+ * @param client - HTTP client instance (a platform-admin key suffices)
54
+ * @param query - `{ projectId?, org?, since?, limit? }`
55
+ * @returns `{ data, total, returned }` — reservation rows, camelCase
56
+ */
57
+ export declare function listProjectRehomes(client: OpsHttpClient, query?: ProjectRehomeListQuery): Promise<ProjectRehomeList>;
58
+ /**
59
+ * The append-only ledger (D21) — `GET /admin/projects/rehome-events`: every
60
+ * move, re-point, annihilation, degenerate drop, release and hard-delete
61
+ * release, written in the same transaction as the change; nothing the API
62
+ * offers removes a row. Key-readable. Pages by `seq` (insertion order) —
63
+ * `nextCursor` is the `seq` to continue strictly below; pass it back verbatim.
64
+ * This, not the reservation listing and not a script's own log, is what a
65
+ * migration reconciles against (spec §4.7 item 4).
66
+ *
67
+ * @param client - HTTP client instance (a platform-admin key suffices)
68
+ * @param query - `{ projectId?, org?, event?, since?, cursor?, limit? }`
69
+ * @returns `{ data, total, returned, hasMore, nextCursor }` — ledger rows, camelCase, newest `seq` first
70
+ * @example
71
+ * ```typescript
72
+ * let cursor: string | undefined;
73
+ * do {
74
+ * const page = await client.admin.listProjectRehomeEvents({ org: 'ulu-labs', event: 'moved', cursor });
75
+ * for (const ev of page.data) console.log(ev.seq, ev.projectName, ev.fromOrgId, '→', ev.toOrgId);
76
+ * cursor = page.nextCursor ?? undefined;
77
+ * } while (cursor);
78
+ * ```
79
+ */
80
+ export declare function listProjectRehomeEvents(client: OpsHttpClient, query?: ProjectRehomeEventListQuery): Promise<ProjectRehomeEventList>;
81
+ /**
82
+ * Release a vacated address — `DELETE /admin/projects/rehomes/:id`. After
83
+ * this the old `(org, name)` is creatable again: a by-name writer there gets a
84
+ * NEW project instead of `410 PROJECT_REHOMED`. Deliberate, audited (`released`
85
+ * ledger row), never done by time. Session-only (D20): release is the step that
86
+ * empties the queryable record.
87
+ *
88
+ * @param client - HTTP client instance carrying a SESSION
89
+ * @param rehomeId - The reservation row id (from {@link listProjectRehomes}); a non-UUID is refused client-side
90
+ * @returns `{ released: true }`
91
+ * @throws {InputValidationError} If `rehomeId` is not a UUID
92
+ * @throws {ZodError} If the 200 body does not say `released: true` — the same signal every other
93
+ * shape mismatch in this SDK gives. Note the server sends 200 AFTER the row is gone, so a
94
+ * shape failure here means the release most likely HAPPENED; re-read `listProjectRehomes`
95
+ * before retrying (a retry answers 404).
96
+ */
97
+ export declare function releaseProjectRehome(client: OpsHttpClient, rehomeId: string): Promise<{
98
+ released: true;
99
+ }>;
100
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/operations/admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EACV,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,2BAA2B,EAC5B,MAAM,oBAAoB,CAAC;AAS5B;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAOzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,KAAK,GAAE,sBAA2B,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAO5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,aAAa,EACrB,KAAK,GAAE,2BAAgC,GACtC,OAAO,CAAC,sBAAsB,CAAC,CAUjC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC,CAG7B"}
@@ -0,0 +1,130 @@
1
+ import { RehomeResponseSchema, ProjectRehomeListResponseSchema, ProjectRehomeEventListResponseSchema, } from '../types/rehome.js';
2
+ import { z } from 'zod';
3
+ import { validateAdminRehomeProjectInput, validateUuid } from '../config/validators.js';
4
+ /**
5
+ * Platform-admin project re-home surface (project-org-routing-and-rehome spec
6
+ * §4.1 D8, §4.7, D20, D21). Every call here requires `users.role = 'admin'` —
7
+ * a PLATFORM role, not an org role — and the two writes additionally require
8
+ * a login-issued SESSION (D20): a `ulr_` key, even an admin's, gets
9
+ * `403 SESSION_REQUIRED` (`isSessionRequiredError`). Log in with
10
+ * `OpsClient.login` (completing MFA via `loginWithTotp` if challenged) and the
11
+ * session bearer is what these calls send. There is deliberately no MCP tool
12
+ * for any of this.
13
+ *
14
+ * `admin.` is a namespace, not an escalation: the same client, the same auth
15
+ * strategy. If the credential cannot do it the server says so.
16
+ */
17
+ /**
18
+ * Move ANY project between ANY two orgs — `POST /admin/projects/:id/rehome`.
19
+ * No source-membership and no target-membership requirement (the platform role
20
+ * is the authority), so `reason` is REQUIRED: on this path the target org's
21
+ * only standing is the `rehome_in` audit row plus that text. Resolves the
22
+ * project by id UNSCOPED (the admin router has no org context) — the route
23
+ * takes a UUID and answers 400 to anything else, so unlike `projects.*` a
24
+ * NAME is refused here, client-side, before the request.
25
+ *
26
+ * Session-only (D20). Phase 4 of the spec runs this once per row of the OQ-4
27
+ * table, sequentially, with the row reference as `reason`. On THIS path a
28
+ * re-run over a finished row answers `same_org` (the lookup is by id, so the
29
+ * moved project is found wherever it is) — read it as "already done" via
30
+ * `rehomeRefusalReason`. That is not true of the member path, whose lookup is
31
+ * source-scoped (see `projects.rehome`).
32
+ *
33
+ * @param client - HTTP client instance carrying a SESSION
34
+ * @param projectId - Project UUID (a name is an `InputValidationError`)
35
+ * @param input - `{ targetOrg, reason }` — both required
36
+ * @returns The project after the move (`orgId` is the target) plus the `rehome` block
37
+ * @throws {InputValidationError} If `projectId` is not a UUID, `targetOrg` is not a slug, or `reason` is missing
38
+ * @example
39
+ * ```typescript
40
+ * await client.login(email, password); // or loginWithTotp after an MfaRequiredError
41
+ * const moved = await client.admin.rehomeProject(projectId, { targetOrg: 'ulu-labs', reason: 'OQ-4 row 7' });
42
+ * moved.rehome.to_org.slug; // 'ulu-labs'
43
+ * ```
44
+ */
45
+ export async function rehomeProject(client, projectId, input) {
46
+ validateUuid(projectId, 'projectId');
47
+ const valid = validateAdminRehomeProjectInput(input);
48
+ return RehomeResponseSchema.parse(await client.post(`/admin/projects/${encodeURIComponent(projectId)}/rehome`, { target_org: valid.targetOrg, reason: valid.reason }));
49
+ }
50
+ /**
51
+ * The reservation table — `GET /admin/projects/rehomes`: every vacated
52
+ * `(org, name)` address and where it redirects. Key-readable. This is the
53
+ * CURRENT redirect state, not the history — a reversal annihilates its row and
54
+ * a release deletes it; for "what happened" read {@link listProjectRehomeEvents}.
55
+ *
56
+ * `org` takes a UUID or a slug; `total` is the matching count, `returned` the page.
57
+ *
58
+ * @param client - HTTP client instance (a platform-admin key suffices)
59
+ * @param query - `{ projectId?, org?, since?, limit? }`
60
+ * @returns `{ data, total, returned }` — reservation rows, camelCase
61
+ */
62
+ export async function listProjectRehomes(client, query = {}) {
63
+ return ProjectRehomeListResponseSchema.parse(await client.request('GET', '/admin/projects/rehomes', rehomeListParams(query), { rawEnvelope: true }));
64
+ }
65
+ /**
66
+ * The append-only ledger (D21) — `GET /admin/projects/rehome-events`: every
67
+ * move, re-point, annihilation, degenerate drop, release and hard-delete
68
+ * release, written in the same transaction as the change; nothing the API
69
+ * offers removes a row. Key-readable. Pages by `seq` (insertion order) —
70
+ * `nextCursor` is the `seq` to continue strictly below; pass it back verbatim.
71
+ * This, not the reservation listing and not a script's own log, is what a
72
+ * migration reconciles against (spec §4.7 item 4).
73
+ *
74
+ * @param client - HTTP client instance (a platform-admin key suffices)
75
+ * @param query - `{ projectId?, org?, event?, since?, cursor?, limit? }`
76
+ * @returns `{ data, total, returned, hasMore, nextCursor }` — ledger rows, camelCase, newest `seq` first
77
+ * @example
78
+ * ```typescript
79
+ * let cursor: string | undefined;
80
+ * do {
81
+ * const page = await client.admin.listProjectRehomeEvents({ org: 'ulu-labs', event: 'moved', cursor });
82
+ * for (const ev of page.data) console.log(ev.seq, ev.projectName, ev.fromOrgId, '→', ev.toOrgId);
83
+ * cursor = page.nextCursor ?? undefined;
84
+ * } while (cursor);
85
+ * ```
86
+ */
87
+ export async function listProjectRehomeEvents(client, query = {}) {
88
+ const params = rehomeListParams(query);
89
+ if (query.event !== undefined)
90
+ params['event'] = query.event;
91
+ if (query.cursor !== undefined)
92
+ params['cursor'] = query.cursor;
93
+ return ProjectRehomeEventListResponseSchema.parse(await client.request('GET', '/admin/projects/rehome-events', params, { rawEnvelope: true }));
94
+ }
95
+ /**
96
+ * Release a vacated address — `DELETE /admin/projects/rehomes/:id`. After
97
+ * this the old `(org, name)` is creatable again: a by-name writer there gets a
98
+ * NEW project instead of `410 PROJECT_REHOMED`. Deliberate, audited (`released`
99
+ * ledger row), never done by time. Session-only (D20): release is the step that
100
+ * empties the queryable record.
101
+ *
102
+ * @param client - HTTP client instance carrying a SESSION
103
+ * @param rehomeId - The reservation row id (from {@link listProjectRehomes}); a non-UUID is refused client-side
104
+ * @returns `{ released: true }`
105
+ * @throws {InputValidationError} If `rehomeId` is not a UUID
106
+ * @throws {ZodError} If the 200 body does not say `released: true` — the same signal every other
107
+ * shape mismatch in this SDK gives. Note the server sends 200 AFTER the row is gone, so a
108
+ * shape failure here means the release most likely HAPPENED; re-read `listProjectRehomes`
109
+ * before retrying (a retry answers 404).
110
+ */
111
+ export async function releaseProjectRehome(client, rehomeId) {
112
+ validateUuid(rehomeId, 'rehomeId');
113
+ return ReleaseResponseSchema.parse(await client.delete(`/admin/projects/rehomes/${encodeURIComponent(rehomeId)}`));
114
+ }
115
+ /** `DELETE /admin/projects/rehomes/:id` answers `{ data: { released: true } }`; anything else is a contract break. */
116
+ const ReleaseResponseSchema = z.object({ released: z.literal(true) });
117
+ /** Shared filter serialisation for the two listings — snake_case on the wire (`project_id`), strings throughout. */
118
+ function rehomeListParams(query) {
119
+ const params = {};
120
+ if (query.projectId !== undefined)
121
+ params['project_id'] = query.projectId;
122
+ if (query.org !== undefined)
123
+ params['org'] = query.org;
124
+ if (query.since !== undefined)
125
+ params['since'] = query.since;
126
+ if (query.limit !== undefined)
127
+ params['limit'] = String(query.limit);
128
+ return params;
129
+ }
130
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/operations/admin.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { OpsHttpClient } from '../http/http-client.js';
2
- import type { RegisterInput, LoginInput, LoginResponse, RegisterResponse, UpdateProfileInput, ChangePasswordInput, ResetPasswordInput, CreateApiKeyInput, ApiKeyCreatedResponse, PublicApiKey, PublicSession, AuthUser, PublicUser } from '../types/auth.js';
2
+ import type { RegisterInput, LoginInput, LoginResponse, TotpLoginInput, RegisterResponse, UpdateProfileInput, ChangePasswordInput, ResetPasswordInput, CreateApiKeyInput, ApiKeyCreatedResponse, PublicApiKey, PublicSession, AuthUser, PublicUser } from '../types/auth.js';
3
3
  import type { MessageResponse } from '../types/responses.js';
4
4
  /**
5
5
  * Register a new user account. Does not require authentication.
@@ -23,8 +23,28 @@ export declare function register(client: OpsHttpClient, input: RegisterInput): P
23
23
  * @returns `{ user, sessionToken }` — token must be manually installed on the client
24
24
  * @throws {InputValidationError} If email or password is missing
25
25
  * @throws {UnauthorizedError} If credentials are invalid
26
+ * @throws {MfaRequiredError} If the account has TOTP or a passkey enrolled — the API answered a
27
+ * challenge, not a session; complete it with `totpLogin` / `OpsClient.loginWithTotp`
26
28
  */
27
29
  export declare function login(client: OpsHttpClient, input: LoginInput): Promise<LoginResponse>;
30
+ /**
31
+ * Complete an MFA-challenged login with a TOTP code (`POST /auth/totp/login`).
32
+ * Returns the same `{ user, sessionToken, expiresAt }` a password login does.
33
+ * Like `login`, this only RETURNS the session — `OpsClient.loginWithTotp`
34
+ * installs it.
35
+ *
36
+ * **The challenge is single-use and is consumed BEFORE the code is checked**
37
+ * (`totp-service.verifyLogin`: consume, then verify). A wrong code therefore
38
+ * burns the token: retrying `totpLogin` with the same `mfaChallengeToken` is a
39
+ * 401 every time. Recovery is a fresh `login()` for a fresh challenge.
40
+ *
41
+ * @param client - HTTP client instance
42
+ * @param input - `{ mfaChallengeToken, code, rememberMe? }`
43
+ * @returns `{ user, sessionToken, expiresAt }` — token must be manually installed on the client
44
+ * @throws {InputValidationError} If the token is empty or the code is not six digits
45
+ * @throws {UnauthorizedError} If the code is wrong, or the challenge expired or was already consumed
46
+ */
47
+ export declare function totpLogin(client: OpsHttpClient, input: TotpLoginInput): Promise<LoginResponse>;
28
48
  /**
29
49
  * Revoke all sessions for the current user (not just the current session).
30
50
  *
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/operations/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/operations/auth.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
- import { AuthUserResponseSchema, PublicUserResponseSchema, LoginResponseSchema, RegisterResponseSchema, PublicApiKeyResponseSchema, ApiKeyCreatedResponseSchema, PublicSessionResponseSchema, MessageResponseSchema, } from '../types/response-schemas.js';
3
- import { validateRegisterInput, validateLoginInput, validateUpdateProfileInput, validateChangePasswordInput, validateResetPasswordInput, validateSetPasswordInput, validateCreateApiKeyInput, } from '../config/validators.js';
2
+ import { AuthUserResponseSchema, PublicUserResponseSchema, LoginResponseSchema, MfaChallengeResponseSchema, RegisterResponseSchema, PublicApiKeyResponseSchema, ApiKeyCreatedResponseSchema, PublicSessionResponseSchema, MessageResponseSchema, } from '../types/response-schemas.js';
3
+ import { validateRegisterInput, validateLoginInput, validateTotpLoginInput, validateUpdateProfileInput, validateChangePasswordInput, validateResetPasswordInput, validateSetPasswordInput, validateCreateApiKeyInput, } from '../config/validators.js';
4
+ import { MfaRequiredError } from '../errors/errors.js';
4
5
  const ProfileResponseSchema = z.object({ user: PublicUserResponseSchema });
5
6
  /**
6
7
  * Register a new user account. Does not require authentication.
@@ -27,10 +28,55 @@ export async function register(client, input) {
27
28
  * @returns `{ user, sessionToken }` — token must be manually installed on the client
28
29
  * @throws {InputValidationError} If email or password is missing
29
30
  * @throws {UnauthorizedError} If credentials are invalid
31
+ * @throws {MfaRequiredError} If the account has TOTP or a passkey enrolled — the API answered a
32
+ * challenge, not a session; complete it with `totpLogin` / `OpsClient.loginWithTotp`
30
33
  */
31
34
  export async function login(client, input) {
32
35
  validateLoginInput(input);
33
- return LoginResponseSchema.parse(await client.post('/auth/login', input, { skipAuth: true }));
36
+ const body = await client.post('/auth/login', input, { skipAuth: true });
37
+ return parseLoginOrChallenge(body);
38
+ }
39
+ /**
40
+ * Complete an MFA-challenged login with a TOTP code (`POST /auth/totp/login`).
41
+ * Returns the same `{ user, sessionToken, expiresAt }` a password login does.
42
+ * Like `login`, this only RETURNS the session — `OpsClient.loginWithTotp`
43
+ * installs it.
44
+ *
45
+ * **The challenge is single-use and is consumed BEFORE the code is checked**
46
+ * (`totp-service.verifyLogin`: consume, then verify). A wrong code therefore
47
+ * burns the token: retrying `totpLogin` with the same `mfaChallengeToken` is a
48
+ * 401 every time. Recovery is a fresh `login()` for a fresh challenge.
49
+ *
50
+ * @param client - HTTP client instance
51
+ * @param input - `{ mfaChallengeToken, code, rememberMe? }`
52
+ * @returns `{ user, sessionToken, expiresAt }` — token must be manually installed on the client
53
+ * @throws {InputValidationError} If the token is empty or the code is not six digits
54
+ * @throws {UnauthorizedError} If the code is wrong, or the challenge expired or was already consumed
55
+ */
56
+ export async function totpLogin(client, input) {
57
+ const valid = validateTotpLoginInput(input);
58
+ return LoginResponseSchema.parse(await client.post('/auth/totp/login', {
59
+ mfa_challenge_token: valid.mfaChallengeToken,
60
+ code: valid.code,
61
+ ...(valid.rememberMe !== undefined ? { rememberMe: valid.rememberMe } : {}),
62
+ }, { skipAuth: true }));
63
+ }
64
+ /**
65
+ * A 200 from `/auth/login` is one of two shapes; the challenge is tried FIRST
66
+ * because it is the narrower literal, and a session body can never carry
67
+ * `mfa_required: true`. Anything else falls through to the strict session
68
+ * parse, whose ZodError names what was actually missing.
69
+ */
70
+ function parseLoginOrChallenge(body) {
71
+ const challenge = MfaChallengeResponseSchema.safeParse(body);
72
+ if (challenge.success) {
73
+ throw new MfaRequiredError({
74
+ mfaChallengeToken: challenge.data.mfa_challenge_token,
75
+ expiresAt: challenge.data.expires_at,
76
+ mfaMethods: challenge.data.mfa_methods,
77
+ });
78
+ }
79
+ return LoginResponseSchema.parse(body);
34
80
  }
35
81
  /**
36
82
  * Revoke all sessions for the current user (not just the current session).