@opengeni/db 3.2.0-canary.0 → 3.4.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-SIBYBA2D.js → chunk-6DPJA36C.js} +30 -11
  3. package/dist/chunk-6DPJA36C.js.map +1 -0
  4. package/dist/{chunk-KRLPEMLH.js → chunk-C2AFP7SB.js} +184 -6
  5. package/dist/chunk-C2AFP7SB.js.map +1 -0
  6. package/dist/{chunk-AZHW7R5V.js → chunk-H7MXYG7R.js} +12 -8
  7. package/dist/chunk-H7MXYG7R.js.map +1 -0
  8. package/dist/{chunk-2PRS4J5Q.js → chunk-HY3F5Q4E.js} +3 -3
  9. package/dist/{chunk-NAB6FKFN.js → chunk-O6FTELKH.js} +3 -3
  10. package/dist/{chunk-UZNXG44K.js → chunk-PYMY3AJW.js} +324 -8
  11. package/dist/chunk-PYMY3AJW.js.map +1 -0
  12. package/dist/{chunk-6HMM2R5T.js → chunk-TRBOWUG3.js} +98 -4
  13. package/dist/chunk-TRBOWUG3.js.map +1 -0
  14. package/dist/{chunk-E6CLMKEE.js → chunk-V3TRUXFJ.js} +2 -2
  15. package/dist/{chunk-2EH4WRHL.js → chunk-ZWRIPCTR.js} +2 -2
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/governed-learning-activation.d.ts +16 -0
  19. package/dist/index.d.ts +108 -7
  20. package/dist/index.js +3605 -1417
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights-model-bundle.d.ts +30 -0
  23. package/dist/insights-usage-bundle.d.ts +32 -0
  24. package/dist/insights.d.ts +10 -2
  25. package/dist/lossless-json.d.ts +1 -1
  26. package/dist/managed-user-setup.d.ts +82 -0
  27. package/dist/memory-domain.d.ts +2 -2
  28. package/dist/migrate.d.ts +3 -1
  29. package/dist/migrate.js +1 -1
  30. package/dist/new-session-drafts.d.ts +4 -4
  31. package/dist/organization-membership-lifecycle.d.ts +60 -1
  32. package/dist/pr-review.d.ts +44 -3
  33. package/dist/provision-roles.js +1 -1
  34. package/dist/runtime-posture.d.ts +12 -7
  35. package/dist/schema.d.ts +839 -101
  36. package/dist/schema.js +9 -1
  37. package/dist/session-background-commands.js +3 -3
  38. package/dist/session-tenancy.d.ts +12 -1
  39. package/dist/session-tenancy.js +3 -3
  40. package/dist/video-generation.js +3 -3
  41. package/drizzle/0348_named_signup_and_user_setup.sql +838 -0
  42. package/drizzle/0349_greenfield_session_tenancy_activation.sql +792 -0
  43. package/drizzle/0350_organization_shared_workspace_administration.sql +889 -0
  44. package/drizzle/0351_organization_user_setup_delivery.sql +978 -0
  45. package/drizzle/0352_session_variable_set_attachments.sql +1661 -0
  46. package/drizzle/0353_automatic_session_title_policy_fence.sql +476 -0
  47. package/drizzle/0354_automatic_session_title_quarantine_index.sql +9 -0
  48. package/drizzle/0355_automatic_session_title_quarantine.sql +92 -0
  49. package/drizzle/0356_set_based_insights_session_visibility.sql +237 -0
  50. package/drizzle/0357_rig_platform_base_only.sql +44 -0
  51. package/drizzle/0358_pr_review_managed_github_app.sql +108 -0
  52. package/drizzle/0359_insights_force_rls_read_capability.sql +936 -0
  53. package/drizzle/0360_organization_identity_confirmation_prompt.sql +103 -0
  54. package/drizzle/0361_remember_knowledge_memory_materialization.sql +249 -0
  55. package/package.json +6 -6
  56. package/src/database.ts +12 -8
  57. package/src/governed-learning-activation.ts +74 -2
  58. package/src/index.ts +879 -92
  59. package/src/insights-model-bundle.ts +681 -0
  60. package/src/insights-usage-bundle.ts +240 -0
  61. package/src/insights.ts +265 -152
  62. package/src/lossless-json.ts +2 -1
  63. package/src/managed-user-setup.ts +316 -0
  64. package/src/memory-domain.ts +3 -3
  65. package/src/migrate.ts +38 -14
  66. package/src/new-session-drafts.ts +22 -15
  67. package/src/organization-membership-lifecycle.ts +253 -1
  68. package/src/pr-review.ts +449 -6
  69. package/src/provision-roles.ts +92 -0
  70. package/src/runtime-posture.ts +247 -4
  71. package/src/schema.ts +210 -4
  72. package/src/session-tenancy.ts +120 -2
  73. package/dist/chunk-6HMM2R5T.js.map +0 -1
  74. package/dist/chunk-AZHW7R5V.js.map +0 -1
  75. package/dist/chunk-KRLPEMLH.js.map +0 -1
  76. package/dist/chunk-SIBYBA2D.js.map +0 -1
  77. package/dist/chunk-UZNXG44K.js.map +0 -1
  78. /package/dist/{chunk-2PRS4J5Q.js.map → chunk-HY3F5Q4E.js.map} +0 -0
  79. /package/dist/{chunk-NAB6FKFN.js.map → chunk-O6FTELKH.js.map} +0 -0
  80. /package/dist/{chunk-E6CLMKEE.js.map → chunk-V3TRUXFJ.js.map} +0 -0
  81. /package/dist/{chunk-2EH4WRHL.js.map → chunk-ZWRIPCTR.js.map} +0 -0
@@ -0,0 +1,240 @@
1
+ import { sql } from "drizzle-orm";
2
+
3
+ import type { Database } from "./database";
4
+ import { rlsContextForWorkspace, withRlsContext } from "./database";
5
+ import { INSIGHTS_WARM_GROUP_UUID_RE, type WarmGroupAggregate } from "./insights";
6
+
7
+ export type WorkspaceInsightsUsageBundleInput = {
8
+ workspaceId: string;
9
+ since: Date;
10
+ until: Date;
11
+ priorSince: Date;
12
+ priorUntil: Date;
13
+ monthSince: Date;
14
+ granularity: "day" | "hour";
15
+ warmGroupLimit?: number;
16
+ };
17
+
18
+ export type WorkspaceInsightsUsageBucket = {
19
+ costMicros: number | null;
20
+ warmSeconds: number;
21
+ };
22
+
23
+ export type WorkspaceInsightsUsageBundle = {
24
+ workspaceCreditMicros: number;
25
+ priorWorkspaceCreditMicros: number;
26
+ warmSeconds: number;
27
+ priorWarmSeconds: number;
28
+ buckets: Map<string, WorkspaceInsightsUsageBucket>;
29
+ warmGroups: WarmGroupAggregate[];
30
+ billableTokensUsed: number;
31
+ agentRunsUsed: number;
32
+ };
33
+
34
+ type RawUsageBundleRow = {
35
+ workspace_credit_micros: unknown;
36
+ prior_workspace_credit_micros: unknown;
37
+ warm_seconds: unknown;
38
+ prior_warm_seconds: unknown;
39
+ billable_tokens_used: unknown;
40
+ agent_runs_used: unknown;
41
+ buckets: unknown;
42
+ warm_groups: unknown;
43
+ };
44
+
45
+ type JsonRecord = Record<string, unknown>;
46
+
47
+ function numberValue(value: unknown, label: string): number {
48
+ if (
49
+ (typeof value !== "number" && typeof value !== "string") ||
50
+ (typeof value === "string" && value.trim().length === 0)
51
+ ) {
52
+ throw new Error(`Insights usage bundle ${label} is not numeric`);
53
+ }
54
+ const parsed = Number(value);
55
+ if (!Number.isFinite(parsed)) {
56
+ throw new Error(`Insights usage bundle ${label} is not numeric`);
57
+ }
58
+ return parsed;
59
+ }
60
+
61
+ function nullableNumberValue(value: unknown, label: string): number | null {
62
+ return value === null || value === undefined ? null : numberValue(value, label);
63
+ }
64
+
65
+ function records(value: unknown, label: string): JsonRecord[] {
66
+ if (!Array.isArray(value)) {
67
+ throw new Error(`Insights usage bundle ${label} is not an array`);
68
+ }
69
+ return value.map((item, index) => {
70
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
71
+ throw new Error(`Insights usage bundle ${label}[${index}] is not an object`);
72
+ }
73
+ return item as JsonRecord;
74
+ });
75
+ }
76
+
77
+ function stringValue(row: JsonRecord, key: string): string {
78
+ const value = row[key];
79
+ if (typeof value !== "string") {
80
+ throw new Error(`Insights usage bundle ${key} is not a string`);
81
+ }
82
+ return value;
83
+ }
84
+
85
+ /**
86
+ * One read for the three existing usage windows. The event-type arrays are
87
+ * deliberately closed so the authority function can keep selective predicates
88
+ * inside its scan while all rollup math remains outside the billing path.
89
+ */
90
+ export async function readWorkspaceInsightsUsageBundle(
91
+ db: Database,
92
+ input: WorkspaceInsightsUsageBundleInput,
93
+ ): Promise<WorkspaceInsightsUsageBundle> {
94
+ const context = await rlsContextForWorkspace(db, input.workspaceId);
95
+ const bucket =
96
+ input.granularity === "hour"
97
+ ? sql`to_char(date_trunc('hour', usage_row.occurred_at at time zone 'UTC'), 'YYYY-MM-DD"T"HH24:00')`
98
+ : sql`to_char(date_trunc('day', usage_row.occurred_at at time zone 'UTC'), 'YYYY-MM-DD')`;
99
+ const warmGroupLimit = Math.max(1, Math.min(input.warmGroupLimit ?? 24, 100));
100
+
101
+ return await withRlsContext(db, context, async (scopedDb) => {
102
+ const [row] = await scopedDb.execute<RawUsageBundleRow>(sql`
103
+ with current_visible as materialized (
104
+ select usage_row.event_type, usage_row.quantity, usage_row.occurred_at,
105
+ usage_row.source_resource_id
106
+ from opengeni_private.visible_workspace_insights_usage_events(
107
+ ${input.workspaceId},
108
+ ${input.since.toISOString()}::timestamp with time zone,
109
+ ${input.until.toISOString()}::timestamp with time zone,
110
+ array['model.cost', 'sandbox.warm_seconds']::text[]
111
+ ) usage_row
112
+ ), prior_visible as materialized (
113
+ select usage_row.event_type, usage_row.quantity
114
+ from opengeni_private.visible_workspace_insights_usage_events(
115
+ ${input.workspaceId},
116
+ ${input.priorSince.toISOString()}::timestamp with time zone,
117
+ ${input.priorUntil.toISOString()}::timestamp with time zone,
118
+ array['model.cost', 'sandbox.warm_seconds']::text[]
119
+ ) usage_row
120
+ ), month_visible as materialized (
121
+ select usage_row.event_type, usage_row.quantity, usage_row.occurred_at
122
+ from opengeni_private.visible_workspace_insights_usage_events(
123
+ ${input.workspaceId},
124
+ ${input.monthSince.toISOString()}::timestamp with time zone,
125
+ 'infinity'::timestamp with time zone,
126
+ array['model.tokens', 'agent_run.created']::text[]
127
+ ) usage_row
128
+ ), current_totals as (
129
+ select
130
+ coalesce(sum(usage_row.quantity) filter (
131
+ where usage_row.event_type = 'model.cost'
132
+ ), 0) as workspace_credit_micros,
133
+ coalesce(sum(usage_row.quantity) filter (
134
+ where usage_row.event_type = 'sandbox.warm_seconds'
135
+ ), 0) as warm_seconds
136
+ from current_visible usage_row
137
+ ), prior_totals as (
138
+ select
139
+ coalesce(sum(usage_row.quantity) filter (
140
+ where usage_row.event_type = 'model.cost'
141
+ ), 0) as prior_workspace_credit_micros,
142
+ coalesce(sum(usage_row.quantity) filter (
143
+ where usage_row.event_type = 'sandbox.warm_seconds'
144
+ ), 0) as prior_warm_seconds
145
+ from prior_visible usage_row
146
+ ), month_totals as (
147
+ select
148
+ coalesce(sum(usage_row.quantity) filter (
149
+ where usage_row.event_type = 'model.tokens'
150
+ and usage_row.occurred_at > ${input.monthSince.toISOString()}::timestamp with time zone
151
+ ), 0) as billable_tokens_used,
152
+ coalesce(sum(usage_row.quantity) filter (
153
+ where usage_row.event_type = 'agent_run.created'
154
+ and usage_row.occurred_at > ${input.monthSince.toISOString()}::timestamp with time zone
155
+ ), 0) as agent_runs_used
156
+ from month_visible usage_row
157
+ ), bucket_rows as (
158
+ select
159
+ ${bucket} as bucket,
160
+ sum(usage_row.quantity) filter (
161
+ where usage_row.event_type = 'model.cost'
162
+ ) as cost_micros,
163
+ coalesce(sum(usage_row.quantity) filter (
164
+ where usage_row.event_type = 'sandbox.warm_seconds'
165
+ ), 0) as warm_seconds
166
+ from current_visible usage_row
167
+ group by ${bucket}
168
+ ), warm_group_rows as (
169
+ select
170
+ split_part(usage_row.source_resource_id, ':', 1) as group_id,
171
+ coalesce(sum(usage_row.quantity), 0) as warm_seconds
172
+ from current_visible usage_row
173
+ where usage_row.event_type = 'sandbox.warm_seconds'
174
+ and usage_row.source_resource_id is not null
175
+ group by split_part(usage_row.source_resource_id, ':', 1)
176
+ order by coalesce(sum(usage_row.quantity), 0) desc
177
+ limit ${Math.max(warmGroupLimit * 4, warmGroupLimit)}
178
+ )
179
+ select
180
+ current_totals.workspace_credit_micros,
181
+ prior_totals.prior_workspace_credit_micros,
182
+ current_totals.warm_seconds,
183
+ prior_totals.prior_warm_seconds,
184
+ month_totals.billable_tokens_used,
185
+ month_totals.agent_runs_used,
186
+ coalesce((
187
+ select jsonb_agg(jsonb_build_object(
188
+ 'bucket', bucket,
189
+ 'costMicros', cost_micros,
190
+ 'warmSeconds', warm_seconds
191
+ ) order by bucket)
192
+ from bucket_rows
193
+ ), '[]'::jsonb) as buckets,
194
+ coalesce((
195
+ select jsonb_agg(jsonb_build_object(
196
+ 'groupId', group_id,
197
+ 'warmSeconds', warm_seconds
198
+ ) order by warm_seconds desc, group_id)
199
+ from warm_group_rows
200
+ ), '[]'::jsonb) as warm_groups
201
+ from current_totals
202
+ cross join prior_totals
203
+ cross join month_totals
204
+ `);
205
+ if (!row) {
206
+ throw new Error("Insights usage bundle query returned no row");
207
+ }
208
+
209
+ const buckets = new Map(
210
+ records(row.buckets, "buckets").map((bucketRow) => [
211
+ stringValue(bucketRow, "bucket"),
212
+ {
213
+ costMicros: nullableNumberValue(bucketRow.costMicros, "costMicros"),
214
+ warmSeconds: numberValue(bucketRow.warmSeconds, "warmSeconds"),
215
+ },
216
+ ]),
217
+ );
218
+ const warmGroups = records(row.warm_groups, "warmGroups")
219
+ .filter((groupRow) => INSIGHTS_WARM_GROUP_UUID_RE.test(stringValue(groupRow, "groupId")))
220
+ .slice(0, warmGroupLimit)
221
+ .map((groupRow) => ({
222
+ groupId: stringValue(groupRow, "groupId"),
223
+ warmSeconds: numberValue(groupRow.warmSeconds, "warmSeconds"),
224
+ }));
225
+
226
+ return {
227
+ workspaceCreditMicros: numberValue(row.workspace_credit_micros, "workspaceCreditMicros"),
228
+ priorWorkspaceCreditMicros: numberValue(
229
+ row.prior_workspace_credit_micros,
230
+ "priorWorkspaceCreditMicros",
231
+ ),
232
+ warmSeconds: numberValue(row.warm_seconds, "warmSeconds"),
233
+ priorWarmSeconds: numberValue(row.prior_warm_seconds, "priorWarmSeconds"),
234
+ buckets,
235
+ warmGroups,
236
+ billableTokensUsed: numberValue(row.billable_tokens_used, "billableTokensUsed"),
237
+ agentRunsUsed: numberValue(row.agent_runs_used, "agentRunsUsed"),
238
+ };
239
+ });
240
+ }