@ganju/utils 0.0.14 → 0.0.16
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/channelCustomer.d.ts +99 -0
- package/dist/channelCustomer.d.ts.map +1 -0
- package/dist/channelCustomer.js +533 -0
- package/dist/channelDebounce.d.ts +7 -0
- package/dist/channelDebounce.d.ts.map +1 -1
- package/dist/chunkOverlap.d.ts +2 -0
- package/dist/chunkOverlap.d.ts.map +1 -0
- package/dist/chunkOverlap.js +9 -0
- package/dist/chunking.d.ts.map +1 -1
- package/dist/chunking.js +24 -4
- package/dist/citations.d.ts +28 -0
- package/dist/citations.d.ts.map +1 -0
- package/dist/citations.js +111 -0
- package/dist/constants.d.ts +49 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +202 -17
- package/dist/data.d.ts +9 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +78 -0
- package/dist/dataApi.d.ts +511 -0
- package/dist/dataApi.d.ts.map +1 -0
- package/dist/dataApi.js +355 -0
- package/dist/dataCompiler.d.ts +68 -0
- package/dist/dataCompiler.d.ts.map +1 -0
- package/dist/dataCompiler.js +726 -0
- package/dist/dataDdl.d.ts +29 -0
- package/dist/dataDdl.d.ts.map +1 -0
- package/dist/dataDdl.js +354 -0
- package/dist/dataEngine.d.ts +143 -0
- package/dist/dataEngine.d.ts.map +1 -0
- package/dist/dataEngine.js +2022 -0
- package/dist/dataIdentifiers.d.ts +8 -0
- package/dist/dataIdentifiers.d.ts.map +1 -0
- package/dist/dataIdentifiers.js +55 -0
- package/dist/dataImport.d.ts +77 -0
- package/dist/dataImport.d.ts.map +1 -0
- package/dist/dataImport.js +450 -0
- package/dist/dataRpc.d.ts +131 -0
- package/dist/dataRpc.d.ts.map +1 -0
- package/dist/dataRpc.js +2 -0
- package/dist/dataTypes.d.ts +157 -0
- package/dist/dataTypes.d.ts.map +1 -0
- package/dist/dataTypes.js +160 -0
- package/dist/index.d.ts +570 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -0
- package/dist/jsonSchemaToZodShape.d.ts +5 -1
- package/dist/jsonSchemaToZodShape.d.ts.map +1 -1
- package/dist/jsonSchemaToZodShape.js +21 -9
- package/dist/oauth.d.ts +14 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +42 -2
- package/dist/pagination.d.ts +47 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +160 -0
- package/dist/processQueueBatch.d.ts +6 -1
- package/dist/processQueueBatch.d.ts.map +1 -1
- package/dist/processQueueBatch.js +23 -10
- package/dist/queueFailure.d.ts +14 -0
- package/dist/queueFailure.d.ts.map +1 -0
- package/dist/queueFailure.js +43 -0
- package/dist/resourceRerank.d.ts +3 -2
- package/dist/resourceRerank.d.ts.map +1 -1
- package/dist/resourceRerank.js +8 -3
- package/dist/schema.d.ts +374 -29
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +290 -6
- package/dist/ssrf.d.ts +1 -0
- package/dist/ssrf.d.ts.map +1 -1
- package/dist/ssrf.js +48 -12
- package/dist/toolConfirmation.d.ts +48 -0
- package/dist/toolConfirmation.d.ts.map +1 -1
- package/dist/toolConfirmation.js +75 -1
- package/dist/toolCount.d.ts +13 -0
- package/dist/toolCount.d.ts.map +1 -0
- package/dist/toolCount.js +45 -0
- package/dist/toolLint.d.ts +1 -1
- package/dist/toolLint.d.ts.map +1 -1
- package/dist/toolLint.js +20 -0
- package/dist/untrustedContent.d.ts +135 -0
- package/dist/untrustedContent.d.ts.map +1 -0
- package/dist/untrustedContent.js +402 -0
- package/package.json +17 -1
- package/src/channelCustomer.ts +604 -0
- package/src/channelDebounce.ts +17 -0
- package/src/chunkOverlap.ts +6 -0
- package/src/chunking.ts +25 -4
- package/src/citations.ts +127 -0
- package/src/constants.ts +219 -17
- package/src/data.ts +74 -0
- package/src/dataApi.ts +428 -0
- package/src/dataCompiler.ts +948 -0
- package/src/dataDdl.ts +419 -0
- package/src/dataEngine.ts +2753 -0
- package/src/dataIdentifiers.ts +63 -0
- package/src/dataImport.ts +554 -0
- package/src/dataRpc.ts +121 -0
- package/src/dataTypes.ts +312 -0
- package/src/index.ts +156 -2
- package/src/jsonSchemaToZodShape.ts +31 -13
- package/src/oauth.ts +42 -1
- package/src/pagination.ts +193 -0
- package/src/processQueueBatch.ts +42 -12
- package/src/queueFailure.ts +63 -0
- package/src/resourceRerank.ts +10 -3
- package/src/schema.ts +346 -4
- package/src/ssrf.ts +40 -11
- package/src/toolConfirmation.ts +123 -0
- package/src/toolCount.ts +53 -0
- package/src/toolLint.ts +27 -0
- package/src/untrustedContent.ts +476 -0
package/src/dataRpc.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// The methods a project's database object answers over RPC. apps/data's
|
|
2
|
+
// ProjectDatabase implements it; apps/api, apps/mcp and apps/tool-broker call
|
|
3
|
+
// it through databaseStub. Every method resolves to a DataResult.
|
|
4
|
+
import type {
|
|
5
|
+
DataCaller,
|
|
6
|
+
DataDeleteImpact,
|
|
7
|
+
DataResult,
|
|
8
|
+
DataSchema,
|
|
9
|
+
DataTable,
|
|
10
|
+
DataTableCopy
|
|
11
|
+
} from './dataTypes';
|
|
12
|
+
|
|
13
|
+
export type ExportFormat = 'jsonl' | 'csv';
|
|
14
|
+
|
|
15
|
+
export interface ExportFile {
|
|
16
|
+
// null for schema.json
|
|
17
|
+
table: string | null;
|
|
18
|
+
key: string;
|
|
19
|
+
rows: number;
|
|
20
|
+
bytes: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ExportState {
|
|
24
|
+
id: string;
|
|
25
|
+
format: ExportFormat;
|
|
26
|
+
status: 'running' | 'done' | 'failed';
|
|
27
|
+
startedAt: string;
|
|
28
|
+
finishedAt: string | null;
|
|
29
|
+
actor: string;
|
|
30
|
+
tables: string[];
|
|
31
|
+
tableIndex: number;
|
|
32
|
+
afterId: number;
|
|
33
|
+
upload: {
|
|
34
|
+
key: string;
|
|
35
|
+
uploadId: string;
|
|
36
|
+
parts: { partNumber: number; etag: string }[];
|
|
37
|
+
rows: number;
|
|
38
|
+
bytes: number;
|
|
39
|
+
// Bytes read but not yet uploaded, kept in R2 between steps: every part
|
|
40
|
+
// but the last must be exactly the same size.
|
|
41
|
+
carryKey: string | null;
|
|
42
|
+
} | null;
|
|
43
|
+
files: ExportFile[];
|
|
44
|
+
error: string | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface DatabaseInfo {
|
|
48
|
+
artifactId: string | null;
|
|
49
|
+
name: string | null;
|
|
50
|
+
initializedAt: string | null;
|
|
51
|
+
deletedAt: string | null;
|
|
52
|
+
firstWriteAt: string | null;
|
|
53
|
+
schemaVersion: number;
|
|
54
|
+
size: number;
|
|
55
|
+
tables: { name: string; label: string | null; columns: number }[];
|
|
56
|
+
// A column change copying a large table in the background: table changes,
|
|
57
|
+
// and writes that would change its rows, wait while it runs.
|
|
58
|
+
copy: DataTableCopy | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface RestoreResult {
|
|
62
|
+
bookmark: string;
|
|
63
|
+
undoBookmark: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type R<T> = Promise<DataResult<T>>;
|
|
67
|
+
|
|
68
|
+
export interface ProjectDatabaseRpc {
|
|
69
|
+
init(args: { artifactId: string; name: string }): R<DatabaseInfo>;
|
|
70
|
+
info(): R<DatabaseInfo>;
|
|
71
|
+
rename(args: { name: string }): R<DatabaseInfo>;
|
|
72
|
+
size(): R<{ bytes: number }>;
|
|
73
|
+
markDeleted(
|
|
74
|
+
caller: DataCaller
|
|
75
|
+
): R<{ deletedAt: string | null; bookmark: string }>;
|
|
76
|
+
undelete(caller: DataCaller): R<DatabaseInfo>;
|
|
77
|
+
purge(): R<{ purged: true; bookmark: string }>;
|
|
78
|
+
currentBookmark(): R<{ bookmark: string }>;
|
|
79
|
+
restoreTo(caller: DataCaller, args: { timestamp: number }): R<RestoreResult>;
|
|
80
|
+
restoreToBookmark(args: { bookmark: string }): R<RestoreResult>;
|
|
81
|
+
schemaRead(): R<DataSchema>;
|
|
82
|
+
createTable(caller: DataCaller, input: unknown): R<DataTable>;
|
|
83
|
+
updateTable(caller: DataCaller, table: string, patch: unknown): R<DataTable>;
|
|
84
|
+
dropTable(
|
|
85
|
+
caller: DataCaller,
|
|
86
|
+
table: string
|
|
87
|
+
): R<{ dropped: string; bookmark: string }>;
|
|
88
|
+
addColumn(caller: DataCaller, table: string, input: unknown): R<DataTable>;
|
|
89
|
+
updateColumn(
|
|
90
|
+
caller: DataCaller,
|
|
91
|
+
table: string,
|
|
92
|
+
column: string,
|
|
93
|
+
patch: unknown
|
|
94
|
+
): R<{ table: DataTable; bookmark: string | null; copy: DataTableCopy | null }>;
|
|
95
|
+
dropColumn(
|
|
96
|
+
caller: DataCaller,
|
|
97
|
+
table: string,
|
|
98
|
+
column: string
|
|
99
|
+
): R<{ table: DataTable; bookmark: string; copy: DataTableCopy | null }>;
|
|
100
|
+
// Forgets a failed background copy once the owner has seen why.
|
|
101
|
+
dismissCopy(caller: DataCaller): R<{ copy: null }>;
|
|
102
|
+
describe(caller: DataCaller, args?: unknown): R<unknown>;
|
|
103
|
+
query(caller: DataCaller, args: unknown): R<unknown>;
|
|
104
|
+
write(
|
|
105
|
+
caller: DataCaller,
|
|
106
|
+
args: unknown
|
|
107
|
+
): R<{ ok: true; results: unknown[] }>;
|
|
108
|
+
deleteImpact(
|
|
109
|
+
caller: DataCaller,
|
|
110
|
+
args: { table: string; ids?: number[] }
|
|
111
|
+
): R<DataDeleteImpact>;
|
|
112
|
+
history(
|
|
113
|
+
caller: DataCaller,
|
|
114
|
+
args: { table: string; id: number; limit?: number; cursor?: number }
|
|
115
|
+
): R<unknown>;
|
|
116
|
+
exportStart(
|
|
117
|
+
caller: DataCaller,
|
|
118
|
+
args?: { format?: ExportFormat }
|
|
119
|
+
): R<{ exportId: string; status: ExportState['status'] }>;
|
|
120
|
+
exportStatus(args?: { exportId?: string }): R<ExportState>;
|
|
121
|
+
}
|
package/src/dataTypes.ts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// The shapes and limits shared by a project's database object (apps/data),
|
|
2
|
+
// the workers that call it, and the tests. Pure: nothing here touches SQLite.
|
|
3
|
+
|
|
4
|
+
export const DATA_COLUMN_TYPES = [
|
|
5
|
+
'text',
|
|
6
|
+
'long_text',
|
|
7
|
+
'integer',
|
|
8
|
+
'decimal',
|
|
9
|
+
'boolean',
|
|
10
|
+
'date',
|
|
11
|
+
'datetime',
|
|
12
|
+
'enum',
|
|
13
|
+
'json',
|
|
14
|
+
'email',
|
|
15
|
+
'url',
|
|
16
|
+
'phone',
|
|
17
|
+
'relation',
|
|
18
|
+
'file'
|
|
19
|
+
] as const;
|
|
20
|
+
export type DataColumnType = (typeof DATA_COLUMN_TYPES)[number];
|
|
21
|
+
|
|
22
|
+
// What the assistant may do with a table when the caller is restricted (a
|
|
23
|
+
// channel bot). Owners, the dashboard, the CLI and functions see every table.
|
|
24
|
+
export const DATA_ACCESS_LEVELS = ['none', 'read', 'add', 'full'] as const;
|
|
25
|
+
export type DataAccess = (typeof DATA_ACCESS_LEVELS)[number];
|
|
26
|
+
export const DATA_ACCESS_RANK: Record<DataAccess, number> = {
|
|
27
|
+
none: 0,
|
|
28
|
+
read: 1,
|
|
29
|
+
add: 2,
|
|
30
|
+
full: 3
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const DATA_ON_DELETE = ['restrict', 'cascade', 'set_null'] as const;
|
|
34
|
+
export type DataOnDelete = (typeof DATA_ON_DELETE)[number];
|
|
35
|
+
|
|
36
|
+
export type DataDefaultValue = string | number | boolean | null;
|
|
37
|
+
|
|
38
|
+
// A column as the owner defines it: the dashboard's form, `ganju.data.json`
|
|
39
|
+
// and the table-create body all use this shape.
|
|
40
|
+
export interface DataColumnInput {
|
|
41
|
+
name: string;
|
|
42
|
+
type: DataColumnType;
|
|
43
|
+
label?: string | null;
|
|
44
|
+
description?: string | null;
|
|
45
|
+
required?: boolean;
|
|
46
|
+
unique?: boolean;
|
|
47
|
+
filterable?: boolean;
|
|
48
|
+
searchable?: boolean;
|
|
49
|
+
personal?: boolean;
|
|
50
|
+
// enum
|
|
51
|
+
values?: string[];
|
|
52
|
+
// relation: the table it points at, and what deleting that row does
|
|
53
|
+
table?: string;
|
|
54
|
+
onDelete?: DataOnDelete;
|
|
55
|
+
// integer / decimal: the lowest value the column may hold
|
|
56
|
+
min?: number | null;
|
|
57
|
+
default?: DataDefaultValue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DataTableInput {
|
|
61
|
+
name: string;
|
|
62
|
+
label?: string | null;
|
|
63
|
+
description?: string | null;
|
|
64
|
+
displayColumn?: string | null;
|
|
65
|
+
access?: DataAccess;
|
|
66
|
+
customerScoped?: boolean;
|
|
67
|
+
history?: boolean;
|
|
68
|
+
columns: DataColumnInput[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// A column as the database object stores it: the input plus its stable id,
|
|
72
|
+
// which names its indexes and constraints so a rename never orphans them.
|
|
73
|
+
export interface DataColumn {
|
|
74
|
+
id: number;
|
|
75
|
+
name: string;
|
|
76
|
+
type: DataColumnType;
|
|
77
|
+
label: string | null;
|
|
78
|
+
description: string | null;
|
|
79
|
+
required: boolean;
|
|
80
|
+
unique: boolean;
|
|
81
|
+
filterable: boolean;
|
|
82
|
+
searchable: boolean;
|
|
83
|
+
personal: boolean;
|
|
84
|
+
values: string[] | null;
|
|
85
|
+
table: string | null;
|
|
86
|
+
onDelete: DataOnDelete | null;
|
|
87
|
+
min: number | null;
|
|
88
|
+
default: DataDefaultValue | undefined;
|
|
89
|
+
position: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface DataTable {
|
|
93
|
+
id: number;
|
|
94
|
+
name: string;
|
|
95
|
+
label: string | null;
|
|
96
|
+
description: string | null;
|
|
97
|
+
displayColumn: string | null;
|
|
98
|
+
access: DataAccess;
|
|
99
|
+
customerScoped: boolean;
|
|
100
|
+
history: boolean;
|
|
101
|
+
position: number;
|
|
102
|
+
columns: DataColumn[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface DataSchema {
|
|
106
|
+
tables: DataTable[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Who is calling and under which rules. `actor` is recorded on every row a
|
|
110
|
+
// call writes; the storage layer refuses a write without one.
|
|
111
|
+
export interface DataCaller {
|
|
112
|
+
// user:<id> · cli:<tokenId> · mcp:<userId> · channel:<participantId> ·
|
|
113
|
+
// function:<toolName> · trigger:<id> · system:<job>
|
|
114
|
+
actor: string;
|
|
115
|
+
// Apply each table's assistant access. Set for channel bots only.
|
|
116
|
+
restricted?: boolean;
|
|
117
|
+
// Customer-scoped tables: fill and filter `participant_id` with this.
|
|
118
|
+
participantId?: string;
|
|
119
|
+
// Datetimes come back in this zone, with the offset.
|
|
120
|
+
timeZone?: string;
|
|
121
|
+
limits?: DataCallerLimits;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface DataCallerLimits {
|
|
125
|
+
// Writes that add data stop at this size (the plan's ceiling).
|
|
126
|
+
maxBytes?: number | null;
|
|
127
|
+
maxTables?: number | null;
|
|
128
|
+
// The organization left the paid plan: reads and exports only.
|
|
129
|
+
readOnly?: boolean;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface DataUsage {
|
|
133
|
+
rowsRead: number;
|
|
134
|
+
rowsWritten: number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const DATA_ERROR_CODES = [
|
|
138
|
+
'invalid',
|
|
139
|
+
'not_found',
|
|
140
|
+
'forbidden',
|
|
141
|
+
'conflict',
|
|
142
|
+
'constraint',
|
|
143
|
+
'guard',
|
|
144
|
+
'too_large',
|
|
145
|
+
'full',
|
|
146
|
+
'read_only',
|
|
147
|
+
'deleted',
|
|
148
|
+
'not_initialised',
|
|
149
|
+
'restore',
|
|
150
|
+
'internal'
|
|
151
|
+
] as const;
|
|
152
|
+
export type DataErrorCode = (typeof DATA_ERROR_CODES)[number];
|
|
153
|
+
|
|
154
|
+
// The one error the database object returns. Its message is written for the
|
|
155
|
+
// person or model that made the call, never raw SQLite text.
|
|
156
|
+
export class DataError extends Error {
|
|
157
|
+
readonly code: DataErrorCode;
|
|
158
|
+
readonly details: Record<string, unknown> | undefined;
|
|
159
|
+
|
|
160
|
+
constructor(
|
|
161
|
+
message: string,
|
|
162
|
+
code: DataErrorCode = 'invalid',
|
|
163
|
+
details?: Record<string, unknown>
|
|
164
|
+
) {
|
|
165
|
+
super(message);
|
|
166
|
+
this.name = 'DataError';
|
|
167
|
+
this.code = code;
|
|
168
|
+
this.details = details;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// What the API answers with; its error handler reads both.
|
|
172
|
+
get status(): 400 | 403 | 404 | 409 | 500 {
|
|
173
|
+
return DATA_ERROR_STATUS[this.code];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
toBody(): Record<string, unknown> {
|
|
177
|
+
return { code: this.code, ...(this.details ? { details: this.details } : {}) };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const DATA_ERROR_STATUS: Record<DataErrorCode, 400 | 403 | 404 | 409 | 500> = {
|
|
182
|
+
invalid: 400,
|
|
183
|
+
not_found: 404,
|
|
184
|
+
forbidden: 403,
|
|
185
|
+
conflict: 409,
|
|
186
|
+
constraint: 409,
|
|
187
|
+
guard: 409,
|
|
188
|
+
too_large: 400,
|
|
189
|
+
full: 409,
|
|
190
|
+
read_only: 403,
|
|
191
|
+
deleted: 409,
|
|
192
|
+
not_initialised: 404,
|
|
193
|
+
restore: 400,
|
|
194
|
+
internal: 500
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const isDataError = (error: unknown): error is DataError =>
|
|
198
|
+
error instanceof DataError;
|
|
199
|
+
|
|
200
|
+
// What every database object method returns. Errors travel as values, not
|
|
201
|
+
// throws: an RPC exception keeps only its message, and the caller needs the
|
|
202
|
+
// code and the rows read before it.
|
|
203
|
+
export type DataResult<T> =
|
|
204
|
+
| { ok: true; value: T; usage: DataUsage }
|
|
205
|
+
| {
|
|
206
|
+
ok: false;
|
|
207
|
+
error: {
|
|
208
|
+
code: DataErrorCode;
|
|
209
|
+
message: string;
|
|
210
|
+
details?: Record<string, unknown>;
|
|
211
|
+
};
|
|
212
|
+
usage: DataUsage;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Limits. SQLite in a Durable Object allows 100 columns per table, 100 bound
|
|
216
|
+
// parameters per statement and 100 KB per statement; the rest are ours.
|
|
217
|
+
export const DATA_MAX_PARAMS = 100;
|
|
218
|
+
export const DATA_MAX_STATEMENT_BYTES = 90_000;
|
|
219
|
+
// 100 minus id, created_at, updated_at, version, created_by, updated_by and
|
|
220
|
+
// participant_id.
|
|
221
|
+
export const DATA_MAX_COLUMNS = 93;
|
|
222
|
+
export const DATA_MAX_TABLES = 50;
|
|
223
|
+
export const DATA_DEFAULT_PAGE = 20;
|
|
224
|
+
export const DATA_MAX_PAGE = 500;
|
|
225
|
+
export const DATA_MAX_RESULT_BYTES = 1024 * 1024;
|
|
226
|
+
// Past this many rows, an aggregate or a sort on an unindexed column needs a
|
|
227
|
+
// filter on an indexed one: the object serves one request at a time.
|
|
228
|
+
export const DATA_LARGE_TABLE_ROWS = 200_000;
|
|
229
|
+
export const DATA_MAX_WRITE_OPERATIONS = 50;
|
|
230
|
+
export const DATA_MAX_INSERT_ROWS = 500;
|
|
231
|
+
export const DATA_MAX_ROWS_PER_WRITE = 5_000;
|
|
232
|
+
export const DATA_MAX_VALUE_BYTES = 1_000_000;
|
|
233
|
+
export const DATA_MAX_DESCRIPTION = 300;
|
|
234
|
+
export const DATA_MAX_LABEL = 100;
|
|
235
|
+
export const DATA_MAX_ENUM_VALUES = 100;
|
|
236
|
+
export const DATA_MAX_IN_VALUES = 50;
|
|
237
|
+
export const DATA_MAX_SORT_KEYS = 3;
|
|
238
|
+
export const DATA_MAX_AGGREGATES = 5;
|
|
239
|
+
export const DATA_MAX_GROUP_BY = 3;
|
|
240
|
+
export const DATA_MAX_GROUPS = 100;
|
|
241
|
+
// A type change copies the table in one request up to this size. A larger
|
|
242
|
+
// table is copied in the background, this many rows a step (tens of
|
|
243
|
+
// milliseconds, so other requests are served in between), and writes that
|
|
244
|
+
// would change its rows wait until it is done.
|
|
245
|
+
export const DATA_REBUILD_MAX_ROWS = 100_000;
|
|
246
|
+
export const DATA_COPY_STEP_ROWS = 5_000;
|
|
247
|
+
// A delete preview follows cascades through up to this many rows; past it,
|
|
248
|
+
// its counts are lower bounds.
|
|
249
|
+
export const DATA_IMPACT_MAX_ROWS = 200_000;
|
|
250
|
+
export const DATA_IMPACT_MAX_IDS = DATA_MAX_ROWS_PER_WRITE;
|
|
251
|
+
export const DATA_HISTORY_DAYS = 90;
|
|
252
|
+
|
|
253
|
+
// What deleting rows does elsewhere: one entry per relation column that points
|
|
254
|
+
// at a row the delete removes, cascades followed all the way down. `depth` is
|
|
255
|
+
// how many cascades away from the deleted rows the pointed-at table is.
|
|
256
|
+
export interface DataDeleteImpact {
|
|
257
|
+
table: string;
|
|
258
|
+
rows: number;
|
|
259
|
+
effects: {
|
|
260
|
+
table: string;
|
|
261
|
+
column: string;
|
|
262
|
+
onDelete: DataOnDelete;
|
|
263
|
+
rows: number;
|
|
264
|
+
depth: number;
|
|
265
|
+
}[];
|
|
266
|
+
// A restrict would refuse the delete.
|
|
267
|
+
blocked: boolean;
|
|
268
|
+
// Past DATA_IMPACT_MAX_ROWS: every count is at least what it says.
|
|
269
|
+
truncated: boolean;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// A table copy running in the background, as callers see it.
|
|
273
|
+
export interface DataTableCopy {
|
|
274
|
+
table: string;
|
|
275
|
+
// The column whose change or drop started it.
|
|
276
|
+
column: string;
|
|
277
|
+
kind: 'change' | 'drop';
|
|
278
|
+
rows: number;
|
|
279
|
+
copied: number;
|
|
280
|
+
startedAt: string;
|
|
281
|
+
actor: string;
|
|
282
|
+
status: 'running' | 'failed';
|
|
283
|
+
error: string | null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// The table as the owner would write it again: what `ganju.data.json` and an
|
|
287
|
+
// export's schema.json hold.
|
|
288
|
+
export const toTableInput = (table: DataTable): DataTableInput => ({
|
|
289
|
+
name: table.name,
|
|
290
|
+
label: table.label,
|
|
291
|
+
description: table.description,
|
|
292
|
+
displayColumn: table.displayColumn,
|
|
293
|
+
access: table.access,
|
|
294
|
+
customerScoped: table.customerScoped,
|
|
295
|
+
history: table.history,
|
|
296
|
+
columns: table.columns.map(column => {
|
|
297
|
+
const out: DataColumnInput = { name: column.name, type: column.type };
|
|
298
|
+
if (column.label) out.label = column.label;
|
|
299
|
+
if (column.description) out.description = column.description;
|
|
300
|
+
if (column.required) out.required = true;
|
|
301
|
+
if (column.unique) out.unique = true;
|
|
302
|
+
if (column.filterable) out.filterable = true;
|
|
303
|
+
if (column.searchable) out.searchable = true;
|
|
304
|
+
if (column.personal) out.personal = true;
|
|
305
|
+
if (column.values) out.values = column.values;
|
|
306
|
+
if (column.table) out.table = column.table;
|
|
307
|
+
if (column.onDelete) out.onDelete = column.onDelete;
|
|
308
|
+
if (column.min !== null) out.min = column.min;
|
|
309
|
+
if (column.default !== undefined) out.default = column.default;
|
|
310
|
+
return out;
|
|
311
|
+
})
|
|
312
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -98,6 +98,14 @@ import {
|
|
|
98
98
|
} from './jsonSchemaToZodShape';
|
|
99
99
|
import type { SchemaViolation } from './jsonSchemaToZodShape';
|
|
100
100
|
import { buildProxyToolName } from './mcpProxy';
|
|
101
|
+
import { countInstallTools } from './toolCount';
|
|
102
|
+
import {
|
|
103
|
+
capText,
|
|
104
|
+
findNextCursor,
|
|
105
|
+
paginate,
|
|
106
|
+
InvalidCursorError,
|
|
107
|
+
listResourcesPage
|
|
108
|
+
} from './pagination';
|
|
101
109
|
import {
|
|
102
110
|
mintCustomCodeToken,
|
|
103
111
|
verifyCustomCodeToken,
|
|
@@ -142,7 +150,7 @@ import type {
|
|
|
142
150
|
ResolvedAttachment,
|
|
143
151
|
ResolveAttachmentResult
|
|
144
152
|
} from './attachment';
|
|
145
|
-
import { ipv4InPrivateRange, isBlockedHost } from './ssrf';
|
|
153
|
+
import { ipv4InPrivateRange, isBlockedHost, isBlockedUrl } from './ssrf';
|
|
146
154
|
import {
|
|
147
155
|
requiresLlmBaseUrl,
|
|
148
156
|
isAllowedLlmBaseUrl,
|
|
@@ -201,8 +209,10 @@ import type { RerankAiBinding } from './resourceRerank';
|
|
|
201
209
|
import { sleep, isRateLimitError, withRateLimitRetry } from './retry';
|
|
202
210
|
import type { RateLimitRetryOptions } from './retry';
|
|
203
211
|
import { processQueueBatch } from './processQueueBatch';
|
|
212
|
+
import { PermanentJobError, isPermanentJobError } from './queueFailure';
|
|
204
213
|
import type {
|
|
205
214
|
QueueBatchLike,
|
|
215
|
+
QueueFailureContext,
|
|
206
216
|
QueueMessageLike,
|
|
207
217
|
ProcessQueueBatchHandlers
|
|
208
218
|
} from './processQueueBatch';
|
|
@@ -222,6 +232,7 @@ import {
|
|
|
222
232
|
import type {
|
|
223
233
|
BufferedChannelMessage,
|
|
224
234
|
BufferedChannelCommand,
|
|
235
|
+
BufferedVoiceNote,
|
|
225
236
|
ChannelBufferEnvelope,
|
|
226
237
|
ChannelBufferFlush
|
|
227
238
|
} from './channelDebounce';
|
|
@@ -235,13 +246,79 @@ import {
|
|
|
235
246
|
annotationsForEffect,
|
|
236
247
|
TOOL_EFFECTS,
|
|
237
248
|
isSensitiveTool,
|
|
249
|
+
proxiedToolAnnotations,
|
|
250
|
+
proxiedToolTrust,
|
|
251
|
+
isSensitiveProxiedTool,
|
|
252
|
+
keepProxiedToolMarks,
|
|
253
|
+
toolApprovalStatus,
|
|
254
|
+
toolApprovalUrl,
|
|
238
255
|
stableJson
|
|
239
256
|
} from './toolConfirmation';
|
|
240
257
|
import type {
|
|
241
258
|
PendingToolConfirmation,
|
|
242
259
|
PendingToolConfirmations,
|
|
243
|
-
ToolEffect
|
|
260
|
+
ToolEffect,
|
|
261
|
+
ToolApprovalStatus,
|
|
262
|
+
ProxiedToolTrust
|
|
244
263
|
} from './toolConfirmation';
|
|
264
|
+
import {
|
|
265
|
+
wrapUntrustedContent,
|
|
266
|
+
unwrapUntrustedContent,
|
|
267
|
+
isUntrustedToolResult,
|
|
268
|
+
findInstructionLikeText,
|
|
269
|
+
UNTRUSTED_CONTENT_TAG,
|
|
270
|
+
UNTRUSTED_CONTENT_META_KEY,
|
|
271
|
+
UNTRUSTED_CONTENT_NOTE,
|
|
272
|
+
INSTRUCTION_WARNING_METADATA_KEY,
|
|
273
|
+
untrustedToolResult,
|
|
274
|
+
ownWritingToolResult,
|
|
275
|
+
labelOwnToolResult,
|
|
276
|
+
labelProxiedToolResult,
|
|
277
|
+
untrustedErrorResult,
|
|
278
|
+
readsLikeInstructions,
|
|
279
|
+
labelResourceContents
|
|
280
|
+
} from './untrustedContent';
|
|
281
|
+
import type {
|
|
282
|
+
InstructionWarning,
|
|
283
|
+
LabelledToolResult
|
|
284
|
+
} from './untrustedContent';
|
|
285
|
+
import {
|
|
286
|
+
PARTICIPANT_DAILY_LIMIT_DEFAULT,
|
|
287
|
+
PARTICIPANT_DAILY_LIMIT_MAX,
|
|
288
|
+
PARTICIPANT_DAILY_LIMIT_OFF,
|
|
289
|
+
PARTICIPANT_DAILY_LIMIT_WINDOW_MS,
|
|
290
|
+
PARTICIPANT_LIMIT_METADATA_KEY,
|
|
291
|
+
resolveParticipantDailyLimit,
|
|
292
|
+
resolveParticipantMemoryEnabled,
|
|
293
|
+
VOICE_NOTE_MAX_BYTES,
|
|
294
|
+
VOICE_NOTE_MAX_SECONDS,
|
|
295
|
+
audioDurationSeconds,
|
|
296
|
+
oggDurationSeconds,
|
|
297
|
+
VOICE_NOTE_TRANSCRIPTION_PROMPT,
|
|
298
|
+
VOICE_NOTE_METADATA_KEY,
|
|
299
|
+
VOICE_NOTE_UNREADABLE_METADATA_KEY,
|
|
300
|
+
PARTICIPANT_MEMORY_TOOL_NAME,
|
|
301
|
+
PARTICIPANT_MEMORY_MAX_FACTS,
|
|
302
|
+
PARTICIPANT_MEMORY_TOOL_DESCRIPTION,
|
|
303
|
+
PARTICIPANT_MEMORY_TOOL_SCHEMA,
|
|
304
|
+
PARTICIPANT_MEMORY_GROUP_NOTE,
|
|
305
|
+
readParticipantMemory,
|
|
306
|
+
applyParticipantMemoryUpdate,
|
|
307
|
+
redactParticipantMemoryArgs,
|
|
308
|
+
redactParticipantMemoryConfirmation,
|
|
309
|
+
participantMemoryUpdateReadsLikeInstructions,
|
|
310
|
+
CONVERSATION_UNTRUSTED_WINDOW_MS,
|
|
311
|
+
CONVERSATION_UNTRUSTED_READ_AT_KEY,
|
|
312
|
+
conversationReadUntrustedRecently,
|
|
313
|
+
formatParticipantMemoryPrompt,
|
|
314
|
+
participantLimitNotice,
|
|
315
|
+
voiceNoteUnreadableNotice,
|
|
316
|
+
voiceNoteTooLongNotice
|
|
317
|
+
} from './channelCustomer';
|
|
318
|
+
import type {
|
|
319
|
+
ParticipantMemory,
|
|
320
|
+
ParticipantMemoryUpdate
|
|
321
|
+
} from './channelCustomer';
|
|
245
322
|
import {
|
|
246
323
|
lintTools,
|
|
247
324
|
TOOL_LINT_RULES,
|
|
@@ -263,9 +340,12 @@ import {
|
|
|
263
340
|
formatSourcesAsButtons
|
|
264
341
|
} from './sources';
|
|
265
342
|
import type { Source, ResourceUrlContext, SourceButton } from './sources';
|
|
343
|
+
import { citesUrl, citedPages, selectCitedSources } from './citations';
|
|
266
344
|
import {
|
|
267
345
|
refreshOAuthToken,
|
|
268
346
|
OAuthReauthRequiredError,
|
|
347
|
+
OAuthRefreshError,
|
|
348
|
+
refreshFailureReauthReason,
|
|
269
349
|
buildReauthMetadata,
|
|
270
350
|
clearReauthMetadata,
|
|
271
351
|
isCredentialNeedingReauth
|
|
@@ -323,6 +403,12 @@ export const utils = {
|
|
|
323
403
|
jsonSchemaToZodShape,
|
|
324
404
|
validateAgainstJsonSchema,
|
|
325
405
|
buildProxyToolName,
|
|
406
|
+
countInstallTools,
|
|
407
|
+
capText,
|
|
408
|
+
findNextCursor,
|
|
409
|
+
paginate,
|
|
410
|
+
InvalidCursorError,
|
|
411
|
+
listResourcesPage,
|
|
326
412
|
mintCustomCodeToken,
|
|
327
413
|
verifyCustomCodeToken,
|
|
328
414
|
customCodeScriptName,
|
|
@@ -347,6 +433,7 @@ export const utils = {
|
|
|
347
433
|
validateProjectPath,
|
|
348
434
|
projectPathIssue,
|
|
349
435
|
ipv4InPrivateRange,
|
|
436
|
+
isBlockedUrl,
|
|
350
437
|
isBlockedHost,
|
|
351
438
|
requiresLlmBaseUrl,
|
|
352
439
|
isAllowedLlmBaseUrl,
|
|
@@ -388,6 +475,8 @@ export const utils = {
|
|
|
388
475
|
isRateLimitError,
|
|
389
476
|
withRateLimitRetry,
|
|
390
477
|
processQueueBatch,
|
|
478
|
+
PermanentJobError,
|
|
479
|
+
isPermanentJobError,
|
|
391
480
|
getToolStatusMessage,
|
|
392
481
|
resolveDebounceMs,
|
|
393
482
|
channelBufferKey,
|
|
@@ -402,7 +491,59 @@ export const utils = {
|
|
|
402
491
|
annotationsForEffect,
|
|
403
492
|
TOOL_EFFECTS,
|
|
404
493
|
isSensitiveTool,
|
|
494
|
+
proxiedToolAnnotations,
|
|
495
|
+
proxiedToolTrust,
|
|
496
|
+
isSensitiveProxiedTool,
|
|
497
|
+
keepProxiedToolMarks,
|
|
498
|
+
toolApprovalStatus,
|
|
499
|
+
toolApprovalUrl,
|
|
405
500
|
stableJson,
|
|
501
|
+
wrapUntrustedContent,
|
|
502
|
+
unwrapUntrustedContent,
|
|
503
|
+
isUntrustedToolResult,
|
|
504
|
+
findInstructionLikeText,
|
|
505
|
+
UNTRUSTED_CONTENT_TAG,
|
|
506
|
+
UNTRUSTED_CONTENT_META_KEY,
|
|
507
|
+
UNTRUSTED_CONTENT_NOTE,
|
|
508
|
+
INSTRUCTION_WARNING_METADATA_KEY,
|
|
509
|
+
untrustedToolResult,
|
|
510
|
+
ownWritingToolResult,
|
|
511
|
+
labelOwnToolResult,
|
|
512
|
+
labelProxiedToolResult,
|
|
513
|
+
untrustedErrorResult,
|
|
514
|
+
readsLikeInstructions,
|
|
515
|
+
labelResourceContents,
|
|
516
|
+
PARTICIPANT_DAILY_LIMIT_DEFAULT,
|
|
517
|
+
PARTICIPANT_DAILY_LIMIT_MAX,
|
|
518
|
+
PARTICIPANT_DAILY_LIMIT_OFF,
|
|
519
|
+
PARTICIPANT_DAILY_LIMIT_WINDOW_MS,
|
|
520
|
+
PARTICIPANT_LIMIT_METADATA_KEY,
|
|
521
|
+
resolveParticipantDailyLimit,
|
|
522
|
+
resolveParticipantMemoryEnabled,
|
|
523
|
+
VOICE_NOTE_MAX_BYTES,
|
|
524
|
+
VOICE_NOTE_MAX_SECONDS,
|
|
525
|
+
audioDurationSeconds,
|
|
526
|
+
oggDurationSeconds,
|
|
527
|
+
VOICE_NOTE_TRANSCRIPTION_PROMPT,
|
|
528
|
+
VOICE_NOTE_METADATA_KEY,
|
|
529
|
+
VOICE_NOTE_UNREADABLE_METADATA_KEY,
|
|
530
|
+
PARTICIPANT_MEMORY_TOOL_NAME,
|
|
531
|
+
PARTICIPANT_MEMORY_MAX_FACTS,
|
|
532
|
+
PARTICIPANT_MEMORY_TOOL_DESCRIPTION,
|
|
533
|
+
PARTICIPANT_MEMORY_TOOL_SCHEMA,
|
|
534
|
+
PARTICIPANT_MEMORY_GROUP_NOTE,
|
|
535
|
+
readParticipantMemory,
|
|
536
|
+
applyParticipantMemoryUpdate,
|
|
537
|
+
redactParticipantMemoryArgs,
|
|
538
|
+
redactParticipantMemoryConfirmation,
|
|
539
|
+
participantMemoryUpdateReadsLikeInstructions,
|
|
540
|
+
CONVERSATION_UNTRUSTED_WINDOW_MS,
|
|
541
|
+
CONVERSATION_UNTRUSTED_READ_AT_KEY,
|
|
542
|
+
conversationReadUntrustedRecently,
|
|
543
|
+
formatParticipantMemoryPrompt,
|
|
544
|
+
participantLimitNotice,
|
|
545
|
+
voiceNoteUnreadableNotice,
|
|
546
|
+
voiceNoteTooLongNotice,
|
|
406
547
|
lintTools,
|
|
407
548
|
TOOL_LINT_RULES,
|
|
408
549
|
TOOL_LINT_MAX_TOOLS,
|
|
@@ -413,8 +554,13 @@ export const utils = {
|
|
|
413
554
|
buildResourceDownloadUrl,
|
|
414
555
|
formatSourcesAsMarkdown,
|
|
415
556
|
formatSourcesAsButtons,
|
|
557
|
+
citesUrl,
|
|
558
|
+
citedPages,
|
|
559
|
+
selectCitedSources,
|
|
416
560
|
refreshOAuthToken,
|
|
417
561
|
OAuthReauthRequiredError,
|
|
562
|
+
OAuthRefreshError,
|
|
563
|
+
refreshFailureReauthReason,
|
|
418
564
|
buildReauthMetadata,
|
|
419
565
|
clearReauthMetadata,
|
|
420
566
|
isCredentialNeedingReauth,
|
|
@@ -429,6 +575,10 @@ export const utils = {
|
|
|
429
575
|
};
|
|
430
576
|
|
|
431
577
|
export type {
|
|
578
|
+
ParticipantMemory,
|
|
579
|
+
ParticipantMemoryUpdate,
|
|
580
|
+
InstructionWarning,
|
|
581
|
+
LabelledToolResult,
|
|
432
582
|
MintedAccessToken,
|
|
433
583
|
CustomCodeProject,
|
|
434
584
|
ProjectPathIssue,
|
|
@@ -439,6 +589,8 @@ export type {
|
|
|
439
589
|
PendingToolConfirmation,
|
|
440
590
|
PendingToolConfirmations,
|
|
441
591
|
ToolEffect,
|
|
592
|
+
ToolApprovalStatus,
|
|
593
|
+
ProxiedToolTrust,
|
|
442
594
|
LintableTool,
|
|
443
595
|
ToolLintFinding,
|
|
444
596
|
ToolLintOptions,
|
|
@@ -479,12 +631,14 @@ export type {
|
|
|
479
631
|
RateLimitRetryOptions,
|
|
480
632
|
RerankAiBinding,
|
|
481
633
|
QueueBatchLike,
|
|
634
|
+
QueueFailureContext,
|
|
482
635
|
QueueMessageLike,
|
|
483
636
|
ProcessQueueBatchHandlers,
|
|
484
637
|
ChannelNotifier,
|
|
485
638
|
ToolStatusEvent,
|
|
486
639
|
BufferedChannelMessage,
|
|
487
640
|
BufferedChannelCommand,
|
|
641
|
+
BufferedVoiceNote,
|
|
488
642
|
ChannelBufferEnvelope,
|
|
489
643
|
ChannelBufferFlush,
|
|
490
644
|
Source,
|