@centrali-io/centrali-sdk 6.7.0 → 6.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +157 -1
- package/dist/index.js +145 -4
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/client.ts +25 -0
- package/src/internal/auth.ts +25 -2
- package/src/managers/embed.ts +180 -0
- package/src/types/embed.ts +67 -0
package/dist/index.d.ts
CHANGED
|
@@ -2858,6 +2858,66 @@ interface AddAllowedDomainOptions {
|
|
|
2858
2858
|
domain: string;
|
|
2859
2859
|
}
|
|
2860
2860
|
|
|
2861
|
+
/**
|
|
2862
|
+
* Types for the Event Log embed surface (CEN-1301).
|
|
2863
|
+
*
|
|
2864
|
+
* Mirrors the request/response shapes defined by IAM at
|
|
2865
|
+
* services/backend/iam/src/controllers/embedTokenController.ts.
|
|
2866
|
+
* Keep field names in sync with that controller's Zod schemas.
|
|
2867
|
+
*/
|
|
2868
|
+
/**
|
|
2869
|
+
* Capabilities that can be encoded into an embed token.
|
|
2870
|
+
*
|
|
2871
|
+
* - `events:read` — list + retrieve event-log rows for the tenant.
|
|
2872
|
+
* IAM unconditionally injects this on every minted token, so omitting
|
|
2873
|
+
* `capabilities` is equivalent to `['events:read']`.
|
|
2874
|
+
* - `events:replay` — allow the iframe to replay a failed delivery. The
|
|
2875
|
+
* issuing service account must also hold `webhook-subscriptions:replay`.
|
|
2876
|
+
*/
|
|
2877
|
+
type EmbedCapability = 'events:read' | 'events:replay';
|
|
2878
|
+
interface IssueEmbedTokenInput {
|
|
2879
|
+
/**
|
|
2880
|
+
* Tenant id the embed is allowed to read. Burned into the token claim;
|
|
2881
|
+
* the data-service auto-injects this as a filter on every query the
|
|
2882
|
+
* iframe makes. Centrali never interprets the bytes — treat it as
|
|
2883
|
+
* opaque (1-255 chars).
|
|
2884
|
+
*/
|
|
2885
|
+
tenantId: string;
|
|
2886
|
+
/**
|
|
2887
|
+
* Defaults to `['events:read']`. Pass `['events:read', 'events:replay']`
|
|
2888
|
+
* to allow the iframe's "Replay" action. The issuing service account
|
|
2889
|
+
* must already hold the corresponding capability.
|
|
2890
|
+
*/
|
|
2891
|
+
capabilities?: EmbedCapability[];
|
|
2892
|
+
/**
|
|
2893
|
+
* Optional cohort id. Useful if you want to revoke every token issued
|
|
2894
|
+
* for one of your end-users on logout — mint each with the same
|
|
2895
|
+
* `sessionId`, then call `revokeSession({ sessionId })` later. Server
|
|
2896
|
+
* mints a random one if omitted (returned in the response).
|
|
2897
|
+
*/
|
|
2898
|
+
sessionId?: string;
|
|
2899
|
+
/**
|
|
2900
|
+
* Token TTL in seconds. Defaults to 600 (10 min). Capped at 3600 (1h)
|
|
2901
|
+
* server-side; out-of-range values 400.
|
|
2902
|
+
*/
|
|
2903
|
+
ttlSeconds?: number;
|
|
2904
|
+
}
|
|
2905
|
+
interface IssueEmbedTokenResult {
|
|
2906
|
+
/** `ev_…` JWT for the iframe's URL fragment. */
|
|
2907
|
+
token: string;
|
|
2908
|
+
/** Echo of the input sessionId, or the server-minted one if omitted. */
|
|
2909
|
+
sessionId: string;
|
|
2910
|
+
/** ISO-8601 timestamp at which the token's `exp` claim fires. */
|
|
2911
|
+
expiresAt: string;
|
|
2912
|
+
}
|
|
2913
|
+
interface RevokeEmbedSessionInput {
|
|
2914
|
+
sessionId: string;
|
|
2915
|
+
}
|
|
2916
|
+
interface RevokeEmbedSessionResult {
|
|
2917
|
+
sessionId: string;
|
|
2918
|
+
revokedAt: string;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2861
2921
|
/**
|
|
2862
2922
|
* Internal configuration for realtime connections.
|
|
2863
2923
|
*/
|
|
@@ -5182,6 +5242,90 @@ declare class WebhookSubscriptionsManager {
|
|
|
5182
5242
|
getPayloadVersions(): Promise<ApiResponse<WebhookPayloadVersions>>;
|
|
5183
5243
|
}
|
|
5184
5244
|
|
|
5245
|
+
/**
|
|
5246
|
+
* Embed manager — server-side helpers for the white-label Event Log iframe
|
|
5247
|
+
* (`embed.centrali.io/v1/event-log`, CEN-1301).
|
|
5248
|
+
*
|
|
5249
|
+
* Why this lives outside the main axios instance:
|
|
5250
|
+
* The shared client mints workspace JWTs with `resource=<data-service>`,
|
|
5251
|
+
* so its `aud` claim is the data plane. IAM's embed issuance endpoint
|
|
5252
|
+
* explicitly rejects data-audienced tokens (`audience_mismatch`) — see
|
|
5253
|
+
* services/backend/iam/src/controllers/embedTokenController.ts. This
|
|
5254
|
+
* manager keeps its own axios instance pointed at the IAM host and its
|
|
5255
|
+
* own cached IAM-audienced workspace JWT, minted via
|
|
5256
|
+
* `fetchIamAudiencedToken`.
|
|
5257
|
+
*
|
|
5258
|
+
* Confidential credentials only: IAM also rejects publishable keys and
|
|
5259
|
+
* service-account dev tokens. The manager throws up front if the SDK was
|
|
5260
|
+
* constructed without `clientId` + `clientSecret`.
|
|
5261
|
+
*/
|
|
5262
|
+
|
|
5263
|
+
interface EmbedManagerOptions {
|
|
5264
|
+
baseUrl: string;
|
|
5265
|
+
workspaceId: string;
|
|
5266
|
+
clientId?: string;
|
|
5267
|
+
clientSecret?: string;
|
|
5268
|
+
/**
|
|
5269
|
+
* Pass-through of the SDK's `axiosConfig` (custom CA, agent, timeouts,
|
|
5270
|
+
* etc.). The manager always disables HTTP_PROXY/HTTPS_PROXY env vars
|
|
5271
|
+
* to match the main client + token mint, but caller-supplied fields
|
|
5272
|
+
* are merged on top — including an explicit `proxy` override.
|
|
5273
|
+
*/
|
|
5274
|
+
axiosConfig?: AxiosRequestConfig;
|
|
5275
|
+
}
|
|
5276
|
+
/**
|
|
5277
|
+
* Server-side helpers for the Event Log embed iframe. Access via
|
|
5278
|
+
* `client.embed.eventLog`.
|
|
5279
|
+
*
|
|
5280
|
+
* @example
|
|
5281
|
+
* ```ts
|
|
5282
|
+
* const { token, sessionId, expiresAt } = await client.embed.eventLog.issueToken({
|
|
5283
|
+
* tenantId: customerOrgId,
|
|
5284
|
+
* capabilities: ['events:read', 'events:replay'],
|
|
5285
|
+
* ttlSeconds: 900,
|
|
5286
|
+
* });
|
|
5287
|
+
*
|
|
5288
|
+
* // Render in your frontend:
|
|
5289
|
+
* // <iframe src={`https://embed.centrali.io/v1/event-log#token=${token}&o=${origin}`} />
|
|
5290
|
+
*
|
|
5291
|
+
* // On user logout:
|
|
5292
|
+
* await client.embed.eventLog.revokeSession({ sessionId });
|
|
5293
|
+
* ```
|
|
5294
|
+
*/
|
|
5295
|
+
declare class EmbedManager {
|
|
5296
|
+
private readonly _eventLog;
|
|
5297
|
+
constructor(opts: EmbedManagerOptions);
|
|
5298
|
+
get eventLog(): EventLogEmbed;
|
|
5299
|
+
}
|
|
5300
|
+
declare class EventLogEmbed {
|
|
5301
|
+
private readonly baseUrl;
|
|
5302
|
+
private readonly workspaceId;
|
|
5303
|
+
private readonly clientId?;
|
|
5304
|
+
private readonly clientSecret?;
|
|
5305
|
+
private readonly axios;
|
|
5306
|
+
/**
|
|
5307
|
+
* Cached IAM-audienced workspace JWT. Reused across calls; refreshed
|
|
5308
|
+
* lazily on 401 (which is what IAM returns when `exp` fires).
|
|
5309
|
+
*/
|
|
5310
|
+
private iamToken;
|
|
5311
|
+
private inflightTokenMint;
|
|
5312
|
+
constructor(opts: EmbedManagerOptions);
|
|
5313
|
+
/**
|
|
5314
|
+
* Mint a short-lived `ev_…` embed token. Hand the result to your
|
|
5315
|
+
* frontend and drop it into the iframe URL fragment as `#token=…&o=…`.
|
|
5316
|
+
*/
|
|
5317
|
+
issueToken(input: IssueEmbedTokenInput): Promise<IssueEmbedTokenResult>;
|
|
5318
|
+
/**
|
|
5319
|
+
* Revoke an embed session (typically tied to your user's logout).
|
|
5320
|
+
* Every embed token carrying this `sessionId` is rejected by
|
|
5321
|
+
* data-service until the entry expires (max token TTL).
|
|
5322
|
+
*/
|
|
5323
|
+
revokeSession(input: RevokeEmbedSessionInput): Promise<RevokeEmbedSessionResult>;
|
|
5324
|
+
private serializeIssueBody;
|
|
5325
|
+
private postWithIamToken;
|
|
5326
|
+
private getIamToken;
|
|
5327
|
+
}
|
|
5328
|
+
|
|
5185
5329
|
/** Mirror of `@centrali/query`'s `ValidateOptions`. */
|
|
5186
5330
|
type QueryValidateOptions = {
|
|
5187
5331
|
rejectReservedClauses?: boolean;
|
|
@@ -5305,6 +5449,7 @@ declare class CentraliSDK {
|
|
|
5305
5449
|
private _files;
|
|
5306
5450
|
private _webhookSubscriptions;
|
|
5307
5451
|
private _query;
|
|
5452
|
+
private _embed;
|
|
5308
5453
|
private isRefreshingToken;
|
|
5309
5454
|
private tokenRefreshPromise;
|
|
5310
5455
|
constructor(options: CentraliSDKOptions);
|
|
@@ -5742,6 +5887,17 @@ declare class CentraliSDK {
|
|
|
5742
5887
|
* ```
|
|
5743
5888
|
*/
|
|
5744
5889
|
get webhookSubscriptions(): WebhookSubscriptionsManager;
|
|
5890
|
+
/**
|
|
5891
|
+
* Server-side helpers for the white-label Event Log embed
|
|
5892
|
+
* (CEN-1301 — see `embed.centrali.io/v1/event-log`). Use to mint
|
|
5893
|
+
* short-lived tokens that scope the iframe to one of your end-user
|
|
5894
|
+
* tenants, and to revoke them on logout.
|
|
5895
|
+
*
|
|
5896
|
+
* Requires the SDK to be constructed with `clientId` + `clientSecret`
|
|
5897
|
+
* (service-account client credentials). Publishable keys and
|
|
5898
|
+
* supplied bearer tokens are rejected by IAM for this surface.
|
|
5899
|
+
*/
|
|
5900
|
+
get embed(): EmbedManager;
|
|
5745
5901
|
/**
|
|
5746
5902
|
* Manually set or update the bearer token for subsequent requests.
|
|
5747
5903
|
*/
|
|
@@ -6126,4 +6282,4 @@ declare class CentraliSDK {
|
|
|
6126
6282
|
checkAuthorization(options: CheckAuthorizationOptions): Promise<ApiResponse<AuthorizationResult>>;
|
|
6127
6283
|
}
|
|
6128
6284
|
|
|
6129
|
-
export { type AcceptSuggestionResult, type AddAllowedDomainOptions, type AllowedDomain, type AllowedDomainsListResponse, AllowedDomainsManager, type AnomalyAnalysisResult, type AnomalyDetectionData, type AnomalyEventType, type AnomalyInsight, type AnomalyInsightData, AnomalyInsightsManager, type ApiResponse, type ArrayPropertyDefinition, AuditLogManager, type AuthorizationResult, type BasePropertyDefinition, type BatchScanResult, type BatchScanStatus, type BooleanPropertyDefinition, type BulkOperationResult, CANONICAL_OPERATORS, type CanonicalOperator, CentraliError, CentraliSDK, type CentraliSDKOptions, type CheckAuthorizationOptions, CollectionsManager, type ComputeEventType, type ComputeFunction, ComputeFunctionsManager, type ComputeJobStatus, type ComputeJobStatusResponse, type ConditionOperator, type CreateComputeFunctionInput, type CreateOrchestrationInput, type CreateSmartQueryInput, type CreateStructureInput, type CreateTriggerInput, type CreateWebhookSubscriptionInput, type DateTimePropertyDefinition, type DateWindowOption, type DeleteRecordOptions, type EndpointResponse, type ExecuteSavedQueryValues, type ExecuteSmartQueryOptions, type ExpandOptions, type FieldCondition, type FieldConditionMap, type FileMetadata, FilesManager, type FilterOperators, type FilterValue, type FunctionMemoryUsage, type FunctionRun, type FunctionRunError, type FunctionRunExecutionSource, type FunctionRunStatus, FunctionRunsManager, type FunctionTrigger, type GetRecordOptions, type IncludeClause, type InsightSeverity, type InsightStatus, type InsightType, type InsightsSummary, type InvokeEndpointOptions, type InvokeTriggerOptions, JOINS_MAX_LENGTH, type JoinClause, type JoinType, type LegacyTranslateOptions, type LegacyTranslateResult, type LegacyTranslateWarning, type ListAllTriggersOptions, type ListCollectionsOptions, type ListComputeFunctionsOptions, type ListFunctionRunsOptions, type ListInsightsOptions, type ListOrchestrationRunsOptions, type ListOrchestrationsOptions, type ListSmartQueryOptions, type ListStructuresOptions, type ListValidationSuggestionsOptions, type ListWebhookDeliveriesOptions, type NumberPropertyDefinition, OPERATOR_METADATA, type ObjectPropertyDefinition, type OperatorMeta, type OperatorTypeApplicability, type OperatorValueShape, type Orchestration, type OrchestrationCaseEvaluation, type OrchestrationCondition, type OrchestrationConditionEvaluation, type OrchestrationDecisionCase, type OrchestrationDecisionResult, type OrchestrationDelayConfig, type OrchestrationEventType, type OrchestrationFailureReason, type OrchestrationOnFailure, type OrchestrationOnSuccess, type OrchestrationRetryConfig, type OrchestrationRun, type OrchestrationRunStatus, type OrchestrationRunStep, OrchestrationRunsManager, type OrchestrationScheduleType, type OrchestrationStatus, type OrchestrationStep, type OrchestrationStepError, type OrchestrationStepStatus, type OrchestrationStepType, type OrchestrationTrigger, type OrchestrationTriggerMetadata, type OrchestrationTriggerType, OrchestrationsManager, type PageClause, type PaginatedResponse, type ParsedUrlQuery, type PropertyDefinition, type PropertyType, type QueryDefinition, type QueryError, type QueryErrorCode, type QueryExecutionMode, type QueryHttpError, type QueryHttpErrorCode, QueryManager, type QueryRecordOptions, type QueryResult, type QueryResultMeta, type QueryValidateOptions, type QueryVariableDefinition, RECORDS_PAGE_DEFAULT_LIMIT, RECORDS_PAGE_MAX_LIMIT, type RealtimeAnomalyDetectionEvent, type RealtimeAnomalyInsightEvent, type RealtimeCloseEvent, type RealtimeError, type RealtimeEvent, type RealtimeEventType, type RealtimeFunctionRunEvent, RealtimeManager, type RealtimeOrchestrationRunEvent, type RealtimeRecordEvent, type RealtimeSubscribeOptions, type RealtimeSubscription, type RealtimeValidationBatchEvent, type RealtimeValidationSuggestionEvent, type RecordEventType, RecordEvents, type RecordTtlOptions, RecordsManager, type ReferencePropertyDefinition, type ResourceCategory, type SavedQueryDefinition, type SavedQueryScalarBinding, type ScalarValue, type SchemaDiscoveryMode, type SearchHit, type SearchOptions, type SearchResponse, type SelectClause, SmartQueriesManager, type SmartQuery, type SmartQueryDefinition, type SmartQueryExecuteResult, type SmartQueryFieldCondition, type SmartQueryJoin, type SmartQuerySort, type SmartQueryWhereClause, type SortClause, type StepEncryptedParam, type StringPropertyDefinition, type Structure, StructuresManager, type TestComputeFunctionInput, type TestComputeFunctionResult, type TestSmartQueryInput, type TextSearchClause, type TriggerExecutionType, type TriggerHealthMetrics, type TriggerHealthStatus, type TriggerInvokeResponse, type TriggerOrchestrationRunOptions, type TriggerScanOptions, type TriggerWithHealth, TriggersManager, type UpdateComputeFunctionInput, type UpdateOrchestrationInput, type UpdateSmartQueryInput, type UpdateStructureInput, type UpdateTriggerInput, type UpdateWebhookSubscriptionInput, type UrlParserOptions, type ValidateStructureInput, type ValidationBatchData, type ValidationEventType, type ValidationIssueType, ValidationManager, type ValidationResult, type ValidationSuggestion, type ValidationSuggestionData, type ValidationSuggestionStatus, type ValidationSummary, type VariableType, type WaitForScanOptions, type WebhookCancelResponse, type WebhookDeliveriesListMeta, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookDeliverySummary, type WebhookPayloadVersions, type WebhookReplayResponse, type WebhookSubscription, WebhookSubscriptionsManager, type WhereExpression, fetchClientToken, getAllowedDomainsApiPath, getAnomalyAnalysisTriggerApiPath, getAnomalyInsightAcknowledgeApiPath, getAnomalyInsightDismissApiPath, getAnomalyInsightsApiPath, getAnomalyInsightsBulkAcknowledgeApiPath, getAnomalyInsightsSummaryApiPath, getApiUrl, getAuthUrl, getCollectionBySlugApiPath, getCollectionInsightsApiPath, getCollectionValidateApiPath, getCollectionsApiPath, getComputeFunctionTestApiPath, getComputeFunctionsApiPath, getComputeJobStatusApiPath, getEndpointApiPath, getFileUploadApiPath, getFilesCanonicalApiPath, getFunctionRunsApiPath, getFunctionRunsByFunctionApiPath, getFunctionRunsByTriggerApiPath, getFunctionTriggerExecuteApiPath, getFunctionTriggerPauseApiPath, getFunctionTriggerResumeApiPath, getFunctionTriggersApiPath, getOrchestrationRunStepsApiPath, getOrchestrationRunsApiPath, getOrchestrationRunsCanonicalApiPath, getOrchestrationsApiPath, getRealtimeUrl, getRecordApiPath, getSavedQueryCanonicalByIdPath, getSavedQueryCanonicalCollectionPath, getSavedQueryCanonicalExecutePath, getSavedQueryCanonicalTestPath, getSearchApiPath, getSmartQueriesApiPath, getSmartQueriesStructureApiPath, getSmartQueryByNameApiPath, getSmartQueryExecuteApiPath, getSmartQueryTestApiPath, getStructureBySlugApiPath, getStructureInsightsApiPath, getStructureValidateApiPath, getStructuresApiPath, getValidationBulkAcceptApiPath, getValidationBulkRejectApiPath, getValidationPendingCountApiPath, getValidationRecordSuggestionsApiPath, getValidationScanApiPath, getValidationSuggestionAcceptApiPath, getValidationSuggestionRejectApiPath, getValidationSuggestionsApiPath, getValidationSummaryApiPath, getWebhookDeliveryCancelApiPath, getWebhookDeliveryRetryApiPath, getWebhookPayloadVersionsApiPath, getWebhookSubscriptionDeliveriesApiPath, getWebhookSubscriptionRotateSecretApiPath, getWebhookSubscriptionsApiPath, isCentraliError, operatorsForFieldType };
|
|
6285
|
+
export { type AcceptSuggestionResult, type AddAllowedDomainOptions, type AllowedDomain, type AllowedDomainsListResponse, AllowedDomainsManager, type AnomalyAnalysisResult, type AnomalyDetectionData, type AnomalyEventType, type AnomalyInsight, type AnomalyInsightData, AnomalyInsightsManager, type ApiResponse, type ArrayPropertyDefinition, AuditLogManager, type AuthorizationResult, type BasePropertyDefinition, type BatchScanResult, type BatchScanStatus, type BooleanPropertyDefinition, type BulkOperationResult, CANONICAL_OPERATORS, type CanonicalOperator, CentraliError, CentraliSDK, type CentraliSDKOptions, type CheckAuthorizationOptions, CollectionsManager, type ComputeEventType, type ComputeFunction, ComputeFunctionsManager, type ComputeJobStatus, type ComputeJobStatusResponse, type ConditionOperator, type CreateComputeFunctionInput, type CreateOrchestrationInput, type CreateSmartQueryInput, type CreateStructureInput, type CreateTriggerInput, type CreateWebhookSubscriptionInput, type DateTimePropertyDefinition, type DateWindowOption, type DeleteRecordOptions, type EmbedCapability, EmbedManager, type EndpointResponse, EventLogEmbed, type ExecuteSavedQueryValues, type ExecuteSmartQueryOptions, type ExpandOptions, type FieldCondition, type FieldConditionMap, type FileMetadata, FilesManager, type FilterOperators, type FilterValue, type FunctionMemoryUsage, type FunctionRun, type FunctionRunError, type FunctionRunExecutionSource, type FunctionRunStatus, FunctionRunsManager, type FunctionTrigger, type GetRecordOptions, type IncludeClause, type InsightSeverity, type InsightStatus, type InsightType, type InsightsSummary, type InvokeEndpointOptions, type InvokeTriggerOptions, type IssueEmbedTokenInput, type IssueEmbedTokenResult, JOINS_MAX_LENGTH, type JoinClause, type JoinType, type LegacyTranslateOptions, type LegacyTranslateResult, type LegacyTranslateWarning, type ListAllTriggersOptions, type ListCollectionsOptions, type ListComputeFunctionsOptions, type ListFunctionRunsOptions, type ListInsightsOptions, type ListOrchestrationRunsOptions, type ListOrchestrationsOptions, type ListSmartQueryOptions, type ListStructuresOptions, type ListValidationSuggestionsOptions, type ListWebhookDeliveriesOptions, type NumberPropertyDefinition, OPERATOR_METADATA, type ObjectPropertyDefinition, type OperatorMeta, type OperatorTypeApplicability, type OperatorValueShape, type Orchestration, type OrchestrationCaseEvaluation, type OrchestrationCondition, type OrchestrationConditionEvaluation, type OrchestrationDecisionCase, type OrchestrationDecisionResult, type OrchestrationDelayConfig, type OrchestrationEventType, type OrchestrationFailureReason, type OrchestrationOnFailure, type OrchestrationOnSuccess, type OrchestrationRetryConfig, type OrchestrationRun, type OrchestrationRunStatus, type OrchestrationRunStep, OrchestrationRunsManager, type OrchestrationScheduleType, type OrchestrationStatus, type OrchestrationStep, type OrchestrationStepError, type OrchestrationStepStatus, type OrchestrationStepType, type OrchestrationTrigger, type OrchestrationTriggerMetadata, type OrchestrationTriggerType, OrchestrationsManager, type PageClause, type PaginatedResponse, type ParsedUrlQuery, type PropertyDefinition, type PropertyType, type QueryDefinition, type QueryError, type QueryErrorCode, type QueryExecutionMode, type QueryHttpError, type QueryHttpErrorCode, QueryManager, type QueryRecordOptions, type QueryResult, type QueryResultMeta, type QueryValidateOptions, type QueryVariableDefinition, RECORDS_PAGE_DEFAULT_LIMIT, RECORDS_PAGE_MAX_LIMIT, type RealtimeAnomalyDetectionEvent, type RealtimeAnomalyInsightEvent, type RealtimeCloseEvent, type RealtimeError, type RealtimeEvent, type RealtimeEventType, type RealtimeFunctionRunEvent, RealtimeManager, type RealtimeOrchestrationRunEvent, type RealtimeRecordEvent, type RealtimeSubscribeOptions, type RealtimeSubscription, type RealtimeValidationBatchEvent, type RealtimeValidationSuggestionEvent, type RecordEventType, RecordEvents, type RecordTtlOptions, RecordsManager, type ReferencePropertyDefinition, type ResourceCategory, type RevokeEmbedSessionInput, type RevokeEmbedSessionResult, type SavedQueryDefinition, type SavedQueryScalarBinding, type ScalarValue, type SchemaDiscoveryMode, type SearchHit, type SearchOptions, type SearchResponse, type SelectClause, SmartQueriesManager, type SmartQuery, type SmartQueryDefinition, type SmartQueryExecuteResult, type SmartQueryFieldCondition, type SmartQueryJoin, type SmartQuerySort, type SmartQueryWhereClause, type SortClause, type StepEncryptedParam, type StringPropertyDefinition, type Structure, StructuresManager, type TestComputeFunctionInput, type TestComputeFunctionResult, type TestSmartQueryInput, type TextSearchClause, type TriggerExecutionType, type TriggerHealthMetrics, type TriggerHealthStatus, type TriggerInvokeResponse, type TriggerOrchestrationRunOptions, type TriggerScanOptions, type TriggerWithHealth, TriggersManager, type UpdateComputeFunctionInput, type UpdateOrchestrationInput, type UpdateSmartQueryInput, type UpdateStructureInput, type UpdateTriggerInput, type UpdateWebhookSubscriptionInput, type UrlParserOptions, type ValidateStructureInput, type ValidationBatchData, type ValidationEventType, type ValidationIssueType, ValidationManager, type ValidationResult, type ValidationSuggestion, type ValidationSuggestionData, type ValidationSuggestionStatus, type ValidationSummary, type VariableType, type WaitForScanOptions, type WebhookCancelResponse, type WebhookDeliveriesListMeta, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookDeliverySummary, type WebhookPayloadVersions, type WebhookReplayResponse, type WebhookSubscription, WebhookSubscriptionsManager, type WhereExpression, fetchClientToken, getAllowedDomainsApiPath, getAnomalyAnalysisTriggerApiPath, getAnomalyInsightAcknowledgeApiPath, getAnomalyInsightDismissApiPath, getAnomalyInsightsApiPath, getAnomalyInsightsBulkAcknowledgeApiPath, getAnomalyInsightsSummaryApiPath, getApiUrl, getAuthUrl, getCollectionBySlugApiPath, getCollectionInsightsApiPath, getCollectionValidateApiPath, getCollectionsApiPath, getComputeFunctionTestApiPath, getComputeFunctionsApiPath, getComputeJobStatusApiPath, getEndpointApiPath, getFileUploadApiPath, getFilesCanonicalApiPath, getFunctionRunsApiPath, getFunctionRunsByFunctionApiPath, getFunctionRunsByTriggerApiPath, getFunctionTriggerExecuteApiPath, getFunctionTriggerPauseApiPath, getFunctionTriggerResumeApiPath, getFunctionTriggersApiPath, getOrchestrationRunStepsApiPath, getOrchestrationRunsApiPath, getOrchestrationRunsCanonicalApiPath, getOrchestrationsApiPath, getRealtimeUrl, getRecordApiPath, getSavedQueryCanonicalByIdPath, getSavedQueryCanonicalCollectionPath, getSavedQueryCanonicalExecutePath, getSavedQueryCanonicalTestPath, getSearchApiPath, getSmartQueriesApiPath, getSmartQueriesStructureApiPath, getSmartQueryByNameApiPath, getSmartQueryExecuteApiPath, getSmartQueryTestApiPath, getStructureBySlugApiPath, getStructureInsightsApiPath, getStructureValidateApiPath, getStructuresApiPath, getValidationBulkAcceptApiPath, getValidationBulkRejectApiPath, getValidationPendingCountApiPath, getValidationRecordSuggestionsApiPath, getValidationScanApiPath, getValidationSuggestionAcceptApiPath, getValidationSuggestionRejectApiPath, getValidationSuggestionsApiPath, getValidationSummaryApiPath, getWebhookDeliveryCancelApiPath, getWebhookDeliveryRetryApiPath, getWebhookPayloadVersionsApiPath, getWebhookSubscriptionDeliveriesApiPath, getWebhookSubscriptionRotateSecretApiPath, getWebhookSubscriptionsApiPath, isCentraliError, operatorsForFieldType };
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,8 @@ __export(index_exports, {
|
|
|
75
75
|
CentraliSDK: () => CentraliSDK,
|
|
76
76
|
CollectionsManager: () => CollectionsManager,
|
|
77
77
|
ComputeFunctionsManager: () => ComputeFunctionsManager,
|
|
78
|
+
EmbedManager: () => EmbedManager,
|
|
79
|
+
EventLogEmbed: () => EventLogEmbed,
|
|
78
80
|
FilesManager: () => FilesManager,
|
|
79
81
|
FunctionRunsManager: () => FunctionRunsManager,
|
|
80
82
|
JOINS_MAX_LENGTH: () => JOINS_MAX_LENGTH,
|
|
@@ -410,14 +412,25 @@ function encodeFormData(data) {
|
|
|
410
412
|
}
|
|
411
413
|
function fetchClientToken(clientId, clientSecret, baseUrl) {
|
|
412
414
|
return __async(this, null, function* () {
|
|
413
|
-
const authUrl = getAuthUrl(baseUrl);
|
|
414
415
|
const apiUrl = getApiUrl(baseUrl);
|
|
416
|
+
return fetchClientTokenForResource(clientId, clientSecret, baseUrl, `${apiUrl}/data`);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
function fetchIamAudiencedToken(clientId, clientSecret, baseUrl) {
|
|
420
|
+
return __async(this, null, function* () {
|
|
421
|
+
const authUrl = getAuthUrl(baseUrl);
|
|
422
|
+
return fetchClientTokenForResource(clientId, clientSecret, baseUrl, authUrl);
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
function fetchClientTokenForResource(clientId, clientSecret, baseUrl, resource) {
|
|
426
|
+
return __async(this, null, function* () {
|
|
427
|
+
const authUrl = getAuthUrl(baseUrl);
|
|
415
428
|
const tokenEndpoint = `${authUrl}/token`;
|
|
416
429
|
const form = encodeFormData({
|
|
417
430
|
grant_type: "client_credentials",
|
|
418
431
|
client_id: clientId,
|
|
419
432
|
client_secret: clientSecret,
|
|
420
|
-
resource
|
|
433
|
+
resource
|
|
421
434
|
});
|
|
422
435
|
const resp = yield import_axios2.default.post(
|
|
423
436
|
tokenEndpoint,
|
|
@@ -8020,8 +8033,111 @@ var WebhookSubscriptionsManager = class {
|
|
|
8020
8033
|
}
|
|
8021
8034
|
};
|
|
8022
8035
|
|
|
8023
|
-
// src/
|
|
8036
|
+
// src/managers/embed.ts
|
|
8024
8037
|
var import_axios3 = __toESM(require("axios"));
|
|
8038
|
+
var EmbedManager = class {
|
|
8039
|
+
constructor(opts) {
|
|
8040
|
+
this._eventLog = new EventLogEmbed(opts);
|
|
8041
|
+
}
|
|
8042
|
+
get eventLog() {
|
|
8043
|
+
return this._eventLog;
|
|
8044
|
+
}
|
|
8045
|
+
};
|
|
8046
|
+
var EventLogEmbed = class {
|
|
8047
|
+
constructor(opts) {
|
|
8048
|
+
/**
|
|
8049
|
+
* Cached IAM-audienced workspace JWT. Reused across calls; refreshed
|
|
8050
|
+
* lazily on 401 (which is what IAM returns when `exp` fires).
|
|
8051
|
+
*/
|
|
8052
|
+
this.iamToken = null;
|
|
8053
|
+
this.inflightTokenMint = null;
|
|
8054
|
+
this.baseUrl = opts.baseUrl;
|
|
8055
|
+
this.workspaceId = opts.workspaceId;
|
|
8056
|
+
this.clientId = opts.clientId;
|
|
8057
|
+
this.clientSecret = opts.clientSecret;
|
|
8058
|
+
this.axios = import_axios3.default.create(__spreadValues({
|
|
8059
|
+
baseURL: getAuthUrl(opts.baseUrl),
|
|
8060
|
+
headers: { "Content-Type": "application/json" },
|
|
8061
|
+
proxy: false
|
|
8062
|
+
}, opts.axiosConfig));
|
|
8063
|
+
}
|
|
8064
|
+
/**
|
|
8065
|
+
* Mint a short-lived `ev_…` embed token. Hand the result to your
|
|
8066
|
+
* frontend and drop it into the iframe URL fragment as `#token=…&o=…`.
|
|
8067
|
+
*/
|
|
8068
|
+
issueToken(input) {
|
|
8069
|
+
return __async(this, null, function* () {
|
|
8070
|
+
const path = `/workspace/${this.workspaceId}/embed/event-log/issue-token`;
|
|
8071
|
+
return this.postWithIamToken(path, this.serializeIssueBody(input));
|
|
8072
|
+
});
|
|
8073
|
+
}
|
|
8074
|
+
/**
|
|
8075
|
+
* Revoke an embed session (typically tied to your user's logout).
|
|
8076
|
+
* Every embed token carrying this `sessionId` is rejected by
|
|
8077
|
+
* data-service until the entry expires (max token TTL).
|
|
8078
|
+
*/
|
|
8079
|
+
revokeSession(input) {
|
|
8080
|
+
return __async(this, null, function* () {
|
|
8081
|
+
const path = `/workspace/${this.workspaceId}/embed/event-log/revoke-session`;
|
|
8082
|
+
return this.postWithIamToken(path, { sessionId: input.sessionId });
|
|
8083
|
+
});
|
|
8084
|
+
}
|
|
8085
|
+
serializeIssueBody(input) {
|
|
8086
|
+
const body = { tenantId: input.tenantId };
|
|
8087
|
+
if (input.capabilities) body.capabilities = input.capabilities;
|
|
8088
|
+
if (input.sessionId) body.sessionId = input.sessionId;
|
|
8089
|
+
if (input.ttlSeconds !== void 0) body.ttlSeconds = input.ttlSeconds;
|
|
8090
|
+
return body;
|
|
8091
|
+
}
|
|
8092
|
+
postWithIamToken(path, body) {
|
|
8093
|
+
return __async(this, null, function* () {
|
|
8094
|
+
var _a;
|
|
8095
|
+
const token = yield this.getIamToken();
|
|
8096
|
+
try {
|
|
8097
|
+
const resp = yield this.axios.post(path, body, {
|
|
8098
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
8099
|
+
});
|
|
8100
|
+
return resp.data;
|
|
8101
|
+
} catch (err) {
|
|
8102
|
+
const status = (_a = err == null ? void 0 : err.response) == null ? void 0 : _a.status;
|
|
8103
|
+
if (status === 401) {
|
|
8104
|
+
this.iamToken = null;
|
|
8105
|
+
const fresh = yield this.getIamToken();
|
|
8106
|
+
const resp = yield this.axios.post(path, body, {
|
|
8107
|
+
headers: { Authorization: `Bearer ${fresh}` }
|
|
8108
|
+
});
|
|
8109
|
+
return resp.data;
|
|
8110
|
+
}
|
|
8111
|
+
throw err;
|
|
8112
|
+
}
|
|
8113
|
+
});
|
|
8114
|
+
}
|
|
8115
|
+
getIamToken() {
|
|
8116
|
+
return __async(this, null, function* () {
|
|
8117
|
+
if (this.iamToken) return this.iamToken;
|
|
8118
|
+
if (this.inflightTokenMint) return this.inflightTokenMint;
|
|
8119
|
+
if (!this.clientId || !this.clientSecret) {
|
|
8120
|
+
throw new Error(
|
|
8121
|
+
"Embed token issuance requires the SDK to be configured with clientId + clientSecret (service-account client credentials). Publishable keys and supplied bearer tokens are not accepted by IAM for this endpoint."
|
|
8122
|
+
);
|
|
8123
|
+
}
|
|
8124
|
+
this.inflightTokenMint = fetchIamAudiencedToken(
|
|
8125
|
+
this.clientId,
|
|
8126
|
+
this.clientSecret,
|
|
8127
|
+
this.baseUrl
|
|
8128
|
+
);
|
|
8129
|
+
try {
|
|
8130
|
+
this.iamToken = yield this.inflightTokenMint;
|
|
8131
|
+
return this.iamToken;
|
|
8132
|
+
} finally {
|
|
8133
|
+
this.inflightTokenMint = null;
|
|
8134
|
+
}
|
|
8135
|
+
});
|
|
8136
|
+
}
|
|
8137
|
+
};
|
|
8138
|
+
|
|
8139
|
+
// src/client.ts
|
|
8140
|
+
var import_axios4 = __toESM(require("axios"));
|
|
8025
8141
|
var import_qs = __toESM(require("qs"));
|
|
8026
8142
|
|
|
8027
8143
|
// src/internal/queryGuard.ts
|
|
@@ -8051,6 +8167,7 @@ var CentraliSDK = class {
|
|
|
8051
8167
|
this._files = null;
|
|
8052
8168
|
this._webhookSubscriptions = null;
|
|
8053
8169
|
this._query = null;
|
|
8170
|
+
this._embed = null;
|
|
8054
8171
|
this.isRefreshingToken = false;
|
|
8055
8172
|
this.tokenRefreshPromise = null;
|
|
8056
8173
|
this.options = options;
|
|
@@ -8067,7 +8184,7 @@ var CentraliSDK = class {
|
|
|
8067
8184
|
throw new Error("Cannot use getToken with clientId/clientSecret. Use one auth method.");
|
|
8068
8185
|
}
|
|
8069
8186
|
const apiUrl = getApiUrl(options.baseUrl);
|
|
8070
|
-
this.axios =
|
|
8187
|
+
this.axios = import_axios4.default.create(__spreadValues({
|
|
8071
8188
|
baseURL: apiUrl,
|
|
8072
8189
|
paramsSerializer: (params) => import_qs.default.stringify(params, { arrayFormat: "repeat" }),
|
|
8073
8190
|
proxy: false
|
|
@@ -8750,6 +8867,28 @@ var CentraliSDK = class {
|
|
|
8750
8867
|
}
|
|
8751
8868
|
return this._webhookSubscriptions;
|
|
8752
8869
|
}
|
|
8870
|
+
/**
|
|
8871
|
+
* Server-side helpers for the white-label Event Log embed
|
|
8872
|
+
* (CEN-1301 — see `embed.centrali.io/v1/event-log`). Use to mint
|
|
8873
|
+
* short-lived tokens that scope the iframe to one of your end-user
|
|
8874
|
+
* tenants, and to revoke them on logout.
|
|
8875
|
+
*
|
|
8876
|
+
* Requires the SDK to be constructed with `clientId` + `clientSecret`
|
|
8877
|
+
* (service-account client credentials). Publishable keys and
|
|
8878
|
+
* supplied bearer tokens are rejected by IAM for this surface.
|
|
8879
|
+
*/
|
|
8880
|
+
get embed() {
|
|
8881
|
+
if (!this._embed) {
|
|
8882
|
+
this._embed = new EmbedManager({
|
|
8883
|
+
baseUrl: this.options.baseUrl,
|
|
8884
|
+
workspaceId: this.options.workspaceId,
|
|
8885
|
+
clientId: this.options.clientId,
|
|
8886
|
+
clientSecret: this.options.clientSecret,
|
|
8887
|
+
axiosConfig: this.options.axiosConfig
|
|
8888
|
+
});
|
|
8889
|
+
}
|
|
8890
|
+
return this._embed;
|
|
8891
|
+
}
|
|
8753
8892
|
/**
|
|
8754
8893
|
* Manually set or update the bearer token for subsequent requests.
|
|
8755
8894
|
*/
|
|
@@ -9259,6 +9398,8 @@ var CentraliSDK = class {
|
|
|
9259
9398
|
CentraliSDK,
|
|
9260
9399
|
CollectionsManager,
|
|
9261
9400
|
ComputeFunctionsManager,
|
|
9401
|
+
EmbedManager,
|
|
9402
|
+
EventLogEmbed,
|
|
9262
9403
|
FilesManager,
|
|
9263
9404
|
FunctionRunsManager,
|
|
9264
9405
|
JOINS_MAX_LENGTH,
|
package/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ export * from './src/types/insights';
|
|
|
32
32
|
export * from './src/types/validation';
|
|
33
33
|
export * from './src/types/webhooks';
|
|
34
34
|
export * from './src/types/allowedDomains';
|
|
35
|
+
export * from './src/types/embed';
|
|
35
36
|
|
|
36
37
|
// Realtime
|
|
37
38
|
export { RealtimeManager } from './src/realtime/manager';
|
|
@@ -52,6 +53,7 @@ export { FunctionRunsManager } from './src/managers/functionRuns';
|
|
|
52
53
|
export { OrchestrationRunsManager } from './src/managers/orchestrationRuns';
|
|
53
54
|
export { FilesManager, FileMetadata } from './src/managers/files';
|
|
54
55
|
export { WebhookSubscriptionsManager } from './src/managers/webhookSubscriptions';
|
|
56
|
+
export { EmbedManager, EventLogEmbed } from './src/managers/embed';
|
|
55
57
|
export {
|
|
56
58
|
QueryManager,
|
|
57
59
|
type QueryValidateOptions,
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -36,6 +36,7 @@ import { OrchestrationRunsManager } from './managers/orchestrationRuns';
|
|
|
36
36
|
import { FilesManager } from './managers/files';
|
|
37
37
|
import { WebhookSubscriptionsManager } from './managers/webhookSubscriptions';
|
|
38
38
|
import { QueryManager } from './managers/query';
|
|
39
|
+
import { EmbedManager } from './managers/embed';
|
|
39
40
|
|
|
40
41
|
export class CentraliSDK {
|
|
41
42
|
private axios: AxiosInstance;
|
|
@@ -59,6 +60,7 @@ export class CentraliSDK {
|
|
|
59
60
|
private _files: FilesManager | null = null;
|
|
60
61
|
private _webhookSubscriptions: WebhookSubscriptionsManager | null = null;
|
|
61
62
|
private _query: QueryManager | null = null;
|
|
63
|
+
private _embed: EmbedManager | null = null;
|
|
62
64
|
private isRefreshingToken: boolean = false;
|
|
63
65
|
private tokenRefreshPromise: Promise<string> | null = null;
|
|
64
66
|
|
|
@@ -814,6 +816,29 @@ export class CentraliSDK {
|
|
|
814
816
|
return this._webhookSubscriptions;
|
|
815
817
|
}
|
|
816
818
|
|
|
819
|
+
/**
|
|
820
|
+
* Server-side helpers for the white-label Event Log embed
|
|
821
|
+
* (CEN-1301 — see `embed.centrali.io/v1/event-log`). Use to mint
|
|
822
|
+
* short-lived tokens that scope the iframe to one of your end-user
|
|
823
|
+
* tenants, and to revoke them on logout.
|
|
824
|
+
*
|
|
825
|
+
* Requires the SDK to be constructed with `clientId` + `clientSecret`
|
|
826
|
+
* (service-account client credentials). Publishable keys and
|
|
827
|
+
* supplied bearer tokens are rejected by IAM for this surface.
|
|
828
|
+
*/
|
|
829
|
+
public get embed(): EmbedManager {
|
|
830
|
+
if (!this._embed) {
|
|
831
|
+
this._embed = new EmbedManager({
|
|
832
|
+
baseUrl: this.options.baseUrl,
|
|
833
|
+
workspaceId: this.options.workspaceId,
|
|
834
|
+
clientId: this.options.clientId,
|
|
835
|
+
clientSecret: this.options.clientSecret,
|
|
836
|
+
axiosConfig: this.options.axiosConfig,
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
return this._embed;
|
|
840
|
+
}
|
|
841
|
+
|
|
817
842
|
/**
|
|
818
843
|
* Manually set or update the bearer token for subsequent requests.
|
|
819
844
|
*/
|
package/src/internal/auth.ts
CHANGED
|
@@ -14,14 +14,37 @@ export async function fetchClientToken(
|
|
|
14
14
|
clientSecret: string,
|
|
15
15
|
baseUrl: string
|
|
16
16
|
): Promise<string> {
|
|
17
|
-
const authUrl = getAuthUrl(baseUrl);
|
|
18
17
|
const apiUrl = getApiUrl(baseUrl);
|
|
18
|
+
return fetchClientTokenForResource(clientId, clientSecret, baseUrl, `${apiUrl}/data`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Mint an IAM-audienced workspace JWT. Required for the embed-token issuance
|
|
23
|
+
* endpoint, which rejects data-audienced tokens with `audience_mismatch`
|
|
24
|
+
* (see services/backend/iam/src/controllers/embedTokenController.ts).
|
|
25
|
+
*/
|
|
26
|
+
export async function fetchIamAudiencedToken(
|
|
27
|
+
clientId: string,
|
|
28
|
+
clientSecret: string,
|
|
29
|
+
baseUrl: string
|
|
30
|
+
): Promise<string> {
|
|
31
|
+
const authUrl = getAuthUrl(baseUrl);
|
|
32
|
+
return fetchClientTokenForResource(clientId, clientSecret, baseUrl, authUrl);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function fetchClientTokenForResource(
|
|
36
|
+
clientId: string,
|
|
37
|
+
clientSecret: string,
|
|
38
|
+
baseUrl: string,
|
|
39
|
+
resource: string
|
|
40
|
+
): Promise<string> {
|
|
41
|
+
const authUrl = getAuthUrl(baseUrl);
|
|
19
42
|
const tokenEndpoint = `${authUrl}/token`;
|
|
20
43
|
const form = encodeFormData({
|
|
21
44
|
grant_type: 'client_credentials',
|
|
22
45
|
client_id: clientId,
|
|
23
46
|
client_secret: clientSecret,
|
|
24
|
-
resource
|
|
47
|
+
resource,
|
|
25
48
|
});
|
|
26
49
|
const resp = await axios.post(
|
|
27
50
|
tokenEndpoint,
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embed manager — server-side helpers for the white-label Event Log iframe
|
|
3
|
+
* (`embed.centrali.io/v1/event-log`, CEN-1301).
|
|
4
|
+
*
|
|
5
|
+
* Why this lives outside the main axios instance:
|
|
6
|
+
* The shared client mints workspace JWTs with `resource=<data-service>`,
|
|
7
|
+
* so its `aud` claim is the data plane. IAM's embed issuance endpoint
|
|
8
|
+
* explicitly rejects data-audienced tokens (`audience_mismatch`) — see
|
|
9
|
+
* services/backend/iam/src/controllers/embedTokenController.ts. This
|
|
10
|
+
* manager keeps its own axios instance pointed at the IAM host and its
|
|
11
|
+
* own cached IAM-audienced workspace JWT, minted via
|
|
12
|
+
* `fetchIamAudiencedToken`.
|
|
13
|
+
*
|
|
14
|
+
* Confidential credentials only: IAM also rejects publishable keys and
|
|
15
|
+
* service-account dev tokens. The manager throws up front if the SDK was
|
|
16
|
+
* constructed without `clientId` + `clientSecret`.
|
|
17
|
+
*/
|
|
18
|
+
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
19
|
+
|
|
20
|
+
import { fetchIamAudiencedToken } from '../internal/auth';
|
|
21
|
+
import { getAuthUrl } from '../urls';
|
|
22
|
+
import type {
|
|
23
|
+
IssueEmbedTokenInput,
|
|
24
|
+
IssueEmbedTokenResult,
|
|
25
|
+
RevokeEmbedSessionInput,
|
|
26
|
+
RevokeEmbedSessionResult,
|
|
27
|
+
} from '../types/embed';
|
|
28
|
+
|
|
29
|
+
interface EmbedManagerOptions {
|
|
30
|
+
baseUrl: string;
|
|
31
|
+
workspaceId: string;
|
|
32
|
+
clientId?: string;
|
|
33
|
+
clientSecret?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Pass-through of the SDK's `axiosConfig` (custom CA, agent, timeouts,
|
|
36
|
+
* etc.). The manager always disables HTTP_PROXY/HTTPS_PROXY env vars
|
|
37
|
+
* to match the main client + token mint, but caller-supplied fields
|
|
38
|
+
* are merged on top — including an explicit `proxy` override.
|
|
39
|
+
*/
|
|
40
|
+
axiosConfig?: AxiosRequestConfig;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Server-side helpers for the Event Log embed iframe. Access via
|
|
45
|
+
* `client.embed.eventLog`.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const { token, sessionId, expiresAt } = await client.embed.eventLog.issueToken({
|
|
50
|
+
* tenantId: customerOrgId,
|
|
51
|
+
* capabilities: ['events:read', 'events:replay'],
|
|
52
|
+
* ttlSeconds: 900,
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Render in your frontend:
|
|
56
|
+
* // <iframe src={`https://embed.centrali.io/v1/event-log#token=${token}&o=${origin}`} />
|
|
57
|
+
*
|
|
58
|
+
* // On user logout:
|
|
59
|
+
* await client.embed.eventLog.revokeSession({ sessionId });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export class EmbedManager {
|
|
63
|
+
private readonly _eventLog: EventLogEmbed;
|
|
64
|
+
|
|
65
|
+
constructor(opts: EmbedManagerOptions) {
|
|
66
|
+
this._eventLog = new EventLogEmbed(opts);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public get eventLog(): EventLogEmbed {
|
|
70
|
+
return this._eventLog;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export class EventLogEmbed {
|
|
75
|
+
private readonly baseUrl: string;
|
|
76
|
+
private readonly workspaceId: string;
|
|
77
|
+
private readonly clientId?: string;
|
|
78
|
+
private readonly clientSecret?: string;
|
|
79
|
+
private readonly axios: AxiosInstance;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Cached IAM-audienced workspace JWT. Reused across calls; refreshed
|
|
83
|
+
* lazily on 401 (which is what IAM returns when `exp` fires).
|
|
84
|
+
*/
|
|
85
|
+
private iamToken: string | null = null;
|
|
86
|
+
private inflightTokenMint: Promise<string> | null = null;
|
|
87
|
+
|
|
88
|
+
constructor(opts: EmbedManagerOptions) {
|
|
89
|
+
this.baseUrl = opts.baseUrl;
|
|
90
|
+
this.workspaceId = opts.workspaceId;
|
|
91
|
+
this.clientId = opts.clientId;
|
|
92
|
+
this.clientSecret = opts.clientSecret;
|
|
93
|
+
// Mirror the main client + `fetchClientToken`: disable HTTP_PROXY/
|
|
94
|
+
// HTTPS_PROXY env-var pickup by default so embed-token traffic doesn't
|
|
95
|
+
// get silently routed through an outbound proxy a caller hasn't
|
|
96
|
+
// opted into. Caller-supplied `axiosConfig` (custom CA, agent,
|
|
97
|
+
// timeouts, explicit `proxy`) is merged on top.
|
|
98
|
+
this.axios = axios.create({
|
|
99
|
+
baseURL: getAuthUrl(opts.baseUrl),
|
|
100
|
+
headers: { 'Content-Type': 'application/json' },
|
|
101
|
+
proxy: false,
|
|
102
|
+
...opts.axiosConfig,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Mint a short-lived `ev_…` embed token. Hand the result to your
|
|
108
|
+
* frontend and drop it into the iframe URL fragment as `#token=…&o=…`.
|
|
109
|
+
*/
|
|
110
|
+
public async issueToken(input: IssueEmbedTokenInput): Promise<IssueEmbedTokenResult> {
|
|
111
|
+
const path = `/workspace/${this.workspaceId}/embed/event-log/issue-token`;
|
|
112
|
+
return this.postWithIamToken<IssueEmbedTokenResult>(path, this.serializeIssueBody(input));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Revoke an embed session (typically tied to your user's logout).
|
|
117
|
+
* Every embed token carrying this `sessionId` is rejected by
|
|
118
|
+
* data-service until the entry expires (max token TTL).
|
|
119
|
+
*/
|
|
120
|
+
public async revokeSession(input: RevokeEmbedSessionInput): Promise<RevokeEmbedSessionResult> {
|
|
121
|
+
const path = `/workspace/${this.workspaceId}/embed/event-log/revoke-session`;
|
|
122
|
+
return this.postWithIamToken<RevokeEmbedSessionResult>(path, { sessionId: input.sessionId });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private serializeIssueBody(input: IssueEmbedTokenInput): Record<string, unknown> {
|
|
126
|
+
const body: Record<string, unknown> = { tenantId: input.tenantId };
|
|
127
|
+
if (input.capabilities) body.capabilities = input.capabilities;
|
|
128
|
+
if (input.sessionId) body.sessionId = input.sessionId;
|
|
129
|
+
if (input.ttlSeconds !== undefined) body.ttlSeconds = input.ttlSeconds;
|
|
130
|
+
return body;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private async postWithIamToken<T>(path: string, body: Record<string, unknown>): Promise<T> {
|
|
134
|
+
const token = await this.getIamToken();
|
|
135
|
+
try {
|
|
136
|
+
const resp = await this.axios.post<T>(path, body, {
|
|
137
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
138
|
+
});
|
|
139
|
+
return resp.data;
|
|
140
|
+
} catch (err) {
|
|
141
|
+
// Refresh-on-401 once. Any subsequent 401 is propagated so the
|
|
142
|
+
// caller sees the real reason (missing capability, revoked SA,
|
|
143
|
+
// misconfigured audience, etc.) instead of a silent loop.
|
|
144
|
+
const status = (err as AxiosError)?.response?.status;
|
|
145
|
+
if (status === 401) {
|
|
146
|
+
this.iamToken = null;
|
|
147
|
+
const fresh = await this.getIamToken();
|
|
148
|
+
const resp = await this.axios.post<T>(path, body, {
|
|
149
|
+
headers: { Authorization: `Bearer ${fresh}` },
|
|
150
|
+
});
|
|
151
|
+
return resp.data;
|
|
152
|
+
}
|
|
153
|
+
throw err;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private async getIamToken(): Promise<string> {
|
|
158
|
+
if (this.iamToken) return this.iamToken;
|
|
159
|
+
if (this.inflightTokenMint) return this.inflightTokenMint;
|
|
160
|
+
if (!this.clientId || !this.clientSecret) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
'Embed token issuance requires the SDK to be configured with ' +
|
|
163
|
+
'clientId + clientSecret (service-account client credentials). ' +
|
|
164
|
+
'Publishable keys and supplied bearer tokens are not accepted by ' +
|
|
165
|
+
'IAM for this endpoint.',
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
this.inflightTokenMint = fetchIamAudiencedToken(
|
|
169
|
+
this.clientId,
|
|
170
|
+
this.clientSecret,
|
|
171
|
+
this.baseUrl,
|
|
172
|
+
);
|
|
173
|
+
try {
|
|
174
|
+
this.iamToken = await this.inflightTokenMint;
|
|
175
|
+
return this.iamToken;
|
|
176
|
+
} finally {
|
|
177
|
+
this.inflightTokenMint = null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Event Log embed surface (CEN-1301).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the request/response shapes defined by IAM at
|
|
5
|
+
* services/backend/iam/src/controllers/embedTokenController.ts.
|
|
6
|
+
* Keep field names in sync with that controller's Zod schemas.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Capabilities that can be encoded into an embed token.
|
|
11
|
+
*
|
|
12
|
+
* - `events:read` — list + retrieve event-log rows for the tenant.
|
|
13
|
+
* IAM unconditionally injects this on every minted token, so omitting
|
|
14
|
+
* `capabilities` is equivalent to `['events:read']`.
|
|
15
|
+
* - `events:replay` — allow the iframe to replay a failed delivery. The
|
|
16
|
+
* issuing service account must also hold `webhook-subscriptions:replay`.
|
|
17
|
+
*/
|
|
18
|
+
export type EmbedCapability = 'events:read' | 'events:replay';
|
|
19
|
+
|
|
20
|
+
export interface IssueEmbedTokenInput {
|
|
21
|
+
/**
|
|
22
|
+
* Tenant id the embed is allowed to read. Burned into the token claim;
|
|
23
|
+
* the data-service auto-injects this as a filter on every query the
|
|
24
|
+
* iframe makes. Centrali never interprets the bytes — treat it as
|
|
25
|
+
* opaque (1-255 chars).
|
|
26
|
+
*/
|
|
27
|
+
tenantId: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Defaults to `['events:read']`. Pass `['events:read', 'events:replay']`
|
|
31
|
+
* to allow the iframe's "Replay" action. The issuing service account
|
|
32
|
+
* must already hold the corresponding capability.
|
|
33
|
+
*/
|
|
34
|
+
capabilities?: EmbedCapability[];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Optional cohort id. Useful if you want to revoke every token issued
|
|
38
|
+
* for one of your end-users on logout — mint each with the same
|
|
39
|
+
* `sessionId`, then call `revokeSession({ sessionId })` later. Server
|
|
40
|
+
* mints a random one if omitted (returned in the response).
|
|
41
|
+
*/
|
|
42
|
+
sessionId?: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Token TTL in seconds. Defaults to 600 (10 min). Capped at 3600 (1h)
|
|
46
|
+
* server-side; out-of-range values 400.
|
|
47
|
+
*/
|
|
48
|
+
ttlSeconds?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface IssueEmbedTokenResult {
|
|
52
|
+
/** `ev_…` JWT for the iframe's URL fragment. */
|
|
53
|
+
token: string;
|
|
54
|
+
/** Echo of the input sessionId, or the server-minted one if omitted. */
|
|
55
|
+
sessionId: string;
|
|
56
|
+
/** ISO-8601 timestamp at which the token's `exp` claim fires. */
|
|
57
|
+
expiresAt: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RevokeEmbedSessionInput {
|
|
61
|
+
sessionId: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface RevokeEmbedSessionResult {
|
|
65
|
+
sessionId: string;
|
|
66
|
+
revokedAt: string;
|
|
67
|
+
}
|