@opengeni/core 0.28.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/access/external-actor-authority.d.ts +47 -0
- package/dist/access/index.d.ts +182 -3
- package/dist/access/service-initiator.d.ts +3 -0
- package/dist/application/api-integration-servers.d.ts +20 -0
- package/dist/application/archived-session-imports.d.ts +6 -0
- package/dist/application/composer-submit.d.ts +24 -0
- package/dist/application/connect-authority.d.ts +13 -0
- package/dist/application/connect-operation.d.ts +31 -0
- package/dist/application/external-continuation.d.ts +15 -0
- package/dist/application/external-identity-lifecycle.d.ts +20 -0
- package/dist/application/external-link-work-admission.d.ts +12 -0
- package/dist/application/external-workspace-members.d.ts +34 -0
- package/dist/application/modal-native-worker-host-transport.d.ts +297 -0
- package/dist/application/new-session-drafts.d.ts +39 -2
- package/dist/application/sandbox-recovery.d.ts +58 -0
- package/dist/application/session-commands.d.ts +26 -13
- package/dist/application/session-mcp-credential-rotation.d.ts +29 -0
- package/dist/application/session-tenancy.d.ts +19 -0
- package/dist/application/user-resource-grants.d.ts +20 -0
- package/dist/billing/limits.d.ts +11 -0
- package/dist/canonical-human-identities.d.ts +7 -2
- package/dist/canonical-human-identities.js +17 -4
- package/dist/canonical-human-identities.js.map +1 -1
- package/dist/{chunk-6WKPWE5S.js → chunk-2MKMRGSY.js} +108 -24
- package/dist/chunk-2MKMRGSY.js.map +1 -0
- package/dist/{chunk-NYPMQ7NO.js → chunk-GVO3N37G.js} +205 -37
- package/dist/chunk-GVO3N37G.js.map +1 -0
- package/dist/{chunk-JJU6I5XD.js → chunk-LCQXNR62.js} +36 -10
- package/dist/chunk-LCQXNR62.js.map +1 -0
- package/dist/chunk-MM6N7CTO.js +387 -0
- package/dist/chunk-MM6N7CTO.js.map +1 -0
- package/dist/chunk-QO5GVFFO.js +235 -0
- package/dist/chunk-QO5GVFFO.js.map +1 -0
- package/dist/codex-model-availability.d.ts +14 -0
- package/dist/default-session-model.d.ts +139 -0
- package/dist/dependencies.d.ts +87 -4
- package/dist/developer-setup-credential-ceiling.d.ts +10 -0
- package/dist/domain/agent-config-resolution.d.ts +49 -0
- package/dist/domain/automations.d.ts +58 -0
- package/dist/domain/capabilities.d.ts +22 -4
- package/dist/domain/company-profile-agent-admin.d.ts +25 -0
- package/dist/domain/connection-account-selection-error.d.ts +8 -0
- package/dist/domain/connector-tool-permissions.d.ts +36 -0
- package/dist/domain/direct-model-provider.d.ts +3 -0
- package/dist/domain/editable-artifacts/agent-application.d.ts +10 -1
- package/dist/domain/editable-artifacts/durable-export.d.ts +22 -1
- package/dist/domain/editable-artifacts/ports.d.ts +10 -0
- package/dist/domain/editable-artifacts/service.d.ts +4 -3
- package/dist/domain/environments.d.ts +5 -9
- package/dist/domain/external-creation-attribution.d.ts +6 -0
- package/dist/domain/file-owner.d.ts +8 -0
- package/dist/domain/github-action-policies.d.ts +36 -0
- package/dist/domain/github-repository-bindings.d.ts +117 -0
- package/dist/domain/github-skill-source.d.ts +5 -0
- package/dist/domain/governed-learning-slack-publication.d.ts +45 -0
- package/dist/domain/insights-timing.d.ts +16 -0
- package/dist/domain/insights-usage.d.ts +27 -0
- package/dist/domain/insights.d.ts +28 -1
- package/dist/domain/knowledge-files.d.ts +20 -0
- package/dist/domain/knowledge-messages.d.ts +39 -0
- package/dist/domain/knowledge-messages.test.d.ts +1 -0
- package/dist/domain/knowledge-preparation.d.ts +10 -0
- package/dist/domain/knowledge-preparation.test.d.ts +1 -0
- package/dist/domain/knowledge-search.d.ts +15 -0
- package/dist/domain/knowledge-search.test.d.ts +1 -0
- package/dist/domain/knowledge.d.ts +9 -0
- package/dist/domain/mcp-account-bindings.d.ts +19 -0
- package/dist/domain/mcp-account-routes.d.ts +21 -0
- package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
- package/dist/domain/organization-integration-catalog.d.ts +15 -0
- package/dist/domain/organization-membership-lifecycle.d.ts +1 -0
- package/dist/domain/personal-connection-delegations.d.ts +87 -4
- package/dist/domain/pr-review.d.ts +249 -0
- package/dist/domain/resources.d.ts +24 -3
- package/dist/domain/scheduled-task-access.d.ts +247 -0
- package/dist/domain/scheduled-tasks.d.ts +103 -6
- package/dist/domain/session-connection-accounts.d.ts +16 -0
- package/dist/domain/session-file-access.d.ts +4 -0
- package/dist/domain/session-native-connection-replacement.d.ts +14 -0
- package/dist/domain/session-start-timing.d.ts +7 -0
- package/dist/domain/session-tool-policy.d.ts +93 -4
- package/dist/domain/sessions.d.ts +275 -28
- package/dist/domain/skill-imports.d.ts +1 -0
- package/dist/domain/skill-search.d.ts +30 -0
- package/dist/domain/skills.d.ts +117 -0
- package/dist/domain/slack-bot.d.ts +46 -1
- package/dist/domain/workspace-members.d.ts +8 -1
- package/dist/editable-artifact-live/application.d.ts +12 -3
- package/dist/editable-artifact-live/ports.d.ts +0 -1
- package/dist/editable-artifact-live/server.d.ts +5 -2
- package/dist/editable-artifact-live/ticket.d.ts +2 -2
- package/dist/editable-artifact-live/types.d.ts +14 -2
- package/dist/editable-artifact-live.js +2 -2
- package/dist/editable-artifacts.js +10 -4
- package/dist/index.d.ts +49 -3
- package/dist/index.js +18812 -6833
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.d.ts +131 -0
- package/dist/managed-auth-session-sets.js +51 -0
- package/dist/managed-auth-session-sets.js.map +1 -0
- package/dist/managed-session.d.ts +98 -11
- package/dist/model-catalog.d.ts +117 -0
- package/dist/product-usage-metrics.d.ts +30 -0
- package/dist/rigs/index.d.ts +22 -5
- package/dist/rigs/provider-images.d.ts +1 -1
- package/dist/sandbox/fleet.d.ts +59 -10
- package/dist/sandbox/routing.d.ts +22 -2
- package/dist/sandbox/runtime-settings.d.ts +56 -0
- package/dist/session-authorization.d.ts +38 -1
- package/dist/site-session-origin.d.ts +9 -0
- package/dist/transcription.d.ts +12 -1
- package/dist/turn-surface.d.ts +18 -0
- package/dist/user-presence.d.ts +32 -0
- package/package.json +18 -11
- package/src/access/external-actor-authority.ts +94 -0
- package/src/access/index.ts +1386 -44
- package/src/access/service-initiator.ts +50 -0
- package/src/application/api-integration-servers.ts +215 -0
- package/src/application/archived-session-imports.ts +161 -0
- package/src/application/composer-submit.ts +77 -0
- package/src/application/connect-authority.ts +77 -0
- package/src/application/connect-operation.ts +80 -0
- package/src/application/external-continuation.ts +129 -0
- package/src/application/external-identity-lifecycle.ts +48 -0
- package/src/application/external-link-work-admission.ts +90 -0
- package/src/application/external-workspace-members.ts +232 -0
- package/src/application/modal-native-worker-host-transport.ts +263 -0
- package/src/application/new-session-drafts.ts +222 -29
- package/src/application/sandbox-recovery.ts +78 -0
- package/src/application/session-commands.ts +430 -73
- package/src/application/session-mcp-credential-rotation.ts +217 -0
- package/src/application/session-tenancy.ts +445 -0
- package/src/application/user-resource-grants.ts +154 -0
- package/src/billing/limits.ts +103 -24
- package/src/canonical-human-identities.ts +22 -3
- package/src/codex-model-availability.ts +136 -0
- package/src/default-session-model.ts +656 -0
- package/src/dependencies.ts +97 -5
- package/src/developer-setup-credential-ceiling.ts +60 -0
- package/src/domain/agent-config-resolution.ts +148 -0
- package/src/domain/automations.ts +270 -0
- package/src/domain/capabilities.ts +244 -151
- package/src/domain/company-profile-agent-admin.ts +56 -0
- package/src/domain/connection-account-selection-error.ts +19 -0
- package/src/domain/connector-tool-permissions.ts +371 -0
- package/src/domain/direct-model-provider.ts +62 -0
- package/src/domain/editable-artifacts/agent-application.ts +61 -15
- package/src/domain/editable-artifacts/durable-export.ts +100 -5
- package/src/domain/editable-artifacts/in-memory.ts +6 -0
- package/src/domain/editable-artifacts/ports.ts +11 -0
- package/src/domain/editable-artifacts/service.ts +32 -1
- package/src/domain/editable-artifacts/snapshot-compaction.ts +9 -5
- package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +10 -8
- package/src/domain/editable-artifacts/snapshot-verifier.ts +10 -3
- package/src/domain/environments.ts +25 -45
- package/src/domain/external-creation-attribution.ts +22 -0
- package/src/domain/file-owner.ts +67 -0
- package/src/domain/github-action-policies.ts +169 -0
- package/src/domain/github-repository-bindings.ts +295 -0
- package/src/domain/github-skill-source.ts +233 -0
- package/src/domain/governed-learning-slack-publication.ts +157 -0
- package/src/domain/insights-timing.ts +95 -0
- package/src/domain/insights-usage.ts +67 -0
- package/src/domain/insights.ts +270 -169
- package/src/domain/knowledge-files.ts +46 -0
- package/src/domain/knowledge-messages.test.ts +91 -0
- package/src/domain/knowledge-messages.ts +106 -0
- package/src/domain/knowledge-preparation.test.ts +276 -0
- package/src/domain/knowledge-preparation.ts +147 -0
- package/src/domain/knowledge-search.test.ts +561 -0
- package/src/domain/knowledge-search.ts +256 -0
- package/src/domain/knowledge.ts +133 -0
- package/src/domain/mcp-account-bindings.ts +171 -0
- package/src/domain/mcp-account-routes.ts +121 -0
- package/src/domain/native-mcp-connection-admission.ts +14 -0
- package/src/domain/organization-integration-catalog.ts +88 -0
- package/src/domain/organization-membership-lifecycle.ts +10 -0
- package/src/domain/personal-connection-delegations.ts +758 -115
- package/src/domain/pr-review.ts +687 -0
- package/src/domain/resources.ts +182 -25
- package/src/domain/scheduled-task-access.ts +1052 -0
- package/src/domain/scheduled-tasks.ts +1952 -215
- package/src/domain/session-connection-accounts.ts +67 -0
- package/src/domain/session-file-access.ts +47 -0
- package/src/domain/session-native-connection-replacement.ts +64 -0
- package/src/domain/session-start-timing.ts +55 -0
- package/src/domain/session-tool-policy.ts +443 -19
- package/src/domain/sessions.ts +3417 -619
- package/src/domain/skill-imports.ts +137 -17
- package/src/domain/skill-search.ts +221 -0
- package/src/domain/skills.ts +104 -0
- package/src/domain/slack-bot.ts +128 -3
- package/src/domain/workspace-members.ts +34 -2
- package/src/editable-artifact-live/application.ts +29 -4
- package/src/editable-artifact-live/ports.ts +0 -1
- package/src/editable-artifact-live/server.ts +167 -13
- package/src/editable-artifact-live/ticket.ts +87 -6
- package/src/editable-artifact-live/types.ts +16 -2
- package/src/editable-artifact-live/wire.ts +0 -10
- package/src/index.ts +69 -4
- package/src/managed-auth-session-sets.ts +371 -0
- package/src/managed-session.ts +520 -2
- package/src/model-catalog.ts +873 -0
- package/src/product-usage-metrics.ts +101 -0
- package/src/rigs/index.ts +179 -63
- package/src/rigs/provider-images.ts +2 -3
- package/src/sandbox/fleet.ts +471 -59
- package/src/sandbox/routing.ts +160 -33
- package/src/sandbox/runtime-settings.ts +281 -0
- package/src/session-authorization.ts +262 -78
- package/src/site-session-origin.ts +22 -0
- package/src/transcription.ts +13 -1
- package/src/turn-surface.ts +45 -0
- package/src/user-presence.ts +134 -0
- package/dist/chunk-6WKPWE5S.js.map +0 -1
- package/dist/chunk-IBOEYG6N.js +0 -34
- package/dist/chunk-IBOEYG6N.js.map +0 -1
- package/dist/chunk-JJU6I5XD.js.map +0 -1
- package/dist/chunk-NYPMQ7NO.js.map +0 -1
- package/dist/domain/durable-learning-slack-publication.d.ts +0 -72
- package/dist/domain/packs.d.ts +0 -55
- package/src/domain/durable-learning-slack-publication.ts +0 -202
- package/src/domain/packs.ts +0 -556
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GovernedLearningActivationReceipt,
|
|
3
|
+
GovernedLearningActivationUndoReceipt,
|
|
4
|
+
} from "@opengeni/contracts";
|
|
5
|
+
import {
|
|
6
|
+
enqueueMemorySlackPublication,
|
|
7
|
+
getCurrentMemorySlackPublicationConfiguration,
|
|
8
|
+
resolveGovernedLearningEvidenceOrigin,
|
|
9
|
+
type Database,
|
|
10
|
+
type EnqueueMemorySlackPublicationResult,
|
|
11
|
+
type GovernedLearningEvidenceOrigin,
|
|
12
|
+
} from "@opengeni/db";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Narrow post-persistence notification port for governed-learning activation
|
|
16
|
+
* and undo receipts (migration 0269). The evaluator/controller own policy,
|
|
17
|
+
* authority, and the immutable receipts; this adapter only projects bounded,
|
|
18
|
+
* content-free facts into the existing Slack publication outbox. It never
|
|
19
|
+
* reads proposal content, evidence bytes, or destination bodies.
|
|
20
|
+
*/
|
|
21
|
+
export type GovernedLearningSlackEvent =
|
|
22
|
+
| {
|
|
23
|
+
kind: "activated";
|
|
24
|
+
receipt: GovernedLearningActivationReceipt;
|
|
25
|
+
sessionId: string | null;
|
|
26
|
+
attemptId: string | null;
|
|
27
|
+
}
|
|
28
|
+
| { kind: "undone"; receipt: GovernedLearningActivationUndoReceipt };
|
|
29
|
+
|
|
30
|
+
export type GovernedLearningSlackPublicationResult =
|
|
31
|
+
| {
|
|
32
|
+
kind: "evidence_origin_unresolved" | "slack_derived_evidence" | "policy_quiet";
|
|
33
|
+
enqueue: null;
|
|
34
|
+
}
|
|
35
|
+
| { kind: "enqueued"; enqueue: EnqueueMemorySlackPublicationResult };
|
|
36
|
+
|
|
37
|
+
export type GovernedLearningSlackProjection = {
|
|
38
|
+
summary: string;
|
|
39
|
+
outcome: "activated" | "undone";
|
|
40
|
+
destination: "instruction_policy" | "preference";
|
|
41
|
+
sourceKind: "scoped-knowledge-evidence" | "task-note" | null;
|
|
42
|
+
destinationRevisionId: string;
|
|
43
|
+
destinationVersion: number;
|
|
44
|
+
activationReceiptId: string;
|
|
45
|
+
undoReceiptId: string | null;
|
|
46
|
+
occurredAt: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const DESTINATION_LABEL: Record<"instruction_policy" | "preference", string> = {
|
|
50
|
+
instruction_policy: "workspace instruction policy",
|
|
51
|
+
preference: "workspace preference",
|
|
52
|
+
};
|
|
53
|
+
const SOURCE_LABEL: Record<"scoped-knowledge-evidence" | "task-note", string> = {
|
|
54
|
+
"scoped-knowledge-evidence": "workspace knowledge evidence",
|
|
55
|
+
"task-note": "a task note",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export function governedLearningSlackImportance(
|
|
59
|
+
event: GovernedLearningSlackEvent,
|
|
60
|
+
): "major" | "normal" | "minor" {
|
|
61
|
+
if (event.kind === "undone") return "major";
|
|
62
|
+
return event.receipt.destination === "instruction_policy" ? "major" : "normal";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function governedLearningSlackProjection(
|
|
66
|
+
event: GovernedLearningSlackEvent,
|
|
67
|
+
): GovernedLearningSlackProjection {
|
|
68
|
+
if (event.kind === "activated") {
|
|
69
|
+
const receipt = event.receipt;
|
|
70
|
+
return {
|
|
71
|
+
summary: `Automatically activated a ${DESTINATION_LABEL[receipt.destination]} learned from ${SOURCE_LABEL[receipt.sourceKind]} (revision ${receipt.destinationNewVersion}). Undo is available through the workspace learning API.`,
|
|
72
|
+
outcome: "activated",
|
|
73
|
+
destination: receipt.destination,
|
|
74
|
+
sourceKind: receipt.sourceKind,
|
|
75
|
+
destinationRevisionId: receipt.destinationRevisionId,
|
|
76
|
+
destinationVersion: receipt.destinationNewVersion,
|
|
77
|
+
activationReceiptId: receipt.id,
|
|
78
|
+
undoReceiptId: null,
|
|
79
|
+
occurredAt: receipt.effectiveAt,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const receipt = event.receipt;
|
|
83
|
+
return {
|
|
84
|
+
summary: `Undid an automatic ${DESTINATION_LABEL[receipt.destination]} activation (revision ${receipt.destinationOldVersion} → ${receipt.destinationNewVersion}).`,
|
|
85
|
+
outcome: "undone",
|
|
86
|
+
destination: receipt.destination,
|
|
87
|
+
sourceKind: null,
|
|
88
|
+
destinationRevisionId: receipt.destinationActivatedRevisionId,
|
|
89
|
+
destinationVersion: receipt.destinationNewVersion,
|
|
90
|
+
activationReceiptId: receipt.activationReceiptId,
|
|
91
|
+
undoReceiptId: receipt.id,
|
|
92
|
+
occurredAt: receipt.effectiveAt,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Evidence that itself came from a Slack knowledge connector must never republish to Slack. */
|
|
97
|
+
export function governedLearningEvidenceIsSlackDerived(
|
|
98
|
+
origin: GovernedLearningEvidenceOrigin,
|
|
99
|
+
): boolean {
|
|
100
|
+
return origin.kind === "document" && /slack/iu.test(origin.providerKey ?? "");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function publishGovernedLearningEventToSlack(
|
|
104
|
+
db: Database,
|
|
105
|
+
event: GovernedLearningSlackEvent,
|
|
106
|
+
options: {
|
|
107
|
+
resolveEvidenceOrigin?: typeof resolveGovernedLearningEvidenceOrigin;
|
|
108
|
+
configuration?: typeof getCurrentMemorySlackPublicationConfiguration;
|
|
109
|
+
enqueue?: typeof enqueueMemorySlackPublication;
|
|
110
|
+
} = {},
|
|
111
|
+
): Promise<GovernedLearningSlackPublicationResult> {
|
|
112
|
+
const workspaceId = event.receipt.workspaceId;
|
|
113
|
+
if (event.kind === "activated") {
|
|
114
|
+
// Loop prevention: evidence that came from a Slack knowledge connector
|
|
115
|
+
// must not be republished to Slack. Task-note evidence is always local.
|
|
116
|
+
const origin = await (options.resolveEvidenceOrigin ?? resolveGovernedLearningEvidenceOrigin)(
|
|
117
|
+
db,
|
|
118
|
+
{ workspaceId, evidenceId: event.receipt.evidenceId },
|
|
119
|
+
);
|
|
120
|
+
if (!origin) return { kind: "evidence_origin_unresolved", enqueue: null };
|
|
121
|
+
if (governedLearningEvidenceIsSlackDerived(origin)) {
|
|
122
|
+
return { kind: "slack_derived_evidence", enqueue: null };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const importance = governedLearningSlackImportance(event);
|
|
126
|
+
const configuration = await (
|
|
127
|
+
options.configuration ?? getCurrentMemorySlackPublicationConfiguration
|
|
128
|
+
)(db, workspaceId);
|
|
129
|
+
const deliveryMode = configuration?.autoImportances.includes(importance)
|
|
130
|
+
? "auto"
|
|
131
|
+
: configuration?.reviewImportances.includes(importance)
|
|
132
|
+
? "review"
|
|
133
|
+
: null;
|
|
134
|
+
if (!configuration?.enabled || !deliveryMode) return { kind: "policy_quiet", enqueue: null };
|
|
135
|
+
|
|
136
|
+
const projection = governedLearningSlackProjection(event);
|
|
137
|
+
const receipt = event.receipt;
|
|
138
|
+
const enqueue = await (options.enqueue ?? enqueueMemorySlackPublication)(db, {
|
|
139
|
+
accountId: receipt.accountId,
|
|
140
|
+
workspaceId,
|
|
141
|
+
sourceType: "durable_learning",
|
|
142
|
+
sourceId: receipt.id,
|
|
143
|
+
sourceVersion: String(projection.destinationVersion),
|
|
144
|
+
sourceIdempotencyKey: `governed-learning:${event.kind}:${receipt.id}`,
|
|
145
|
+
projection: { ...projection },
|
|
146
|
+
importance,
|
|
147
|
+
deliveryMode,
|
|
148
|
+
actor: {
|
|
149
|
+
kind: "service",
|
|
150
|
+
subjectId: receipt.serviceActorSubjectId,
|
|
151
|
+
initiatingHumanSubjectId: receipt.initiatingHumanSubjectId,
|
|
152
|
+
sessionId: event.kind === "activated" ? event.sessionId : null,
|
|
153
|
+
attemptId: event.kind === "activated" ? event.attemptId : null,
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
return { kind: "enqueued", enqueue };
|
|
157
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { withDatabaseTimingObserver, type DatabaseTimingObservation } from "@opengeni/db";
|
|
2
|
+
import type { Observability } from "@opengeni/observability";
|
|
3
|
+
|
|
4
|
+
const phases = new Set([
|
|
5
|
+
"auth",
|
|
6
|
+
"require_workspace",
|
|
7
|
+
"model_bundle",
|
|
8
|
+
"usage_bundle",
|
|
9
|
+
"live_warm",
|
|
10
|
+
"scheduled_tasks",
|
|
11
|
+
"session_depth",
|
|
12
|
+
"floor_sessions",
|
|
13
|
+
"online_machines",
|
|
14
|
+
"attached_sessions",
|
|
15
|
+
"scheduled_fires",
|
|
16
|
+
] as const);
|
|
17
|
+
export type InsightsPhase = typeof phases extends Set<infer T> ? T : never;
|
|
18
|
+
export type InsightsPhaseObservation = {
|
|
19
|
+
phase: InsightsPhase;
|
|
20
|
+
stage: "helper" | DatabaseTimingObservation["stage"];
|
|
21
|
+
outcome: "completed" | "failed";
|
|
22
|
+
durationMs: number;
|
|
23
|
+
};
|
|
24
|
+
export type InsightsPhaseObserver = (observation: InsightsPhaseObservation) => void;
|
|
25
|
+
const stages = new Set([
|
|
26
|
+
"helper",
|
|
27
|
+
"transaction_admission",
|
|
28
|
+
"savepoint_admission",
|
|
29
|
+
"rls_setup",
|
|
30
|
+
"scoped_callback",
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
function observeSafely(
|
|
34
|
+
observer: InsightsPhaseObserver,
|
|
35
|
+
observation: InsightsPhaseObservation,
|
|
36
|
+
): void {
|
|
37
|
+
try {
|
|
38
|
+
void Promise.resolve(observer(observation)).catch(() => undefined);
|
|
39
|
+
} catch {
|
|
40
|
+
// Telemetry is never authoritative for results or authorization.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Helper durations overlap under Promise.all; they must not be summed as request latency. */
|
|
45
|
+
export async function measureInsightsPhase<T>(
|
|
46
|
+
observer: InsightsPhaseObserver | undefined,
|
|
47
|
+
phase: InsightsPhase,
|
|
48
|
+
work: () => Promise<T>,
|
|
49
|
+
): Promise<T> {
|
|
50
|
+
if (!observer) return work();
|
|
51
|
+
const started = performance.now();
|
|
52
|
+
let outcome: InsightsPhaseObservation["outcome"] = "failed";
|
|
53
|
+
try {
|
|
54
|
+
const result = await withDatabaseTimingObserver(
|
|
55
|
+
(observation) => observeSafely(observer, { ...observation, phase }),
|
|
56
|
+
work,
|
|
57
|
+
);
|
|
58
|
+
outcome = "completed";
|
|
59
|
+
return result;
|
|
60
|
+
} finally {
|
|
61
|
+
observeSafely(observer, {
|
|
62
|
+
phase,
|
|
63
|
+
stage: "helper",
|
|
64
|
+
outcome,
|
|
65
|
+
durationMs: performance.now() - started,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Closed runtime label projection: caller input, SQL and identities never become labels. */
|
|
71
|
+
export function workspaceInsightsPhaseMetricObserver(
|
|
72
|
+
observability: Pick<Observability, "observeHistogram"> | null | undefined,
|
|
73
|
+
): InsightsPhaseObserver | undefined {
|
|
74
|
+
if (!observability) return undefined;
|
|
75
|
+
return (observation) => {
|
|
76
|
+
try {
|
|
77
|
+
const result = observability.observeHistogram({
|
|
78
|
+
name: "opengeni_workspace_insights_phase_duration_seconds",
|
|
79
|
+
help: "Insights helper and scoped DB durations; admission includes BEGIN or SAVEPOINT, scoped callback is not pure SQL time. Concurrent phases overlap.",
|
|
80
|
+
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2, 3, 5, 10, 30, 60],
|
|
81
|
+
labels: {
|
|
82
|
+
phase: phases.has(observation.phase) ? observation.phase : "unknown",
|
|
83
|
+
stage: stages.has(observation.stage) ? observation.stage : "unknown",
|
|
84
|
+
outcome: observation.outcome === "completed" ? "completed" : "failed",
|
|
85
|
+
},
|
|
86
|
+
value: Number.isFinite(observation.durationMs)
|
|
87
|
+
? Math.max(0, observation.durationMs) / 1_000
|
|
88
|
+
: 0,
|
|
89
|
+
});
|
|
90
|
+
void Promise.resolve(result).catch(() => undefined);
|
|
91
|
+
} catch {
|
|
92
|
+
// Includes exporter and metric registration failures.
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InsightsCallsQuery,
|
|
3
|
+
InsightsCallsResponse,
|
|
4
|
+
InsightsUsageQuery,
|
|
5
|
+
InsightsUsageRange,
|
|
6
|
+
InsightsUsageResponse,
|
|
7
|
+
} from "@opengeni/contracts/insights-usage";
|
|
8
|
+
import { readInsightsCalls, readInsightsUsage, type Database } from "@opengeni/db";
|
|
9
|
+
|
|
10
|
+
export type InsightsQueryScope = {
|
|
11
|
+
accountId: string;
|
|
12
|
+
/** null means organization scope; it does not grant workspace/session access. */
|
|
13
|
+
workspaceId: string | null;
|
|
14
|
+
/** Server-verified metadata authority; billing permission alone supplies none. */
|
|
15
|
+
detailsWorkspaceIds?: readonly string[];
|
|
16
|
+
/** Existing organization service-key authority applies only to shared workspaces. */
|
|
17
|
+
detailsSharedWorkspaces?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export async function getInsightsUsage(
|
|
21
|
+
db: Database,
|
|
22
|
+
input: InsightsQueryScope & { query: InsightsUsageQuery; now?: Date },
|
|
23
|
+
): Promise<InsightsUsageResponse> {
|
|
24
|
+
return await readInsightsUsage(db, { ...input, now: input.now ?? new Date() });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function listInsightsCalls(
|
|
28
|
+
db: Database,
|
|
29
|
+
input: InsightsQueryScope & { query: InsightsCallsQuery; now?: Date },
|
|
30
|
+
): Promise<InsightsCallsResponse> {
|
|
31
|
+
return await readInsightsCalls(db, { ...input, now: input.now ?? new Date() });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** UTC windows retain the actual request timestamp, including empty midnight windows. */
|
|
35
|
+
export function insightsUsageWindow(range: InsightsUsageRange, now = new Date()) {
|
|
36
|
+
if (!Number.isFinite(now.getTime())) throw new Error("Invalid Insights request time");
|
|
37
|
+
const until = new Date(now);
|
|
38
|
+
const since = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
39
|
+
switch (range) {
|
|
40
|
+
case "today":
|
|
41
|
+
break;
|
|
42
|
+
case "week":
|
|
43
|
+
since.setUTCDate(since.getUTCDate() - 6);
|
|
44
|
+
break;
|
|
45
|
+
case "month":
|
|
46
|
+
since.setUTCDate(1);
|
|
47
|
+
break;
|
|
48
|
+
case "30d":
|
|
49
|
+
since.setUTCDate(since.getUTCDate() - 29);
|
|
50
|
+
break;
|
|
51
|
+
case "90d":
|
|
52
|
+
since.setUTCDate(since.getUTCDate() - 89);
|
|
53
|
+
break;
|
|
54
|
+
case "ytd":
|
|
55
|
+
since.setUTCMonth(0, 1);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
const priorUntil = new Date(since);
|
|
59
|
+
const priorSince = new Date(priorUntil.getTime() - (until.getTime() - since.getTime()));
|
|
60
|
+
return {
|
|
61
|
+
since,
|
|
62
|
+
until,
|
|
63
|
+
priorSince,
|
|
64
|
+
priorUntil,
|
|
65
|
+
bucket: range === "today" ? ("hour" as const) : ("day" as const),
|
|
66
|
+
};
|
|
67
|
+
}
|