@startsimpli/api 0.5.19 → 0.5.21

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.
@@ -0,0 +1,155 @@
1
+ /** Vault API client — environments, secrets, access keys, audit (startsim-d30.3.1).
2
+
3
+ Mirrors the other @startsimpli/api wrappers. The client auto-transforms
4
+ snake_case <-> camelCase, so types here are camelCase. Secret values are
5
+ write-only on create/update and only returned by `revealSecret`.
6
+ */
7
+
8
+ import type { PaginatedResponse } from '../types';
9
+ import type { ApiClient } from './api-client';
10
+
11
+ const E = {
12
+ environments: 'api/v1/vault/environments',
13
+ environment: (slug: string) => `api/v1/vault/environments/${slug}`,
14
+ secrets: (slug: string) => `api/v1/vault/environments/${slug}/secrets`,
15
+ secret: (slug: string, id: string) => `api/v1/vault/environments/${slug}/secrets/${id}`,
16
+ reveal: (slug: string, id: string) => `api/v1/vault/environments/${slug}/secrets/${id}/reveal`,
17
+ accessKeys: (slug: string) => `api/v1/vault/environments/${slug}/access-keys`,
18
+ accessKey: (slug: string, id: string) => `api/v1/vault/environments/${slug}/access-keys/${id}`,
19
+ audit: (slug: string) => `api/v1/vault/environments/${slug}/audit`,
20
+ };
21
+
22
+ export interface VaultEnvironment {
23
+ id: string;
24
+ slug: string;
25
+ name: string;
26
+ description: string;
27
+ secretCount: number;
28
+ createdAt: string;
29
+ updatedAt: string;
30
+ }
31
+
32
+ export interface VaultEnvironmentInput {
33
+ slug: string;
34
+ name: string;
35
+ description?: string;
36
+ }
37
+
38
+ export interface VaultSecret {
39
+ id: string;
40
+ key: string;
41
+ hasValue: boolean;
42
+ valueType: string;
43
+ metadata: Record<string, unknown>;
44
+ lastRotatedAt: string | null;
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ }
48
+
49
+ export interface VaultSecretInput {
50
+ key: string;
51
+ value?: string;
52
+ valueType?: string;
53
+ metadata?: Record<string, unknown>;
54
+ }
55
+
56
+ export interface VaultSecretReveal {
57
+ key: string;
58
+ value: string;
59
+ }
60
+
61
+ export interface VaultAccessKey {
62
+ id: string;
63
+ name: string;
64
+ prefix: string;
65
+ scopes: string[];
66
+ isActive: boolean;
67
+ lastUsedAt: string | null;
68
+ expiresAt: string | null;
69
+ createdAt: string;
70
+ }
71
+
72
+ /** Returned only by createAccessKey — carries the raw key, shown exactly once. */
73
+ export interface VaultAccessKeyCreated extends VaultAccessKey {
74
+ key: string;
75
+ }
76
+
77
+ export interface VaultAccessKeyInput {
78
+ name: string;
79
+ scopes?: string[];
80
+ expiresAt?: string | null;
81
+ }
82
+
83
+ export interface VaultAuditEntry {
84
+ id: string;
85
+ action: string;
86
+ secretKey: string | null;
87
+ actorEmail: string | null;
88
+ accessKeyName: string | null;
89
+ ipAddress: string | null;
90
+ metadata: Record<string, unknown>;
91
+ createdAt: string;
92
+ }
93
+
94
+ export interface VaultListParams {
95
+ page?: number;
96
+ pageSize?: number;
97
+ search?: string;
98
+ ordering?: string;
99
+ // Index signature so this satisfies the client's query-params type.
100
+ [key: string]: unknown;
101
+ }
102
+
103
+ export class VaultApi {
104
+ constructor(private client: ApiClient) {}
105
+
106
+ // --- Environments ---
107
+ listEnvironments(params?: VaultListParams): Promise<PaginatedResponse<VaultEnvironment>> {
108
+ return this.client.fetch.get<PaginatedResponse<VaultEnvironment>>(E.environments, { params });
109
+ }
110
+ getEnvironment(slug: string): Promise<VaultEnvironment> {
111
+ return this.client.fetch.get<VaultEnvironment>(E.environment(slug));
112
+ }
113
+ createEnvironment(data: VaultEnvironmentInput): Promise<VaultEnvironment> {
114
+ return this.client.fetch.post<VaultEnvironment>(E.environments, data);
115
+ }
116
+ updateEnvironment(slug: string, data: Partial<VaultEnvironmentInput>): Promise<VaultEnvironment> {
117
+ return this.client.fetch.patch<VaultEnvironment>(E.environment(slug), data);
118
+ }
119
+ deleteEnvironment(slug: string): Promise<void> {
120
+ return this.client.fetch.delete<void>(E.environment(slug));
121
+ }
122
+
123
+ // --- Secrets (value write-only; reveal is separate + audited) ---
124
+ listSecrets(slug: string, params?: VaultListParams): Promise<PaginatedResponse<VaultSecret>> {
125
+ return this.client.fetch.get<PaginatedResponse<VaultSecret>>(E.secrets(slug), { params });
126
+ }
127
+ createSecret(slug: string, data: VaultSecretInput): Promise<VaultSecret> {
128
+ return this.client.fetch.post<VaultSecret>(E.secrets(slug), data);
129
+ }
130
+ updateSecret(slug: string, id: string, data: Partial<VaultSecretInput>): Promise<VaultSecret> {
131
+ return this.client.fetch.patch<VaultSecret>(E.secret(slug, id), data);
132
+ }
133
+ deleteSecret(slug: string, id: string): Promise<void> {
134
+ return this.client.fetch.delete<void>(E.secret(slug, id));
135
+ }
136
+ revealSecret(slug: string, id: string): Promise<VaultSecretReveal> {
137
+ return this.client.fetch.get<VaultSecretReveal>(E.reveal(slug, id));
138
+ }
139
+
140
+ // --- Access keys ---
141
+ listAccessKeys(slug: string, params?: VaultListParams): Promise<PaginatedResponse<VaultAccessKey>> {
142
+ return this.client.fetch.get<PaginatedResponse<VaultAccessKey>>(E.accessKeys(slug), { params });
143
+ }
144
+ createAccessKey(slug: string, data: VaultAccessKeyInput): Promise<VaultAccessKeyCreated> {
145
+ return this.client.fetch.post<VaultAccessKeyCreated>(E.accessKeys(slug), data);
146
+ }
147
+ deleteAccessKey(slug: string, id: string): Promise<void> {
148
+ return this.client.fetch.delete<void>(E.accessKey(slug, id));
149
+ }
150
+
151
+ // --- Audit ---
152
+ listAudit(slug: string, params?: VaultListParams): Promise<PaginatedResponse<VaultAuditEntry>> {
153
+ return this.client.fetch.get<PaginatedResponse<VaultAuditEntry>>(E.audit(slug), { params });
154
+ }
155
+ }
package/src/types/api.ts CHANGED
@@ -15,6 +15,12 @@ export interface ApiError {
15
15
  errors?: Record<string, string[]>;
16
16
  status?: number;
17
17
  statusText?: string;
18
+ /** Machine-readable code from the standardized response (limit_reached,
19
+ * no_company, …). Set when the backend uses apps.core.exceptions. */
20
+ code?: string;
21
+ /** Extra structured context attached to the error (e.g. limit_reached
22
+ * carries { feature_key, limit, current }). */
23
+ details?: Record<string, unknown>;
18
24
  }
19
25
 
20
26
  export interface PaginationParams {
@@ -98,6 +98,28 @@ export type {
98
98
  ApolloEnrichmentSummary,
99
99
  } from './enrichment';
100
100
 
101
+ // Team / Company / Invitation / Domain-claim types (startsim-o7s)
102
+ export type {
103
+ Company,
104
+ AuthUserLike,
105
+ TeamRole,
106
+ Team,
107
+ TeamMember,
108
+ TeamInvitation,
109
+ DomainVerificationMethod,
110
+ EmailDomainClaim,
111
+ CompanyListParams,
112
+ UpdateCompanyInput,
113
+ TeamListParams,
114
+ BulkInviteEntry,
115
+ BulkInviteResult,
116
+ TeamInvitationListParams,
117
+ CreateTeamInvitationInput,
118
+ DomainClaimListParams,
119
+ CreateDomainClaimInput,
120
+ DomainVerifyEmailInitiateResponse,
121
+ } from './team';
122
+
101
123
  // Error types
102
124
  export type {
103
125
  FieldError,
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Team / Company / Invitation / Domain-claim types.
3
+ *
4
+ * Mirrors the Django serializers in apps.companies / apps.teams /
5
+ * apps.email_domain_claims. The FetchWrapper transforms snake_case ↔ camelCase
6
+ * at the boundary, so types here are camelCase. startsim-o7s.
7
+ */
8
+
9
+ /** A Company is the top-level org tenant in StartSimpli. */
10
+ export interface Company {
11
+ id: string;
12
+ slug: string;
13
+ name: string;
14
+ /** Free-form per-company settings blob (feature flags + product prefs). */
15
+ settings: Record<string, unknown>;
16
+ /** Hydrated by `?expand=owner`; otherwise just present as a foreign-key id. */
17
+ owner?: AuthUserLike | null;
18
+ ownerId?: string;
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ }
22
+
23
+ /**
24
+ * Trimmed AuthUser used by the team-mgmt serializers.
25
+ *
26
+ * Imported from @startsimpli/auth in practice, but we keep an internal shape
27
+ * here so @startsimpli/api stays decoupled from the auth package's exports.
28
+ * The real AuthUser is structurally compatible.
29
+ */
30
+ export interface AuthUserLike {
31
+ id: string;
32
+ email: string;
33
+ firstName?: string;
34
+ lastName?: string;
35
+ fullName?: string;
36
+ }
37
+
38
+ /** Role hierarchy on a TeamMember (mirrors backend `Role` choices). */
39
+ export type TeamRole = 'owner' | 'admin' | 'member' | 'viewer';
40
+
41
+ /** A Team scopes role assignments inside a Company. */
42
+ export interface Team {
43
+ id: string;
44
+ slug: string;
45
+ name: string;
46
+ companyId: string;
47
+ settings: Record<string, unknown>;
48
+ createdAt: string;
49
+ updatedAt: string;
50
+ }
51
+
52
+ /** A TeamMember pins a user into a Team at a specific role. */
53
+ export interface TeamMember {
54
+ id: string;
55
+ userId: string;
56
+ teamId: string;
57
+ role: TeamRole;
58
+ invitedById?: string | null;
59
+ joinedAt: string;
60
+ /** Optional hydrated user (when serializer expands it). */
61
+ user?: AuthUserLike;
62
+ }
63
+
64
+ /**
65
+ * Pending or accepted invitation to join a Team.
66
+ * `token` is write-only after create — surfaced only in the create response
67
+ * so apps can build accept-links.
68
+ */
69
+ export interface TeamInvitation {
70
+ id: string;
71
+ email: string;
72
+ teamId: string;
73
+ role: TeamRole;
74
+ /** Only present in the create-response. Backend redacts on subsequent reads. */
75
+ token?: string;
76
+ invitedById: string;
77
+ expiresAt: string;
78
+ acceptedAt?: string | null;
79
+ revokedAt?: string | null;
80
+ isExpired: boolean;
81
+ isAccepted: boolean;
82
+ createdAt: string;
83
+ updatedAt: string;
84
+ }
85
+
86
+ /** Verification method used for an EmailDomainClaim. */
87
+ export type DomainVerificationMethod = 'dns_txt' | 'email_attestation';
88
+
89
+ /**
90
+ * A Company's claim on an email domain — gates "anyone @acme.com auto-joins"
91
+ * behavior once verified. See startsim-gpu.
92
+ */
93
+ export interface EmailDomainClaim {
94
+ id: string;
95
+ companyId: string;
96
+ domain: string;
97
+ verified: boolean;
98
+ verificationMethod?: DomainVerificationMethod | null;
99
+ /** Only visible to the creator on POST — otherwise null/absent. */
100
+ verificationToken?: string | null;
101
+ verifiedAt?: string | null;
102
+ verifiedById?: string | null;
103
+ lastVerifiedCheckAt?: string | null;
104
+ createdAt: string;
105
+ updatedAt: string;
106
+ }
107
+
108
+ // ---- API request/payload shapes -------------------------------------------
109
+
110
+ export interface CompanyListParams {
111
+ page?: number;
112
+ pageSize?: number;
113
+ search?: string;
114
+ ordering?: string;
115
+ [key: string]: unknown;
116
+ }
117
+
118
+ export interface UpdateCompanyInput {
119
+ name?: string;
120
+ slug?: string;
121
+ settings?: Record<string, unknown>;
122
+ }
123
+
124
+ export interface TeamListParams {
125
+ page?: number;
126
+ pageSize?: number;
127
+ search?: string;
128
+ companyId?: string;
129
+ ordering?: string;
130
+ [key: string]: unknown;
131
+ }
132
+
133
+ export interface BulkInviteEntry {
134
+ email: string;
135
+ role: TeamRole;
136
+ }
137
+
138
+ export interface BulkInviteResult {
139
+ invited: TeamInvitation[];
140
+ /** Backend may return duplicates / failures per the bulk endpoint. */
141
+ skipped?: Array<{ email: string; reason: string }>;
142
+ }
143
+
144
+ export interface TeamInvitationListParams {
145
+ page?: number;
146
+ pageSize?: number;
147
+ teamId?: string;
148
+ ordering?: string;
149
+ [key: string]: unknown;
150
+ }
151
+
152
+ export interface CreateTeamInvitationInput {
153
+ email: string;
154
+ teamId: string;
155
+ role: TeamRole;
156
+ }
157
+
158
+ export interface DomainClaimListParams {
159
+ page?: number;
160
+ pageSize?: number;
161
+ companyId?: string;
162
+ verified?: boolean;
163
+ ordering?: string;
164
+ [key: string]: unknown;
165
+ }
166
+
167
+ export interface CreateDomainClaimInput {
168
+ companyId: string;
169
+ domain: string;
170
+ }
171
+
172
+ export interface DomainVerifyEmailInitiateResponse {
173
+ /** Backend confirms an attestation email has been queued. */
174
+ detail: string;
175
+ }
package/src/types/user.ts CHANGED
@@ -24,9 +24,28 @@ export interface UpdateProfileRequest {
24
24
  export interface ChangePasswordRequest {
25
25
  oldPassword: string;
26
26
  newPassword: string;
27
- newPasswordConfirm: string;
28
27
  }
29
28
 
30
29
  export interface ChangePasswordResponse {
31
30
  detail: string;
32
31
  }
32
+
33
+ /**
34
+ * Passwordless early-access registration — name + email only.
35
+ * Hits POST /api/v1/auth/early-register/ (public, no auth).
36
+ */
37
+ export interface EarlyRegisterRequest {
38
+ email: string;
39
+ firstName?: string;
40
+ lastName?: string;
41
+ }
42
+
43
+ export interface EarlyRegisterResponse {
44
+ user: {
45
+ id: string;
46
+ email: string;
47
+ firstName: string;
48
+ lastName: string;
49
+ };
50
+ message: string;
51
+ }