@forg3t/sdk 0.1.4 → 0.1.6
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.
- package/README.md +65 -50
- package/dist/index.d.mts +56 -5
- package/dist/index.d.ts +56 -5
- package/dist/index.js +133 -16
- package/dist/index.mjs +133 -16
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -33,7 +33,26 @@ There is now also a live bearer-token bootstrap path for first-time tenant creat
|
|
|
33
33
|
- public hostname: `https://api.forg3t.io`
|
|
34
34
|
- auth mode: dashboard bearer token, not project API key
|
|
35
35
|
|
|
36
|
-
This closes the biggest admin-led onboarding gap
|
|
36
|
+
This closes the biggest admin-led onboarding gap. The published npm package now includes the bootstrap flow and request-creation surface, but the overall product is still not fully self-serve enterprise onboarding because tenant lifecycle cleanup, whitebox activation, and some runtime specialization paths remain operator-led.
|
|
37
|
+
|
|
38
|
+
## Execution Modes
|
|
39
|
+
|
|
40
|
+
Forg3t now has three materially different execution lanes. Keeping them separate is important:
|
|
41
|
+
|
|
42
|
+
1. **Managed black-box lane**
|
|
43
|
+
- default baseline path for API-only and retrieval-style first runs
|
|
44
|
+
- request enters via `https://api.forg3t.io`
|
|
45
|
+
- control-plane managed worker claims the job
|
|
46
|
+
- a private executor service runs the black-box workload
|
|
47
|
+
- this is the path verified by the published SDK cleanroom smoke
|
|
48
|
+
|
|
49
|
+
2. **Customer-scoped generic worker**
|
|
50
|
+
- used when a customer wants execution tied to their own project-scoped worker runtime
|
|
51
|
+
- not the same thing as the default managed black-box lane
|
|
52
|
+
|
|
53
|
+
3. **Customer-side whitebox worker**
|
|
54
|
+
- required when the customer wants staged model-weight intervention
|
|
55
|
+
- this remains a separate install and acceptance path
|
|
37
56
|
|
|
38
57
|
## Local Development
|
|
39
58
|
1. **Build**: `npm run build`
|
|
@@ -43,66 +62,45 @@ This closes the biggest admin-led onboarding gap, but the published npm package
|
|
|
43
62
|
|
|
44
63
|
### Customer Onboarding Smoke
|
|
45
64
|
|
|
46
|
-
Use this as the first real integration gate for a
|
|
65
|
+
Use this as the first real integration gate for a new signed-in customer session.
|
|
47
66
|
The production API hostname is:
|
|
48
67
|
|
|
49
68
|
```bash
|
|
50
69
|
export FORG3T_API_URL=https://api.forg3t.io
|
|
51
|
-
export
|
|
52
|
-
export FORG3T_PROJECT_ID=... # optional if default project exists
|
|
70
|
+
export FORG3T_BEARER_TOKEN=eyJ...
|
|
53
71
|
```
|
|
54
72
|
|
|
55
|
-
Then run
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
import { Forg3tClient } from '@forg3t/sdk';
|
|
59
|
-
|
|
60
|
-
const client = new Forg3tClient({
|
|
61
|
-
apiUrl: process.env.FORG3T_API_URL,
|
|
62
|
-
apiKey: process.env.FORG3T_API_KEY,
|
|
63
|
-
timeoutMs: 30000,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
async function main() {
|
|
67
|
-
const me = await client.getCurrentUser();
|
|
68
|
-
const projectId = process.env.FORG3T_PROJECT_ID || me.defaultProjectId;
|
|
69
|
-
|
|
70
|
-
if (!projectId) {
|
|
71
|
-
throw new Error('Set FORG3T_PROJECT_ID or configure a default project first.');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const request = await client.createUnlearningRequest(projectId, {
|
|
75
|
-
target: { type: 'phrase', value: 'customer-onboarding-smoke' },
|
|
76
|
-
scope: {},
|
|
77
|
-
accessLevel: 'layer_a_only',
|
|
78
|
-
execution: {
|
|
79
|
-
target: {
|
|
80
|
-
provider: 'custom',
|
|
81
|
-
endpoint: 'https://example.com/inference'
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
console.log({
|
|
87
|
-
requestId: request.id,
|
|
88
|
-
jobId: request.job?.id,
|
|
89
|
-
jobType: request.job?.type,
|
|
90
|
-
jobStatus: request.job?.status
|
|
91
|
-
});
|
|
92
|
-
}
|
|
73
|
+
Then run the official onboarding smoke:
|
|
93
74
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
process.exit(1);
|
|
97
|
-
});
|
|
75
|
+
```bash
|
|
76
|
+
npm run smoke:customer-onboarding
|
|
98
77
|
```
|
|
99
78
|
|
|
100
79
|
This validates:
|
|
101
|
-
-
|
|
80
|
+
- bearer-token bootstrap
|
|
102
81
|
- project resolution
|
|
82
|
+
- API key creation
|
|
103
83
|
- unlearning request creation
|
|
84
|
+
- request detail fetch
|
|
85
|
+
- terminal job success
|
|
86
|
+
- evidence readiness
|
|
87
|
+
- artifact download readiness
|
|
88
|
+
- API key revoke
|
|
104
89
|
- job contract correctness
|
|
105
|
-
-
|
|
90
|
+
- first-customer path through the public API hostname
|
|
91
|
+
|
|
92
|
+
### Cleanroom Release Smoke
|
|
93
|
+
|
|
94
|
+
For release verification from a clean temporary install:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
export FORG3T_ONBOARDING_SMOKE_EMAIL=onboarding-smoke@forg3t.io
|
|
98
|
+
export FORG3T_ONBOARDING_SMOKE_PASSWORD=...
|
|
99
|
+
export SUPABASE_ANON_KEY=...
|
|
100
|
+
npm run smoke:cleanroom
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This installs the package into a fresh temporary directory, runs bootstrap, creates a first request, verifies terminal job success plus evidence/artifact readiness, and revokes the temporary API key. It is the release-candidate gate we use before claiming the SDK package is ready to publish.
|
|
106
104
|
|
|
107
105
|
### First-Time Tenant Bootstrap
|
|
108
106
|
|
|
@@ -145,14 +143,31 @@ Notes:
|
|
|
145
143
|
- Repeating bootstrap with the same bearer token is idempotent and reuses the tenant resources.
|
|
146
144
|
- This flow is live on the control plane today.
|
|
147
145
|
|
|
146
|
+
### First-Time Bootstrap + First Request
|
|
147
|
+
|
|
148
|
+
If you want the full SDK example in one run:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
export FORG3T_API_URL=https://api.forg3t.io
|
|
152
|
+
export FORG3T_BEARER_TOKEN=eyJ...
|
|
153
|
+
npm run example:bootstrap
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This example:
|
|
157
|
+
|
|
158
|
+
1. bootstraps the tenant
|
|
159
|
+
2. creates a temporary project API key
|
|
160
|
+
3. submits the first request
|
|
161
|
+
4. fetches request detail
|
|
162
|
+
5. revokes the temporary API key
|
|
163
|
+
|
|
148
164
|
### Repo Maintainer Smoke
|
|
149
165
|
|
|
150
166
|
If you are working inside the Forg3t SDK repo itself, you can also run the bundled smoke script:
|
|
151
167
|
|
|
152
168
|
```bash
|
|
153
169
|
export FORG3T_API_URL=https://api.forg3t.io
|
|
154
|
-
export
|
|
155
|
-
export FORG3T_PROJECT_ID=...
|
|
170
|
+
export FORG3T_BEARER_TOKEN=eyJ...
|
|
156
171
|
npm run smoke:customer-onboarding
|
|
157
172
|
```
|
|
158
173
|
|
package/dist/index.d.mts
CHANGED
|
@@ -82,7 +82,12 @@ interface CreateApiKeyRequest {
|
|
|
82
82
|
expiresAt?: string;
|
|
83
83
|
}
|
|
84
84
|
interface CreateApiKeyResponse extends ApiKey {
|
|
85
|
-
|
|
85
|
+
key: string;
|
|
86
|
+
plaintextKey?: string;
|
|
87
|
+
}
|
|
88
|
+
interface RevokeApiKeyResponse {
|
|
89
|
+
status: 'revoked' | string;
|
|
90
|
+
revokedAt?: string | null;
|
|
86
91
|
}
|
|
87
92
|
interface AuditEvent {
|
|
88
93
|
id: string;
|
|
@@ -264,6 +269,8 @@ declare enum IntegrationType {
|
|
|
264
269
|
LANGCHAIN = "langchain",
|
|
265
270
|
OPENROUTER = "openrouter",
|
|
266
271
|
OPENAI = "openai",
|
|
272
|
+
PGVECTOR = "pgvector",
|
|
273
|
+
ADAPTER = "adapter",
|
|
267
274
|
CUSTOM = "custom"
|
|
268
275
|
}
|
|
269
276
|
declare enum IntegrationMode {
|
|
@@ -285,6 +292,29 @@ interface OpenRouterAdapterConfig extends BaseAdapterConfig {
|
|
|
285
292
|
routingStrategy: 'cost' | 'latency' | 'quality';
|
|
286
293
|
fallbackModels?: string[];
|
|
287
294
|
}
|
|
295
|
+
interface PgVectorIntegrationConfig extends BaseAdapterConfig {
|
|
296
|
+
backend: 'pgvector_postgres';
|
|
297
|
+
schema?: string;
|
|
298
|
+
table: string;
|
|
299
|
+
document_id_column?: string;
|
|
300
|
+
metadata_column?: string;
|
|
301
|
+
metadata_document_id_key?: string;
|
|
302
|
+
content_column?: string;
|
|
303
|
+
embedding_column?: string;
|
|
304
|
+
database_url_env_var?: string;
|
|
305
|
+
healthcheck_url?: string;
|
|
306
|
+
healthcheck_method?: 'GET' | 'POST';
|
|
307
|
+
worker_mode?: 'rag';
|
|
308
|
+
}
|
|
309
|
+
interface AdapterIntegrationConfig extends BaseAdapterConfig {
|
|
310
|
+
backend: 'peft_lora_safetensors';
|
|
311
|
+
format?: 'safetensors';
|
|
312
|
+
adapter_uri?: string;
|
|
313
|
+
adapter_uri_env_var?: string;
|
|
314
|
+
healthcheck_url?: string;
|
|
315
|
+
healthcheck_method?: 'GET' | 'POST';
|
|
316
|
+
worker_mode?: 'adapter';
|
|
317
|
+
}
|
|
288
318
|
interface Integration {
|
|
289
319
|
id: string;
|
|
290
320
|
projectId: string;
|
|
@@ -292,7 +322,7 @@ interface Integration {
|
|
|
292
322
|
name: string;
|
|
293
323
|
description?: string;
|
|
294
324
|
status: 'active' | 'disconnected' | 'error' | 'pending';
|
|
295
|
-
config: BaseAdapterConfig | LangChainAdapterConfig | OpenRouterAdapterConfig | Record<string, unknown>;
|
|
325
|
+
config: BaseAdapterConfig | LangChainAdapterConfig | OpenRouterAdapterConfig | PgVectorIntegrationConfig | AdapterIntegrationConfig | Record<string, unknown>;
|
|
296
326
|
capabilities: string[];
|
|
297
327
|
createdAt: string;
|
|
298
328
|
updatedAt: string;
|
|
@@ -348,9 +378,29 @@ interface UnlearningExecutionTargetSpec {
|
|
|
348
378
|
responsePath?: string;
|
|
349
379
|
apiKey?: string;
|
|
350
380
|
}
|
|
381
|
+
interface UnlearningExecutionRagSpec {
|
|
382
|
+
backend: 'pgvector_postgres';
|
|
383
|
+
mode?: 'delete_documents';
|
|
384
|
+
integrationId?: string;
|
|
385
|
+
dryRun?: boolean;
|
|
386
|
+
}
|
|
387
|
+
interface UnlearningExecutionAdapterSpec {
|
|
388
|
+
backend: 'peft_lora_safetensors';
|
|
389
|
+
integrationId?: string;
|
|
390
|
+
method?: 'disable_adapter' | 'attenuate_adapter';
|
|
391
|
+
scaleFactor?: number;
|
|
392
|
+
dryRun?: boolean;
|
|
393
|
+
updatedAdapterUri?: string;
|
|
394
|
+
}
|
|
395
|
+
interface UnlearningExecutionRoutingSpec {
|
|
396
|
+
lane?: 'managed' | 'project_scoped';
|
|
397
|
+
}
|
|
351
398
|
interface UnlearningExecutionSpec {
|
|
352
399
|
target?: UnlearningExecutionTargetSpec;
|
|
400
|
+
rag?: UnlearningExecutionRagSpec;
|
|
401
|
+
adapter?: UnlearningExecutionAdapterSpec;
|
|
353
402
|
model?: UnlearningExecutionModelRef;
|
|
403
|
+
routing?: UnlearningExecutionRoutingSpec;
|
|
354
404
|
plan?: UnlearningExecutionPlanSpec;
|
|
355
405
|
}
|
|
356
406
|
interface UnlearningJobSummary {
|
|
@@ -412,8 +462,8 @@ declare class Forg3tClient {
|
|
|
412
462
|
getUnlearningRequest(projectId: string, unlearningRequestId: string, requestId?: string): Promise<UnlearningRequest>;
|
|
413
463
|
listApiKeys(projectId: string, requestId?: string): Promise<ApiKey[]>;
|
|
414
464
|
createApiKey(projectId: string, data: CreateApiKeyRequest, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
415
|
-
rotateApiKey(keyId: string, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
416
|
-
revokeApiKey(keyId: string, requestId?: string): Promise<
|
|
465
|
+
rotateApiKey(projectId: string, keyId: string, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
466
|
+
revokeApiKey(projectId: string, keyId: string, requestId?: string): Promise<RevokeApiKeyResponse>;
|
|
417
467
|
submitJob(projectId: string, data: SubmitJobRequest, requestId?: string): Promise<Job>;
|
|
418
468
|
/**
|
|
419
469
|
* Creates a new job with deduplication support via an optional idempotency key.
|
|
@@ -475,6 +525,7 @@ declare class Forg3tClient {
|
|
|
475
525
|
}, requestId?: string): Promise<void>;
|
|
476
526
|
private assertCreateUnlearningRequest;
|
|
477
527
|
private assertModelUnlearnPreflight;
|
|
528
|
+
private assertAdapterUnlearnPreflight;
|
|
478
529
|
}
|
|
479
530
|
|
|
480
531
|
declare class Forg3tError extends Error {
|
|
@@ -754,4 +805,4 @@ declare const ENTERPRISE_STRICT_QUALITY_GATE_POLICY: Required<WhiteboxQualityGat
|
|
|
754
805
|
declare function assertDeploymentCompatibility(options: DeploymentCompatibilityOptions): void;
|
|
755
806
|
declare function buildWhiteboxWorkerOptions(profile: Forg3tDeploymentProfile, baseOptions: WhiteboxWorkerBaseOptions): WhiteboxWorkerOptions;
|
|
756
807
|
|
|
757
|
-
export { AccessLevel, type AdapterCommandSpec, type ApiKey, type AuditEvent, type AuditEventFilters, type AuditEventListResponse, type BaseAdapterConfig, type BootstrapTenantRequest, type BootstrapTenantResponse, type BuildModelUnlearningJobInput, type ClaimAssertion, type ClaimJobsRequest, type ClaimScope, type ClaimType, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateIntegrationRequest, type CreateUnlearningRequestParams, type CreateWebhookRequest, type CurrentUserResponse, DEFAULT_WHITEBOX_QUALITY_GATE_POLICY, type DeploymentCompatibilityOptions, ENTERPRISE_STRICT_QUALITY_GATE_POLICY, type EvidenceArtifact, type EvidencePdfResponse, type EvidenceStatusResponse, type ExecutionPlan, type ExecutionStep, type Forg3tAdapterMode, Forg3tApiConnectionError, Forg3tAuthenticationError, Forg3tClient, type Forg3tClientOptions, type Forg3tDeploymentProfile, Forg3tError, Forg3tNotFoundError, Forg3tNotImplementedError, Forg3tRateLimitError, HttpTrainingAdapter, type HttpTrainingAdapterOptions, type Integration, IntegrationMode, IntegrationType, type Job, type JobConfig, type JobError, type JobMutationOptions, type JobResult, type JobStatus, type JobType, type LangChainAdapterConfig, type LocalCommandAdapterOptions, LocalCommandTrainingAdapter, type ModelArtifactReference, type NativeAdapterConfig, type OpenRouterAdapterConfig, type PaginationParams, type Project, type SubmitJobRequest, type TrainingBackendAdapter, type UnlearningClaim, type UnlearningExecutionModelRef, type UnlearningExecutionPlanSpec, type UnlearningExecutionSpec, type UnlearningExecutionTargetSpec, type UnlearningJobSummary, type UnlearningRequest, type UnlearningScope, type UnlearningTarget, type UpdateWebhookRequest, WHITEBOX_QUALITY_GATE_PRESETS, WHITEBOX_QUALITY_GATE_PRESET_EXPLANATIONS, type Webhook, type WebhookDelivery, type WebhookDeliveryFilters, type WhiteboxEvaluationInput, type WhiteboxEvaluationOutput, type WhiteboxJobContext, type WhiteboxQualityGateDecision, type WhiteboxQualityGatePolicy, type WhiteboxQualityGatePreset, type WhiteboxTargetSpec, type WhiteboxUnlearningInput, type WhiteboxUnlearningOutput, type WhiteboxUnlearningPlan, WhiteboxWorker, type WhiteboxWorkerBaseOptions, type WhiteboxWorkerLogger, type WhiteboxWorkerOptions, assertDeploymentCompatibility, buildModelUnlearningPayload, buildWhiteboxWorkerOptions, createNativeTrainingAdapter, evaluateWhiteboxQualityGate, resolveWhiteboxQualityGatePolicy };
|
|
808
|
+
export { AccessLevel, type AdapterCommandSpec, type AdapterIntegrationConfig, type ApiKey, type AuditEvent, type AuditEventFilters, type AuditEventListResponse, type BaseAdapterConfig, type BootstrapTenantRequest, type BootstrapTenantResponse, type BuildModelUnlearningJobInput, type ClaimAssertion, type ClaimJobsRequest, type ClaimScope, type ClaimType, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateIntegrationRequest, type CreateUnlearningRequestParams, type CreateWebhookRequest, type CurrentUserResponse, DEFAULT_WHITEBOX_QUALITY_GATE_POLICY, type DeploymentCompatibilityOptions, ENTERPRISE_STRICT_QUALITY_GATE_POLICY, type EvidenceArtifact, type EvidencePdfResponse, type EvidenceStatusResponse, type ExecutionPlan, type ExecutionStep, type Forg3tAdapterMode, Forg3tApiConnectionError, Forg3tAuthenticationError, Forg3tClient, type Forg3tClientOptions, type Forg3tDeploymentProfile, Forg3tError, Forg3tNotFoundError, Forg3tNotImplementedError, Forg3tRateLimitError, HttpTrainingAdapter, type HttpTrainingAdapterOptions, type Integration, IntegrationMode, IntegrationType, type Job, type JobConfig, type JobError, type JobMutationOptions, type JobResult, type JobStatus, type JobType, type LangChainAdapterConfig, type LocalCommandAdapterOptions, LocalCommandTrainingAdapter, type ModelArtifactReference, type NativeAdapterConfig, type OpenRouterAdapterConfig, type PaginationParams, type PgVectorIntegrationConfig, type Project, type RevokeApiKeyResponse, type SubmitJobRequest, type TrainingBackendAdapter, type UnlearningClaim, type UnlearningExecutionAdapterSpec, type UnlearningExecutionModelRef, type UnlearningExecutionPlanSpec, type UnlearningExecutionRagSpec, type UnlearningExecutionRoutingSpec, type UnlearningExecutionSpec, type UnlearningExecutionTargetSpec, type UnlearningJobSummary, type UnlearningRequest, type UnlearningScope, type UnlearningTarget, type UpdateWebhookRequest, WHITEBOX_QUALITY_GATE_PRESETS, WHITEBOX_QUALITY_GATE_PRESET_EXPLANATIONS, type Webhook, type WebhookDelivery, type WebhookDeliveryFilters, type WhiteboxEvaluationInput, type WhiteboxEvaluationOutput, type WhiteboxJobContext, type WhiteboxQualityGateDecision, type WhiteboxQualityGatePolicy, type WhiteboxQualityGatePreset, type WhiteboxTargetSpec, type WhiteboxUnlearningInput, type WhiteboxUnlearningOutput, type WhiteboxUnlearningPlan, WhiteboxWorker, type WhiteboxWorkerBaseOptions, type WhiteboxWorkerLogger, type WhiteboxWorkerOptions, assertDeploymentCompatibility, buildModelUnlearningPayload, buildWhiteboxWorkerOptions, createNativeTrainingAdapter, evaluateWhiteboxQualityGate, resolveWhiteboxQualityGatePolicy };
|
package/dist/index.d.ts
CHANGED
|
@@ -82,7 +82,12 @@ interface CreateApiKeyRequest {
|
|
|
82
82
|
expiresAt?: string;
|
|
83
83
|
}
|
|
84
84
|
interface CreateApiKeyResponse extends ApiKey {
|
|
85
|
-
|
|
85
|
+
key: string;
|
|
86
|
+
plaintextKey?: string;
|
|
87
|
+
}
|
|
88
|
+
interface RevokeApiKeyResponse {
|
|
89
|
+
status: 'revoked' | string;
|
|
90
|
+
revokedAt?: string | null;
|
|
86
91
|
}
|
|
87
92
|
interface AuditEvent {
|
|
88
93
|
id: string;
|
|
@@ -264,6 +269,8 @@ declare enum IntegrationType {
|
|
|
264
269
|
LANGCHAIN = "langchain",
|
|
265
270
|
OPENROUTER = "openrouter",
|
|
266
271
|
OPENAI = "openai",
|
|
272
|
+
PGVECTOR = "pgvector",
|
|
273
|
+
ADAPTER = "adapter",
|
|
267
274
|
CUSTOM = "custom"
|
|
268
275
|
}
|
|
269
276
|
declare enum IntegrationMode {
|
|
@@ -285,6 +292,29 @@ interface OpenRouterAdapterConfig extends BaseAdapterConfig {
|
|
|
285
292
|
routingStrategy: 'cost' | 'latency' | 'quality';
|
|
286
293
|
fallbackModels?: string[];
|
|
287
294
|
}
|
|
295
|
+
interface PgVectorIntegrationConfig extends BaseAdapterConfig {
|
|
296
|
+
backend: 'pgvector_postgres';
|
|
297
|
+
schema?: string;
|
|
298
|
+
table: string;
|
|
299
|
+
document_id_column?: string;
|
|
300
|
+
metadata_column?: string;
|
|
301
|
+
metadata_document_id_key?: string;
|
|
302
|
+
content_column?: string;
|
|
303
|
+
embedding_column?: string;
|
|
304
|
+
database_url_env_var?: string;
|
|
305
|
+
healthcheck_url?: string;
|
|
306
|
+
healthcheck_method?: 'GET' | 'POST';
|
|
307
|
+
worker_mode?: 'rag';
|
|
308
|
+
}
|
|
309
|
+
interface AdapterIntegrationConfig extends BaseAdapterConfig {
|
|
310
|
+
backend: 'peft_lora_safetensors';
|
|
311
|
+
format?: 'safetensors';
|
|
312
|
+
adapter_uri?: string;
|
|
313
|
+
adapter_uri_env_var?: string;
|
|
314
|
+
healthcheck_url?: string;
|
|
315
|
+
healthcheck_method?: 'GET' | 'POST';
|
|
316
|
+
worker_mode?: 'adapter';
|
|
317
|
+
}
|
|
288
318
|
interface Integration {
|
|
289
319
|
id: string;
|
|
290
320
|
projectId: string;
|
|
@@ -292,7 +322,7 @@ interface Integration {
|
|
|
292
322
|
name: string;
|
|
293
323
|
description?: string;
|
|
294
324
|
status: 'active' | 'disconnected' | 'error' | 'pending';
|
|
295
|
-
config: BaseAdapterConfig | LangChainAdapterConfig | OpenRouterAdapterConfig | Record<string, unknown>;
|
|
325
|
+
config: BaseAdapterConfig | LangChainAdapterConfig | OpenRouterAdapterConfig | PgVectorIntegrationConfig | AdapterIntegrationConfig | Record<string, unknown>;
|
|
296
326
|
capabilities: string[];
|
|
297
327
|
createdAt: string;
|
|
298
328
|
updatedAt: string;
|
|
@@ -348,9 +378,29 @@ interface UnlearningExecutionTargetSpec {
|
|
|
348
378
|
responsePath?: string;
|
|
349
379
|
apiKey?: string;
|
|
350
380
|
}
|
|
381
|
+
interface UnlearningExecutionRagSpec {
|
|
382
|
+
backend: 'pgvector_postgres';
|
|
383
|
+
mode?: 'delete_documents';
|
|
384
|
+
integrationId?: string;
|
|
385
|
+
dryRun?: boolean;
|
|
386
|
+
}
|
|
387
|
+
interface UnlearningExecutionAdapterSpec {
|
|
388
|
+
backend: 'peft_lora_safetensors';
|
|
389
|
+
integrationId?: string;
|
|
390
|
+
method?: 'disable_adapter' | 'attenuate_adapter';
|
|
391
|
+
scaleFactor?: number;
|
|
392
|
+
dryRun?: boolean;
|
|
393
|
+
updatedAdapterUri?: string;
|
|
394
|
+
}
|
|
395
|
+
interface UnlearningExecutionRoutingSpec {
|
|
396
|
+
lane?: 'managed' | 'project_scoped';
|
|
397
|
+
}
|
|
351
398
|
interface UnlearningExecutionSpec {
|
|
352
399
|
target?: UnlearningExecutionTargetSpec;
|
|
400
|
+
rag?: UnlearningExecutionRagSpec;
|
|
401
|
+
adapter?: UnlearningExecutionAdapterSpec;
|
|
353
402
|
model?: UnlearningExecutionModelRef;
|
|
403
|
+
routing?: UnlearningExecutionRoutingSpec;
|
|
354
404
|
plan?: UnlearningExecutionPlanSpec;
|
|
355
405
|
}
|
|
356
406
|
interface UnlearningJobSummary {
|
|
@@ -412,8 +462,8 @@ declare class Forg3tClient {
|
|
|
412
462
|
getUnlearningRequest(projectId: string, unlearningRequestId: string, requestId?: string): Promise<UnlearningRequest>;
|
|
413
463
|
listApiKeys(projectId: string, requestId?: string): Promise<ApiKey[]>;
|
|
414
464
|
createApiKey(projectId: string, data: CreateApiKeyRequest, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
415
|
-
rotateApiKey(keyId: string, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
416
|
-
revokeApiKey(keyId: string, requestId?: string): Promise<
|
|
465
|
+
rotateApiKey(projectId: string, keyId: string, requestId?: string): Promise<CreateApiKeyResponse>;
|
|
466
|
+
revokeApiKey(projectId: string, keyId: string, requestId?: string): Promise<RevokeApiKeyResponse>;
|
|
417
467
|
submitJob(projectId: string, data: SubmitJobRequest, requestId?: string): Promise<Job>;
|
|
418
468
|
/**
|
|
419
469
|
* Creates a new job with deduplication support via an optional idempotency key.
|
|
@@ -475,6 +525,7 @@ declare class Forg3tClient {
|
|
|
475
525
|
}, requestId?: string): Promise<void>;
|
|
476
526
|
private assertCreateUnlearningRequest;
|
|
477
527
|
private assertModelUnlearnPreflight;
|
|
528
|
+
private assertAdapterUnlearnPreflight;
|
|
478
529
|
}
|
|
479
530
|
|
|
480
531
|
declare class Forg3tError extends Error {
|
|
@@ -754,4 +805,4 @@ declare const ENTERPRISE_STRICT_QUALITY_GATE_POLICY: Required<WhiteboxQualityGat
|
|
|
754
805
|
declare function assertDeploymentCompatibility(options: DeploymentCompatibilityOptions): void;
|
|
755
806
|
declare function buildWhiteboxWorkerOptions(profile: Forg3tDeploymentProfile, baseOptions: WhiteboxWorkerBaseOptions): WhiteboxWorkerOptions;
|
|
756
807
|
|
|
757
|
-
export { AccessLevel, type AdapterCommandSpec, type ApiKey, type AuditEvent, type AuditEventFilters, type AuditEventListResponse, type BaseAdapterConfig, type BootstrapTenantRequest, type BootstrapTenantResponse, type BuildModelUnlearningJobInput, type ClaimAssertion, type ClaimJobsRequest, type ClaimScope, type ClaimType, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateIntegrationRequest, type CreateUnlearningRequestParams, type CreateWebhookRequest, type CurrentUserResponse, DEFAULT_WHITEBOX_QUALITY_GATE_POLICY, type DeploymentCompatibilityOptions, ENTERPRISE_STRICT_QUALITY_GATE_POLICY, type EvidenceArtifact, type EvidencePdfResponse, type EvidenceStatusResponse, type ExecutionPlan, type ExecutionStep, type Forg3tAdapterMode, Forg3tApiConnectionError, Forg3tAuthenticationError, Forg3tClient, type Forg3tClientOptions, type Forg3tDeploymentProfile, Forg3tError, Forg3tNotFoundError, Forg3tNotImplementedError, Forg3tRateLimitError, HttpTrainingAdapter, type HttpTrainingAdapterOptions, type Integration, IntegrationMode, IntegrationType, type Job, type JobConfig, type JobError, type JobMutationOptions, type JobResult, type JobStatus, type JobType, type LangChainAdapterConfig, type LocalCommandAdapterOptions, LocalCommandTrainingAdapter, type ModelArtifactReference, type NativeAdapterConfig, type OpenRouterAdapterConfig, type PaginationParams, type Project, type SubmitJobRequest, type TrainingBackendAdapter, type UnlearningClaim, type UnlearningExecutionModelRef, type UnlearningExecutionPlanSpec, type UnlearningExecutionSpec, type UnlearningExecutionTargetSpec, type UnlearningJobSummary, type UnlearningRequest, type UnlearningScope, type UnlearningTarget, type UpdateWebhookRequest, WHITEBOX_QUALITY_GATE_PRESETS, WHITEBOX_QUALITY_GATE_PRESET_EXPLANATIONS, type Webhook, type WebhookDelivery, type WebhookDeliveryFilters, type WhiteboxEvaluationInput, type WhiteboxEvaluationOutput, type WhiteboxJobContext, type WhiteboxQualityGateDecision, type WhiteboxQualityGatePolicy, type WhiteboxQualityGatePreset, type WhiteboxTargetSpec, type WhiteboxUnlearningInput, type WhiteboxUnlearningOutput, type WhiteboxUnlearningPlan, WhiteboxWorker, type WhiteboxWorkerBaseOptions, type WhiteboxWorkerLogger, type WhiteboxWorkerOptions, assertDeploymentCompatibility, buildModelUnlearningPayload, buildWhiteboxWorkerOptions, createNativeTrainingAdapter, evaluateWhiteboxQualityGate, resolveWhiteboxQualityGatePolicy };
|
|
808
|
+
export { AccessLevel, type AdapterCommandSpec, type AdapterIntegrationConfig, type ApiKey, type AuditEvent, type AuditEventFilters, type AuditEventListResponse, type BaseAdapterConfig, type BootstrapTenantRequest, type BootstrapTenantResponse, type BuildModelUnlearningJobInput, type ClaimAssertion, type ClaimJobsRequest, type ClaimScope, type ClaimType, type CreateApiKeyRequest, type CreateApiKeyResponse, type CreateIntegrationRequest, type CreateUnlearningRequestParams, type CreateWebhookRequest, type CurrentUserResponse, DEFAULT_WHITEBOX_QUALITY_GATE_POLICY, type DeploymentCompatibilityOptions, ENTERPRISE_STRICT_QUALITY_GATE_POLICY, type EvidenceArtifact, type EvidencePdfResponse, type EvidenceStatusResponse, type ExecutionPlan, type ExecutionStep, type Forg3tAdapterMode, Forg3tApiConnectionError, Forg3tAuthenticationError, Forg3tClient, type Forg3tClientOptions, type Forg3tDeploymentProfile, Forg3tError, Forg3tNotFoundError, Forg3tNotImplementedError, Forg3tRateLimitError, HttpTrainingAdapter, type HttpTrainingAdapterOptions, type Integration, IntegrationMode, IntegrationType, type Job, type JobConfig, type JobError, type JobMutationOptions, type JobResult, type JobStatus, type JobType, type LangChainAdapterConfig, type LocalCommandAdapterOptions, LocalCommandTrainingAdapter, type ModelArtifactReference, type NativeAdapterConfig, type OpenRouterAdapterConfig, type PaginationParams, type PgVectorIntegrationConfig, type Project, type RevokeApiKeyResponse, type SubmitJobRequest, type TrainingBackendAdapter, type UnlearningClaim, type UnlearningExecutionAdapterSpec, type UnlearningExecutionModelRef, type UnlearningExecutionPlanSpec, type UnlearningExecutionRagSpec, type UnlearningExecutionRoutingSpec, type UnlearningExecutionSpec, type UnlearningExecutionTargetSpec, type UnlearningJobSummary, type UnlearningRequest, type UnlearningScope, type UnlearningTarget, type UpdateWebhookRequest, WHITEBOX_QUALITY_GATE_PRESETS, WHITEBOX_QUALITY_GATE_PRESET_EXPLANATIONS, type Webhook, type WebhookDelivery, type WebhookDeliveryFilters, type WhiteboxEvaluationInput, type WhiteboxEvaluationOutput, type WhiteboxJobContext, type WhiteboxQualityGateDecision, type WhiteboxQualityGatePolicy, type WhiteboxQualityGatePreset, type WhiteboxTargetSpec, type WhiteboxUnlearningInput, type WhiteboxUnlearningOutput, type WhiteboxUnlearningPlan, WhiteboxWorker, type WhiteboxWorkerBaseOptions, type WhiteboxWorkerLogger, type WhiteboxWorkerOptions, assertDeploymentCompatibility, buildModelUnlearningPayload, buildWhiteboxWorkerOptions, createNativeTrainingAdapter, evaluateWhiteboxQualityGate, resolveWhiteboxQualityGatePolicy };
|
package/dist/index.js
CHANGED
|
@@ -132,10 +132,14 @@ var Transport = class {
|
|
|
132
132
|
async request(path, options = {}, requestId) {
|
|
133
133
|
const url = `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
134
134
|
const headers = {
|
|
135
|
-
"Content-Type": "application/json",
|
|
136
135
|
"Accept": "application/json",
|
|
137
136
|
...options.headers || {}
|
|
138
137
|
};
|
|
138
|
+
const hasExplicitContentType = Object.keys(headers).some((key) => key.toLowerCase() === "content-type");
|
|
139
|
+
const hasBody = options.body !== void 0 && options.body !== null;
|
|
140
|
+
if (hasBody && !hasExplicitContentType) {
|
|
141
|
+
headers["Content-Type"] = "application/json";
|
|
142
|
+
}
|
|
139
143
|
if (this.apiKey) {
|
|
140
144
|
headers["x-api-key"] = this.apiKey;
|
|
141
145
|
}
|
|
@@ -395,11 +399,29 @@ var Forg3tClient = class {
|
|
|
395
399
|
body: JSON.stringify(data)
|
|
396
400
|
}, requestId);
|
|
397
401
|
}
|
|
398
|
-
async rotateApiKey(keyId, requestId) {
|
|
399
|
-
|
|
402
|
+
async rotateApiKey(projectId, keyId, requestId) {
|
|
403
|
+
if (!projectId || !keyId) {
|
|
404
|
+
throw new Error("rotateApiKey requires both projectId and keyId.");
|
|
405
|
+
}
|
|
406
|
+
const existingKeys = await this.listApiKeys(projectId, requestId);
|
|
407
|
+
const current = existingKeys.find((item) => item.id === keyId);
|
|
408
|
+
if (!current) {
|
|
409
|
+
throw new Forg3tNotFoundError(`API key ${keyId} was not found in project ${projectId}.`, requestId);
|
|
410
|
+
}
|
|
411
|
+
const rotated = await this.createApiKey(projectId, {
|
|
412
|
+
name: current.name,
|
|
413
|
+
...current.expiresAt ? { expiresAt: current.expiresAt } : {}
|
|
414
|
+
}, requestId);
|
|
415
|
+
await this.revokeApiKey(projectId, keyId, requestId);
|
|
416
|
+
return rotated;
|
|
400
417
|
}
|
|
401
|
-
async revokeApiKey(keyId, requestId) {
|
|
402
|
-
|
|
418
|
+
async revokeApiKey(projectId, keyId, requestId) {
|
|
419
|
+
if (!projectId || !keyId) {
|
|
420
|
+
throw new Error("revokeApiKey requires both projectId and keyId.");
|
|
421
|
+
}
|
|
422
|
+
return this.transport.request(`/v1/projects/${projectId}/api-keys/${keyId}`, {
|
|
423
|
+
method: "DELETE"
|
|
424
|
+
}, requestId);
|
|
403
425
|
}
|
|
404
426
|
// --- Jobs ---
|
|
405
427
|
async submitJob(projectId, data, requestId) {
|
|
@@ -409,6 +431,8 @@ var Forg3tClient = class {
|
|
|
409
431
|
};
|
|
410
432
|
if (data.type === "MODEL_UNLEARN") {
|
|
411
433
|
this.assertModelUnlearnPreflight(normalizedPayload);
|
|
434
|
+
} else if (data.type === "ADAPTER_UNLEARN") {
|
|
435
|
+
this.assertAdapterUnlearnPreflight(normalizedPayload);
|
|
412
436
|
}
|
|
413
437
|
const res = await this.transport.request(`/v1/projects/${projectId}/jobs`, {
|
|
414
438
|
method: "POST",
|
|
@@ -633,18 +657,67 @@ var Forg3tClient = class {
|
|
|
633
657
|
}
|
|
634
658
|
}
|
|
635
659
|
if (data.accessLevel === "layer_a_only") {
|
|
660
|
+
const rag = data.execution?.rag;
|
|
636
661
|
const target = data.execution?.target;
|
|
637
|
-
|
|
638
|
-
|
|
662
|
+
const adapter = data.execution?.adapter;
|
|
663
|
+
if (adapter) {
|
|
664
|
+
throw new Error("createUnlearningRequest: execution.adapter is only valid for layer_a_and_b.");
|
|
639
665
|
}
|
|
640
|
-
if (
|
|
641
|
-
throw new Error(
|
|
666
|
+
if (target && rag) {
|
|
667
|
+
throw new Error("createUnlearningRequest: execution.target and execution.rag are mutually exclusive for layer_a_only.");
|
|
642
668
|
}
|
|
643
|
-
if (
|
|
644
|
-
|
|
669
|
+
if (rag) {
|
|
670
|
+
if (rag.backend !== "pgvector_postgres") {
|
|
671
|
+
throw new Error("createUnlearningRequest: execution.rag.backend must be pgvector_postgres.");
|
|
672
|
+
}
|
|
673
|
+
if (data.target.type !== "document_id") {
|
|
674
|
+
throw new Error("createUnlearningRequest: the official RAG lane currently supports target.type=document_id only.");
|
|
675
|
+
}
|
|
676
|
+
if (!Array.isArray(data.scope?.integrationIds) || data.scope.integrationIds.length !== 1) {
|
|
677
|
+
throw new Error("createUnlearningRequest: the official RAG lane requires exactly one scope.integrationIds entry.");
|
|
678
|
+
}
|
|
679
|
+
if (data.execution?.routing?.lane && data.execution.routing.lane !== "project_scoped") {
|
|
680
|
+
throw new Error("createUnlearningRequest: execution.routing.lane must be project_scoped for the official RAG lane.");
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
if (!target) {
|
|
684
|
+
throw new Error("createUnlearningRequest: execution.target is required for layer_a_only unless execution.rag is provided.");
|
|
685
|
+
}
|
|
686
|
+
if ((target.provider === "openai" || target.provider === "groq") && !target.model?.trim()) {
|
|
687
|
+
throw new Error(`createUnlearningRequest: execution.target.model is required when provider=${target.provider}.`);
|
|
688
|
+
}
|
|
689
|
+
if ((target.provider === "http_generic" || target.provider === "custom") && !target.endpoint?.trim()) {
|
|
690
|
+
throw new Error(`createUnlearningRequest: execution.target.endpoint is required when provider=${target.provider}.`);
|
|
691
|
+
}
|
|
645
692
|
}
|
|
646
693
|
}
|
|
647
694
|
if (data.accessLevel === "layer_a_and_b") {
|
|
695
|
+
const adapter = data.execution?.adapter;
|
|
696
|
+
if (adapter) {
|
|
697
|
+
if (adapter.backend !== "peft_lora_safetensors") {
|
|
698
|
+
throw new Error("createUnlearningRequest: execution.adapter.backend must be peft_lora_safetensors.");
|
|
699
|
+
}
|
|
700
|
+
if (data.execution?.model?.uri?.trim()) {
|
|
701
|
+
throw new Error("createUnlearningRequest: execution.adapter and execution.model are mutually exclusive for layer_a_and_b.");
|
|
702
|
+
}
|
|
703
|
+
if (!Array.isArray(data.scope?.integrationIds) || data.scope.integrationIds.length !== 1) {
|
|
704
|
+
throw new Error("createUnlearningRequest: the official adapter lane requires exactly one scope.integrationIds entry.");
|
|
705
|
+
}
|
|
706
|
+
if (data.execution?.routing?.lane && data.execution.routing.lane !== "project_scoped") {
|
|
707
|
+
throw new Error("createUnlearningRequest: execution.routing.lane must be project_scoped for the official adapter lane.");
|
|
708
|
+
}
|
|
709
|
+
const method = String(adapter.method || "attenuate_adapter").trim();
|
|
710
|
+
if (!["disable_adapter", "attenuate_adapter"].includes(method)) {
|
|
711
|
+
throw new Error("createUnlearningRequest: execution.adapter.method must be disable_adapter or attenuate_adapter.");
|
|
712
|
+
}
|
|
713
|
+
if (method === "attenuate_adapter") {
|
|
714
|
+
const scaleFactor = Number(adapter.scaleFactor);
|
|
715
|
+
if (!Number.isFinite(scaleFactor) || scaleFactor <= 0 || scaleFactor >= 1) {
|
|
716
|
+
throw new Error("createUnlearningRequest: execution.adapter.scaleFactor must be a finite number between 0 and 1 for attenuate_adapter.");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
648
721
|
if (!data.execution?.model?.uri?.trim()) {
|
|
649
722
|
throw new Error("createUnlearningRequest: execution.model.uri is required for layer_a_and_b.");
|
|
650
723
|
}
|
|
@@ -716,6 +789,40 @@ var Forg3tClient = class {
|
|
|
716
789
|
);
|
|
717
790
|
}
|
|
718
791
|
}
|
|
792
|
+
assertAdapterUnlearnPreflight(payload) {
|
|
793
|
+
if (!payload || typeof payload !== "object") {
|
|
794
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload must be an object.");
|
|
795
|
+
}
|
|
796
|
+
const asRecord = payload;
|
|
797
|
+
const config = asRecord.config && typeof asRecord.config === "object" && !Array.isArray(asRecord.config) ? asRecord.config : null;
|
|
798
|
+
if (!config) {
|
|
799
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config is required.");
|
|
800
|
+
}
|
|
801
|
+
const targetConfig = config.target_config && typeof config.target_config === "object" && !Array.isArray(config.target_config) ? config.target_config : null;
|
|
802
|
+
const parameters = config.parameters && typeof config.parameters === "object" && !Array.isArray(config.parameters) ? config.parameters : null;
|
|
803
|
+
const adapter = parameters?.adapter && typeof parameters.adapter === "object" && !Array.isArray(parameters.adapter) ? parameters.adapter : null;
|
|
804
|
+
if (!targetConfig) {
|
|
805
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config is required.");
|
|
806
|
+
}
|
|
807
|
+
if (String(targetConfig.backend || "").trim() !== "peft_lora_safetensors") {
|
|
808
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config.backend must be peft_lora_safetensors.");
|
|
809
|
+
}
|
|
810
|
+
const adapterUri = String(targetConfig.adapter_uri || "").trim();
|
|
811
|
+
const adapterUriEnvVar = String(targetConfig.adapter_uri_env_var || "").trim();
|
|
812
|
+
if (!adapterUri && !adapterUriEnvVar) {
|
|
813
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config requires adapter_uri or adapter_uri_env_var.");
|
|
814
|
+
}
|
|
815
|
+
const method = String(adapter?.method || "attenuate_adapter").trim();
|
|
816
|
+
if (!["disable_adapter", "attenuate_adapter"].includes(method)) {
|
|
817
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: parameters.adapter.method must be disable_adapter or attenuate_adapter.");
|
|
818
|
+
}
|
|
819
|
+
if (method === "attenuate_adapter") {
|
|
820
|
+
const scaleFactor = Number(adapter?.scaleFactor);
|
|
821
|
+
if (!Number.isFinite(scaleFactor) || scaleFactor <= 0 || scaleFactor >= 1) {
|
|
822
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: parameters.adapter.scaleFactor must be between 0 and 1 for attenuate_adapter.");
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
719
826
|
};
|
|
720
827
|
|
|
721
828
|
// src/types.ts
|
|
@@ -728,6 +835,8 @@ var IntegrationType = /* @__PURE__ */ ((IntegrationType2) => {
|
|
|
728
835
|
IntegrationType2["LANGCHAIN"] = "langchain";
|
|
729
836
|
IntegrationType2["OPENROUTER"] = "openrouter";
|
|
730
837
|
IntegrationType2["OPENAI"] = "openai";
|
|
838
|
+
IntegrationType2["PGVECTOR"] = "pgvector";
|
|
839
|
+
IntegrationType2["ADAPTER"] = "adapter";
|
|
731
840
|
IntegrationType2["CUSTOM"] = "custom";
|
|
732
841
|
return IntegrationType2;
|
|
733
842
|
})(IntegrationType || {});
|
|
@@ -1431,10 +1540,19 @@ var ENTERPRISE_STRICT_QUALITY_GATE_POLICY = {
|
|
|
1431
1540
|
...WHITEBOX_QUALITY_GATE_PRESETS.strict
|
|
1432
1541
|
};
|
|
1433
1542
|
function assertDeploymentCompatibility(options) {
|
|
1434
|
-
const
|
|
1435
|
-
if (!
|
|
1543
|
+
const parsedApiUrl = parseApiUrl(options.apiUrl);
|
|
1544
|
+
if (!parsedApiUrl) {
|
|
1436
1545
|
throw new Error(`Invalid FORG3T_API_URL: ${options.apiUrl}`);
|
|
1437
1546
|
}
|
|
1547
|
+
const normalizedHost = parsedApiUrl.hostname.toLowerCase();
|
|
1548
|
+
if (options.profile === "customer_online") {
|
|
1549
|
+
const publicHost = !isPrivateHost(normalizedHost);
|
|
1550
|
+
if (publicHost && parsedApiUrl.protocol !== "https:") {
|
|
1551
|
+
throw new Error(
|
|
1552
|
+
`Customer online profile requires HTTPS for public control-plane hosts. Received ${options.apiUrl}.`
|
|
1553
|
+
);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1438
1556
|
if (options.profile !== "customer_airgapped") {
|
|
1439
1557
|
return;
|
|
1440
1558
|
}
|
|
@@ -1465,10 +1583,9 @@ function buildWhiteboxWorkerOptions(profile, baseOptions) {
|
|
|
1465
1583
|
logger: baseOptions.logger
|
|
1466
1584
|
};
|
|
1467
1585
|
}
|
|
1468
|
-
function
|
|
1586
|
+
function parseApiUrl(apiUrl) {
|
|
1469
1587
|
try {
|
|
1470
|
-
|
|
1471
|
-
return parsed.hostname.toLowerCase();
|
|
1588
|
+
return new URL(apiUrl);
|
|
1472
1589
|
} catch {
|
|
1473
1590
|
return null;
|
|
1474
1591
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -74,10 +74,14 @@ var Transport = class {
|
|
|
74
74
|
async request(path, options = {}, requestId) {
|
|
75
75
|
const url = `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
76
76
|
const headers = {
|
|
77
|
-
"Content-Type": "application/json",
|
|
78
77
|
"Accept": "application/json",
|
|
79
78
|
...options.headers || {}
|
|
80
79
|
};
|
|
80
|
+
const hasExplicitContentType = Object.keys(headers).some((key) => key.toLowerCase() === "content-type");
|
|
81
|
+
const hasBody = options.body !== void 0 && options.body !== null;
|
|
82
|
+
if (hasBody && !hasExplicitContentType) {
|
|
83
|
+
headers["Content-Type"] = "application/json";
|
|
84
|
+
}
|
|
81
85
|
if (this.apiKey) {
|
|
82
86
|
headers["x-api-key"] = this.apiKey;
|
|
83
87
|
}
|
|
@@ -337,11 +341,29 @@ var Forg3tClient = class {
|
|
|
337
341
|
body: JSON.stringify(data)
|
|
338
342
|
}, requestId);
|
|
339
343
|
}
|
|
340
|
-
async rotateApiKey(keyId, requestId) {
|
|
341
|
-
|
|
344
|
+
async rotateApiKey(projectId, keyId, requestId) {
|
|
345
|
+
if (!projectId || !keyId) {
|
|
346
|
+
throw new Error("rotateApiKey requires both projectId and keyId.");
|
|
347
|
+
}
|
|
348
|
+
const existingKeys = await this.listApiKeys(projectId, requestId);
|
|
349
|
+
const current = existingKeys.find((item) => item.id === keyId);
|
|
350
|
+
if (!current) {
|
|
351
|
+
throw new Forg3tNotFoundError(`API key ${keyId} was not found in project ${projectId}.`, requestId);
|
|
352
|
+
}
|
|
353
|
+
const rotated = await this.createApiKey(projectId, {
|
|
354
|
+
name: current.name,
|
|
355
|
+
...current.expiresAt ? { expiresAt: current.expiresAt } : {}
|
|
356
|
+
}, requestId);
|
|
357
|
+
await this.revokeApiKey(projectId, keyId, requestId);
|
|
358
|
+
return rotated;
|
|
342
359
|
}
|
|
343
|
-
async revokeApiKey(keyId, requestId) {
|
|
344
|
-
|
|
360
|
+
async revokeApiKey(projectId, keyId, requestId) {
|
|
361
|
+
if (!projectId || !keyId) {
|
|
362
|
+
throw new Error("revokeApiKey requires both projectId and keyId.");
|
|
363
|
+
}
|
|
364
|
+
return this.transport.request(`/v1/projects/${projectId}/api-keys/${keyId}`, {
|
|
365
|
+
method: "DELETE"
|
|
366
|
+
}, requestId);
|
|
345
367
|
}
|
|
346
368
|
// --- Jobs ---
|
|
347
369
|
async submitJob(projectId, data, requestId) {
|
|
@@ -351,6 +373,8 @@ var Forg3tClient = class {
|
|
|
351
373
|
};
|
|
352
374
|
if (data.type === "MODEL_UNLEARN") {
|
|
353
375
|
this.assertModelUnlearnPreflight(normalizedPayload);
|
|
376
|
+
} else if (data.type === "ADAPTER_UNLEARN") {
|
|
377
|
+
this.assertAdapterUnlearnPreflight(normalizedPayload);
|
|
354
378
|
}
|
|
355
379
|
const res = await this.transport.request(`/v1/projects/${projectId}/jobs`, {
|
|
356
380
|
method: "POST",
|
|
@@ -575,18 +599,67 @@ var Forg3tClient = class {
|
|
|
575
599
|
}
|
|
576
600
|
}
|
|
577
601
|
if (data.accessLevel === "layer_a_only") {
|
|
602
|
+
const rag = data.execution?.rag;
|
|
578
603
|
const target = data.execution?.target;
|
|
579
|
-
|
|
580
|
-
|
|
604
|
+
const adapter = data.execution?.adapter;
|
|
605
|
+
if (adapter) {
|
|
606
|
+
throw new Error("createUnlearningRequest: execution.adapter is only valid for layer_a_and_b.");
|
|
581
607
|
}
|
|
582
|
-
if (
|
|
583
|
-
throw new Error(
|
|
608
|
+
if (target && rag) {
|
|
609
|
+
throw new Error("createUnlearningRequest: execution.target and execution.rag are mutually exclusive for layer_a_only.");
|
|
584
610
|
}
|
|
585
|
-
if (
|
|
586
|
-
|
|
611
|
+
if (rag) {
|
|
612
|
+
if (rag.backend !== "pgvector_postgres") {
|
|
613
|
+
throw new Error("createUnlearningRequest: execution.rag.backend must be pgvector_postgres.");
|
|
614
|
+
}
|
|
615
|
+
if (data.target.type !== "document_id") {
|
|
616
|
+
throw new Error("createUnlearningRequest: the official RAG lane currently supports target.type=document_id only.");
|
|
617
|
+
}
|
|
618
|
+
if (!Array.isArray(data.scope?.integrationIds) || data.scope.integrationIds.length !== 1) {
|
|
619
|
+
throw new Error("createUnlearningRequest: the official RAG lane requires exactly one scope.integrationIds entry.");
|
|
620
|
+
}
|
|
621
|
+
if (data.execution?.routing?.lane && data.execution.routing.lane !== "project_scoped") {
|
|
622
|
+
throw new Error("createUnlearningRequest: execution.routing.lane must be project_scoped for the official RAG lane.");
|
|
623
|
+
}
|
|
624
|
+
} else {
|
|
625
|
+
if (!target) {
|
|
626
|
+
throw new Error("createUnlearningRequest: execution.target is required for layer_a_only unless execution.rag is provided.");
|
|
627
|
+
}
|
|
628
|
+
if ((target.provider === "openai" || target.provider === "groq") && !target.model?.trim()) {
|
|
629
|
+
throw new Error(`createUnlearningRequest: execution.target.model is required when provider=${target.provider}.`);
|
|
630
|
+
}
|
|
631
|
+
if ((target.provider === "http_generic" || target.provider === "custom") && !target.endpoint?.trim()) {
|
|
632
|
+
throw new Error(`createUnlearningRequest: execution.target.endpoint is required when provider=${target.provider}.`);
|
|
633
|
+
}
|
|
587
634
|
}
|
|
588
635
|
}
|
|
589
636
|
if (data.accessLevel === "layer_a_and_b") {
|
|
637
|
+
const adapter = data.execution?.adapter;
|
|
638
|
+
if (adapter) {
|
|
639
|
+
if (adapter.backend !== "peft_lora_safetensors") {
|
|
640
|
+
throw new Error("createUnlearningRequest: execution.adapter.backend must be peft_lora_safetensors.");
|
|
641
|
+
}
|
|
642
|
+
if (data.execution?.model?.uri?.trim()) {
|
|
643
|
+
throw new Error("createUnlearningRequest: execution.adapter and execution.model are mutually exclusive for layer_a_and_b.");
|
|
644
|
+
}
|
|
645
|
+
if (!Array.isArray(data.scope?.integrationIds) || data.scope.integrationIds.length !== 1) {
|
|
646
|
+
throw new Error("createUnlearningRequest: the official adapter lane requires exactly one scope.integrationIds entry.");
|
|
647
|
+
}
|
|
648
|
+
if (data.execution?.routing?.lane && data.execution.routing.lane !== "project_scoped") {
|
|
649
|
+
throw new Error("createUnlearningRequest: execution.routing.lane must be project_scoped for the official adapter lane.");
|
|
650
|
+
}
|
|
651
|
+
const method = String(adapter.method || "attenuate_adapter").trim();
|
|
652
|
+
if (!["disable_adapter", "attenuate_adapter"].includes(method)) {
|
|
653
|
+
throw new Error("createUnlearningRequest: execution.adapter.method must be disable_adapter or attenuate_adapter.");
|
|
654
|
+
}
|
|
655
|
+
if (method === "attenuate_adapter") {
|
|
656
|
+
const scaleFactor = Number(adapter.scaleFactor);
|
|
657
|
+
if (!Number.isFinite(scaleFactor) || scaleFactor <= 0 || scaleFactor >= 1) {
|
|
658
|
+
throw new Error("createUnlearningRequest: execution.adapter.scaleFactor must be a finite number between 0 and 1 for attenuate_adapter.");
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
590
663
|
if (!data.execution?.model?.uri?.trim()) {
|
|
591
664
|
throw new Error("createUnlearningRequest: execution.model.uri is required for layer_a_and_b.");
|
|
592
665
|
}
|
|
@@ -658,6 +731,40 @@ var Forg3tClient = class {
|
|
|
658
731
|
);
|
|
659
732
|
}
|
|
660
733
|
}
|
|
734
|
+
assertAdapterUnlearnPreflight(payload) {
|
|
735
|
+
if (!payload || typeof payload !== "object") {
|
|
736
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload must be an object.");
|
|
737
|
+
}
|
|
738
|
+
const asRecord = payload;
|
|
739
|
+
const config = asRecord.config && typeof asRecord.config === "object" && !Array.isArray(asRecord.config) ? asRecord.config : null;
|
|
740
|
+
if (!config) {
|
|
741
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config is required.");
|
|
742
|
+
}
|
|
743
|
+
const targetConfig = config.target_config && typeof config.target_config === "object" && !Array.isArray(config.target_config) ? config.target_config : null;
|
|
744
|
+
const parameters = config.parameters && typeof config.parameters === "object" && !Array.isArray(config.parameters) ? config.parameters : null;
|
|
745
|
+
const adapter = parameters?.adapter && typeof parameters.adapter === "object" && !Array.isArray(parameters.adapter) ? parameters.adapter : null;
|
|
746
|
+
if (!targetConfig) {
|
|
747
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config is required.");
|
|
748
|
+
}
|
|
749
|
+
if (String(targetConfig.backend || "").trim() !== "peft_lora_safetensors") {
|
|
750
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config.backend must be peft_lora_safetensors.");
|
|
751
|
+
}
|
|
752
|
+
const adapterUri = String(targetConfig.adapter_uri || "").trim();
|
|
753
|
+
const adapterUriEnvVar = String(targetConfig.adapter_uri_env_var || "").trim();
|
|
754
|
+
if (!adapterUri && !adapterUriEnvVar) {
|
|
755
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: payload.config.target_config requires adapter_uri or adapter_uri_env_var.");
|
|
756
|
+
}
|
|
757
|
+
const method = String(adapter?.method || "attenuate_adapter").trim();
|
|
758
|
+
if (!["disable_adapter", "attenuate_adapter"].includes(method)) {
|
|
759
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: parameters.adapter.method must be disable_adapter or attenuate_adapter.");
|
|
760
|
+
}
|
|
761
|
+
if (method === "attenuate_adapter") {
|
|
762
|
+
const scaleFactor = Number(adapter?.scaleFactor);
|
|
763
|
+
if (!Number.isFinite(scaleFactor) || scaleFactor <= 0 || scaleFactor >= 1) {
|
|
764
|
+
throw new Error("ADAPTER_UNLEARN preflight failed: parameters.adapter.scaleFactor must be between 0 and 1 for attenuate_adapter.");
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
661
768
|
};
|
|
662
769
|
|
|
663
770
|
// src/types.ts
|
|
@@ -670,6 +777,8 @@ var IntegrationType = /* @__PURE__ */ ((IntegrationType2) => {
|
|
|
670
777
|
IntegrationType2["LANGCHAIN"] = "langchain";
|
|
671
778
|
IntegrationType2["OPENROUTER"] = "openrouter";
|
|
672
779
|
IntegrationType2["OPENAI"] = "openai";
|
|
780
|
+
IntegrationType2["PGVECTOR"] = "pgvector";
|
|
781
|
+
IntegrationType2["ADAPTER"] = "adapter";
|
|
673
782
|
IntegrationType2["CUSTOM"] = "custom";
|
|
674
783
|
return IntegrationType2;
|
|
675
784
|
})(IntegrationType || {});
|
|
@@ -1373,10 +1482,19 @@ var ENTERPRISE_STRICT_QUALITY_GATE_POLICY = {
|
|
|
1373
1482
|
...WHITEBOX_QUALITY_GATE_PRESETS.strict
|
|
1374
1483
|
};
|
|
1375
1484
|
function assertDeploymentCompatibility(options) {
|
|
1376
|
-
const
|
|
1377
|
-
if (!
|
|
1485
|
+
const parsedApiUrl = parseApiUrl(options.apiUrl);
|
|
1486
|
+
if (!parsedApiUrl) {
|
|
1378
1487
|
throw new Error(`Invalid FORG3T_API_URL: ${options.apiUrl}`);
|
|
1379
1488
|
}
|
|
1489
|
+
const normalizedHost = parsedApiUrl.hostname.toLowerCase();
|
|
1490
|
+
if (options.profile === "customer_online") {
|
|
1491
|
+
const publicHost = !isPrivateHost(normalizedHost);
|
|
1492
|
+
if (publicHost && parsedApiUrl.protocol !== "https:") {
|
|
1493
|
+
throw new Error(
|
|
1494
|
+
`Customer online profile requires HTTPS for public control-plane hosts. Received ${options.apiUrl}.`
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1380
1498
|
if (options.profile !== "customer_airgapped") {
|
|
1381
1499
|
return;
|
|
1382
1500
|
}
|
|
@@ -1407,10 +1525,9 @@ function buildWhiteboxWorkerOptions(profile, baseOptions) {
|
|
|
1407
1525
|
logger: baseOptions.logger
|
|
1408
1526
|
};
|
|
1409
1527
|
}
|
|
1410
|
-
function
|
|
1528
|
+
function parseApiUrl(apiUrl) {
|
|
1411
1529
|
try {
|
|
1412
|
-
|
|
1413
|
-
return parsed.hostname.toLowerCase();
|
|
1530
|
+
return new URL(apiUrl);
|
|
1414
1531
|
} catch {
|
|
1415
1532
|
return null;
|
|
1416
1533
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forg3t/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Official TypeScript SDK for Forg3t Protocol",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
"test:whitebox": "node ../../node_modules/ts-node/dist/bin.js tools/whitebox_hardening_smoke.ts",
|
|
29
29
|
"test:example": "npx tsx examples/quickstart.ts",
|
|
30
30
|
"smoke:staging": "node ../../node_modules/ts-node/dist/bin.js examples/staging-smoke.ts",
|
|
31
|
-
"smoke:customer-onboarding": "
|
|
31
|
+
"smoke:customer-onboarding": "npx tsx examples/bootstrap-onboarding.ts",
|
|
32
|
+
"smoke:cleanroom": "node scripts/run_cleanroom_smoke.js",
|
|
33
|
+
"example:bootstrap": "npx tsx examples/bootstrap-onboarding.ts",
|
|
32
34
|
"test:breaking": "node scripts/detect-breaking-changes.js",
|
|
33
35
|
"test:contract": "node tools/probe_contract.mjs",
|
|
34
36
|
"test:exports": "node tools/exports_smoke_esm.mjs && node tools/exports_smoke_cjs.cjs",
|