@opengeni/contracts 0.40.0 → 0.50.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/dist/atlassian.d.ts +278 -0
- package/dist/atlassian.js +57 -0
- package/dist/atlassian.js.map +1 -0
- package/dist/canonical-human-identities.d.ts +157 -0
- package/dist/canonical-human-identities.js +23 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/{chunk-7JZMI22I.js → chunk-5UDNP7AO.js} +34 -2
- package/dist/chunk-5UDNP7AO.js.map +1 -0
- package/dist/chunk-BVGIYW7D.js +11 -0
- package/dist/chunk-BVGIYW7D.js.map +1 -0
- package/dist/chunk-CADSX6UN.js +1145 -0
- package/dist/chunk-CADSX6UN.js.map +1 -0
- package/dist/chunk-CM6BMECR.js +24 -0
- package/dist/chunk-CM6BMECR.js.map +1 -0
- package/dist/chunk-D2HKF2EF.js +1460 -0
- package/dist/chunk-D2HKF2EF.js.map +1 -0
- package/dist/chunk-JBCIY7QD.js +194 -0
- package/dist/chunk-JBCIY7QD.js.map +1 -0
- package/dist/chunk-JUFK3T4Q.js +80 -0
- package/dist/chunk-JUFK3T4Q.js.map +1 -0
- package/dist/chunk-LSB7GRLG.js +779 -0
- package/dist/chunk-LSB7GRLG.js.map +1 -0
- package/dist/chunk-LW7OH6CS.js +382 -0
- package/dist/chunk-LW7OH6CS.js.map +1 -0
- package/dist/chunk-M5ZGRVIQ.js +719 -0
- package/dist/chunk-M5ZGRVIQ.js.map +1 -0
- package/dist/chunk-MYBZRDTY.js +340 -0
- package/dist/chunk-MYBZRDTY.js.map +1 -0
- package/dist/chunk-Q6A7XT2N.js +16734 -0
- package/dist/chunk-Q6A7XT2N.js.map +1 -0
- package/dist/chunk-RIY7GYQS.js +1204 -0
- package/dist/chunk-RIY7GYQS.js.map +1 -0
- package/dist/chunk-TZ6YEYN4.js +386 -0
- package/dist/chunk-TZ6YEYN4.js.map +1 -0
- package/dist/chunk-Y3MLSLB4.js +392 -0
- package/dist/chunk-Y3MLSLB4.js.map +1 -0
- package/dist/chunk-YRKRZ6OF.js +134 -0
- package/dist/chunk-YRKRZ6OF.js.map +1 -0
- package/dist/codex-provider-account-authority.d.ts +23 -0
- package/dist/codex-provider-account-authority.js +23 -0
- package/dist/codex-provider-account-authority.js.map +1 -0
- package/dist/company-profile.d.ts +629 -0
- package/dist/document-artifact-commands.d.ts +282 -0
- package/dist/document-artifact-commands.js +54 -0
- package/dist/document-artifact-commands.js.map +1 -0
- package/dist/document-artifact-query.d.ts +2 -0
- package/dist/document-artifact-query.js +54 -0
- package/dist/document-artifact-query.js.map +1 -0
- package/dist/editable-artifact-binary.d.ts +56 -0
- package/dist/editable-artifact-causal-frontier.d.ts +12 -0
- package/dist/editable-artifact-causal-frontier.js +18 -0
- package/dist/editable-artifact-causal-frontier.js.map +1 -0
- package/dist/editable-artifact-codec-registry.d.ts +48 -0
- package/dist/editable-artifact-codec-registry.js +20 -0
- package/dist/editable-artifact-codec-registry.js.map +1 -0
- package/dist/editable-artifact-committed-transaction.d.ts +35 -0
- package/dist/editable-artifact-committed-transaction.js +19 -0
- package/dist/editable-artifact-committed-transaction.js.map +1 -0
- package/dist/editable-artifact-live.d.ts +276 -0
- package/dist/editable-artifact-live.js +907 -0
- package/dist/editable-artifact-live.js.map +1 -0
- package/dist/editable-artifact-serialized-commit.d.ts +53 -0
- package/dist/editable-artifact-serialized-commit.js +26 -0
- package/dist/editable-artifact-serialized-commit.js.map +1 -0
- package/dist/editable-artifact-versions.d.ts +6 -0
- package/dist/editable-artifact-versions.js +11 -0
- package/dist/editable-artifact-versions.js.map +1 -0
- package/dist/editable-artifacts.d.ts +46 -0
- package/dist/editable-artifacts.js +236 -0
- package/dist/editable-artifacts.js.map +1 -0
- package/dist/event-preview.d.ts +1 -1
- package/dist/google-drive.d.ts +114 -2
- package/dist/google-drive.js +72 -14
- package/dist/google-drive.js.map +1 -1
- package/dist/image-generation.d.ts +70 -0
- package/dist/index.d.ts +5661 -166
- package/dist/index.js +1438 -21
- package/dist/interaction.d.ts +8290 -0
- package/dist/knowledge.d.ts +543 -0
- package/dist/memory-slack-delivery.d.ts +397 -0
- package/dist/presentation-artifact-commands.d.ts +349 -0
- package/dist/presentation-artifact-commands.js +66 -0
- package/dist/presentation-artifact-commands.js.map +1 -0
- package/dist/presentation-artifact-query.d.ts +2 -0
- package/dist/presentation-artifact-query.js +66 -0
- package/dist/presentation-artifact-query.js.map +1 -0
- package/dist/retained-output.d.ts +24 -0
- package/dist/sandbox-snapshots.d.ts +9 -0
- package/dist/scoped-knowledge.d.ts +14 -13
- package/dist/slack-bot-scopes.d.ts +4 -0
- package/dist/slack-bot-scopes.js +3 -1
- package/dist/slack-task-policy.d.ts +294 -0
- package/dist/spreadsheet-artifact-commands.d.ts +101 -0
- package/dist/spreadsheet-artifact-commands.js +27 -0
- package/dist/spreadsheet-artifact-commands.js.map +1 -0
- package/dist/spreadsheet-artifact-date.d.ts +4 -0
- package/dist/spreadsheet-artifact-query.d.ts +120 -0
- package/dist/spreadsheet-artifact-query.js +48 -0
- package/dist/spreadsheet-artifact-query.js.map +1 -0
- package/dist/task-notes.d.ts +128 -0
- package/dist/tool-catalog.d.ts +576 -0
- package/dist/video-generation.d.ts +580 -0
- package/dist/video-generation.js +59 -0
- package/dist/video-generation.js.map +1 -0
- package/dist/workspace-learning-policy.d.ts +208 -0
- package/dist/xai-provider-account-authority.d.ts +23 -0
- package/dist/xai-provider-account-authority.js +9 -0
- package/dist/xai-provider-account-authority.js.map +1 -0
- package/package.json +73 -1
- package/src/artifacts.ts +1 -1
- package/src/atlassian.ts +160 -0
- package/src/canonical-human-identities.ts +93 -0
- package/src/codex-provider-account-authority.ts +37 -0
- package/src/company-profile.ts +306 -0
- package/src/document-artifact-commands.ts +1709 -0
- package/src/document-artifact-query.ts +2 -0
- package/src/editable-artifact-binary.ts +396 -0
- package/src/editable-artifact-causal-frontier.ts +154 -0
- package/src/editable-artifact-codec-registry.ts +261 -0
- package/src/editable-artifact-committed-transaction.ts +478 -0
- package/src/editable-artifact-live.ts +1379 -0
- package/src/editable-artifact-serialized-commit.ts +494 -0
- package/src/editable-artifact-versions.ts +8 -0
- package/src/editable-artifacts.ts +473 -0
- package/src/google-drive.ts +68 -15
- package/src/image-generation.ts +106 -0
- package/src/index.ts +2920 -326
- package/src/interaction.ts +3173 -0
- package/src/knowledge.ts +207 -0
- package/src/memory-slack-delivery.ts +183 -0
- package/src/presentation-artifact-commands.ts +2035 -0
- package/src/presentation-artifact-query.ts +2 -0
- package/src/retained-output.ts +149 -2
- package/src/sandbox-snapshots.ts +28 -1
- package/src/scoped-knowledge.ts +18 -4
- package/src/slack-bot-scopes.ts +34 -1
- package/src/slack-task-policy.ts +215 -0
- package/src/spreadsheet-artifact-commands.ts +999 -0
- package/src/spreadsheet-artifact-date.ts +21 -0
- package/src/spreadsheet-artifact-query.ts +1411 -0
- package/src/task-notes.ts +92 -0
- package/src/tool-catalog.ts +334 -0
- package/src/video-generation.ts +431 -0
- package/src/workspace-learning-policy.ts +233 -0
- package/src/xai-provider-account-authority.ts +37 -0
- package/dist/chunk-5HR2GPSC.js +0 -11031
- package/dist/chunk-5HR2GPSC.js.map +0 -1
- package/dist/chunk-7JZMI22I.js.map +0 -1
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
2
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
3
|
+
|
|
4
|
+
export * from "./spreadsheet-artifact-commands";
|
|
5
|
+
export * from "./spreadsheet-artifact-query";
|
|
6
|
+
export * from "./editable-artifact-causal-frontier";
|
|
7
|
+
export * from "./document-artifact-commands";
|
|
8
|
+
export * from "./presentation-artifact-commands";
|
|
9
|
+
export * from "./editable-artifact-codec-registry";
|
|
10
|
+
|
|
11
|
+
export const EDITABLE_ARTIFACT_INTENT_VERSION = 1 as const;
|
|
12
|
+
export const EDITABLE_ARTIFACT_INTENT_MAX_BYTES = 5 * 1024 * 1024;
|
|
13
|
+
export const EDITABLE_ARTIFACT_COMMAND_MAX_BYTES = 4 * 1024 * 1024;
|
|
14
|
+
export const EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES = 512;
|
|
15
|
+
/** Largest durable snapshot every supported browser/WASM client can open. */
|
|
16
|
+
export const EDITABLE_ARTIFACT_PRODUCT_MAX_SNAPSHOT_BYTES = 64 * 1024 * 1024;
|
|
17
|
+
export const EDITABLE_ARTIFACT_INTENT_MAX_CAUSAL_ACTORS = 1_024;
|
|
18
|
+
export const EDITABLE_ARTIFACT_INTENT_MAX_UNDO_TARGETS = 10_000;
|
|
19
|
+
|
|
20
|
+
const MAGIC = new TextEncoder().encode("OGATX001");
|
|
21
|
+
const textEncoder = new TextEncoder();
|
|
22
|
+
const textDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
23
|
+
const STABLE_ID = /^[0-9a-f]{32}$/u;
|
|
24
|
+
const REPLICA_ID = /^[0-9a-f]{16}$/u;
|
|
25
|
+
const CLIENT_TRANSACTION_ID = /^[A-Za-z0-9._:-]{1,200}$/u;
|
|
26
|
+
const REQUEST_HASH = /^sha256:[0-9a-f]{64}$/u;
|
|
27
|
+
|
|
28
|
+
export type EditableArtifactCausalEntry = Readonly<{
|
|
29
|
+
replicaId: string;
|
|
30
|
+
counter: number;
|
|
31
|
+
}>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Exact client-authored mutation identity. Scope and actor authority are
|
|
35
|
+
* deliberately absent: the server derives them and binds them in the
|
|
36
|
+
* idempotency lookup tuple instead of trusting client bytes.
|
|
37
|
+
*/
|
|
38
|
+
export type EditableArtifactMutationIntent = Readonly<{
|
|
39
|
+
envelopeVersion: typeof EDITABLE_ARTIFACT_INTENT_VERSION;
|
|
40
|
+
protocolVersion: number;
|
|
41
|
+
modelSchemaVersion: number;
|
|
42
|
+
commandProtocolVersion: number;
|
|
43
|
+
artifactId: string;
|
|
44
|
+
clientTransactionId: string;
|
|
45
|
+
replicaId: string;
|
|
46
|
+
replicaCounter: number;
|
|
47
|
+
previousLocalTransactionId: string | null;
|
|
48
|
+
observedHeadSequence: number;
|
|
49
|
+
causalBase: readonly EditableArtifactCausalEntry[];
|
|
50
|
+
selectiveUndoOperationIds: readonly string[];
|
|
51
|
+
commandBytes: Uint8Array;
|
|
52
|
+
}>;
|
|
53
|
+
|
|
54
|
+
export function encodeEditableArtifactMutationIntent(
|
|
55
|
+
input: EditableArtifactMutationIntent,
|
|
56
|
+
): Uint8Array {
|
|
57
|
+
// The writer owns the emitted bytes, so a second eager copy of a potentially
|
|
58
|
+
// multi-megabyte command block would add no safety.
|
|
59
|
+
const intent = normalizeIntent(input, false);
|
|
60
|
+
const writer = new BinaryWriter(EDITABLE_ARTIFACT_INTENT_MAX_BYTES);
|
|
61
|
+
writer.bytes(MAGIC);
|
|
62
|
+
writer.u16(intent.envelopeVersion);
|
|
63
|
+
writer.u16(intent.protocolVersion);
|
|
64
|
+
writer.u16(intent.modelSchemaVersion);
|
|
65
|
+
writer.u16(intent.commandProtocolVersion);
|
|
66
|
+
writer.string(intent.artifactId);
|
|
67
|
+
writer.string(intent.clientTransactionId);
|
|
68
|
+
writer.string(intent.replicaId);
|
|
69
|
+
writer.u64(intent.replicaCounter);
|
|
70
|
+
writer.u8(intent.previousLocalTransactionId === null ? 0 : 1);
|
|
71
|
+
if (intent.previousLocalTransactionId !== null) {
|
|
72
|
+
writer.string(intent.previousLocalTransactionId);
|
|
73
|
+
}
|
|
74
|
+
writer.u64(intent.observedHeadSequence);
|
|
75
|
+
writer.u16(intent.causalBase.length);
|
|
76
|
+
for (const entry of intent.causalBase) {
|
|
77
|
+
writer.string(entry.replicaId);
|
|
78
|
+
writer.u64(entry.counter);
|
|
79
|
+
}
|
|
80
|
+
writer.u16(intent.selectiveUndoOperationIds.length);
|
|
81
|
+
for (const operationId of intent.selectiveUndoOperationIds) writer.string(operationId);
|
|
82
|
+
writer.byteBlock(intent.commandBytes);
|
|
83
|
+
return writer.finish();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function decodeEditableArtifactMutationIntent(
|
|
87
|
+
bytes: Uint8Array,
|
|
88
|
+
): EditableArtifactMutationIntent {
|
|
89
|
+
return parseEditableArtifactMutationIntent(bytes, true);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parseEditableArtifactMutationIntent(
|
|
93
|
+
bytes: Uint8Array,
|
|
94
|
+
copyCommandBytes: boolean,
|
|
95
|
+
): EditableArtifactMutationIntent {
|
|
96
|
+
if (!(bytes instanceof Uint8Array)) throw new TypeError("intent bytes must be a Uint8Array");
|
|
97
|
+
if (bytes.byteLength > EDITABLE_ARTIFACT_INTENT_MAX_BYTES) {
|
|
98
|
+
throw new RangeError("editable artifact intent exceeds its byte limit");
|
|
99
|
+
}
|
|
100
|
+
const reader = new BinaryReader(bytes);
|
|
101
|
+
const magic = reader.bytes(MAGIC.byteLength);
|
|
102
|
+
if (!equalBytes(magic, MAGIC)) throw new TypeError("invalid editable artifact intent magic");
|
|
103
|
+
const envelopeVersion = reader.u16();
|
|
104
|
+
if (envelopeVersion !== EDITABLE_ARTIFACT_INTENT_VERSION) {
|
|
105
|
+
throw new TypeError(`unsupported editable artifact intent version: ${envelopeVersion}`);
|
|
106
|
+
}
|
|
107
|
+
const protocolVersion = reader.u16();
|
|
108
|
+
const modelSchemaVersion = reader.u16();
|
|
109
|
+
const commandProtocolVersion = reader.u16();
|
|
110
|
+
const artifactId = reader.string();
|
|
111
|
+
const clientTransactionId = reader.string();
|
|
112
|
+
const replicaId = reader.string();
|
|
113
|
+
const replicaCounter = reader.u64();
|
|
114
|
+
const predecessorFlag = reader.u8();
|
|
115
|
+
if (predecessorFlag > 1) throw new TypeError("invalid predecessor presence flag");
|
|
116
|
+
const previousLocalTransactionId = predecessorFlag === 1 ? reader.string() : null;
|
|
117
|
+
const observedHeadSequence = reader.u64();
|
|
118
|
+
const causalCount = reader.u16();
|
|
119
|
+
if (causalCount > EDITABLE_ARTIFACT_INTENT_MAX_CAUSAL_ACTORS) {
|
|
120
|
+
throw new RangeError("editable artifact causal base exceeds its actor limit");
|
|
121
|
+
}
|
|
122
|
+
const causalBase: EditableArtifactCausalEntry[] = [];
|
|
123
|
+
let previousReplicaId = "";
|
|
124
|
+
for (let index = 0; index < causalCount; index += 1) {
|
|
125
|
+
const causalReplicaId = reader.string();
|
|
126
|
+
if (causalReplicaId <= previousReplicaId) {
|
|
127
|
+
throw new TypeError("causal base replica ids must be unique and canonically sorted");
|
|
128
|
+
}
|
|
129
|
+
previousReplicaId = causalReplicaId;
|
|
130
|
+
causalBase.push(Object.freeze({ replicaId: causalReplicaId, counter: reader.u64() }));
|
|
131
|
+
}
|
|
132
|
+
const undoCount = reader.u16();
|
|
133
|
+
if (undoCount > EDITABLE_ARTIFACT_INTENT_MAX_UNDO_TARGETS) {
|
|
134
|
+
throw new RangeError("editable artifact undo targets exceed their limit");
|
|
135
|
+
}
|
|
136
|
+
const selectiveUndoOperationIds: string[] = [];
|
|
137
|
+
let previousOperationId = "";
|
|
138
|
+
for (let index = 0; index < undoCount; index += 1) {
|
|
139
|
+
const operationId = reader.string();
|
|
140
|
+
if (operationId <= previousOperationId) {
|
|
141
|
+
throw new TypeError("undo operation ids must be unique and canonically sorted");
|
|
142
|
+
}
|
|
143
|
+
previousOperationId = operationId;
|
|
144
|
+
selectiveUndoOperationIds.push(operationId);
|
|
145
|
+
}
|
|
146
|
+
const commandBytes = reader.byteBlock(EDITABLE_ARTIFACT_COMMAND_MAX_BYTES);
|
|
147
|
+
reader.done();
|
|
148
|
+
return normalizeIntent(
|
|
149
|
+
{
|
|
150
|
+
envelopeVersion: EDITABLE_ARTIFACT_INTENT_VERSION,
|
|
151
|
+
protocolVersion,
|
|
152
|
+
modelSchemaVersion,
|
|
153
|
+
commandProtocolVersion,
|
|
154
|
+
artifactId,
|
|
155
|
+
clientTransactionId,
|
|
156
|
+
replicaId,
|
|
157
|
+
replicaCounter,
|
|
158
|
+
previousLocalTransactionId,
|
|
159
|
+
observedHeadSequence,
|
|
160
|
+
causalBase,
|
|
161
|
+
selectiveUndoOperationIds,
|
|
162
|
+
commandBytes,
|
|
163
|
+
},
|
|
164
|
+
copyCommandBytes,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function hashEditableArtifactMutationIntentBytes(bytes: Uint8Array): string {
|
|
169
|
+
// Decode first so noncanonical or malformed bytes can never acquire a valid
|
|
170
|
+
// application-level request hash merely because SHA-256 accepts any bytes.
|
|
171
|
+
parseEditableArtifactMutationIntent(bytes, false);
|
|
172
|
+
return `sha256:${bytesToHex(sha256(bytes))}`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export function hashEditableArtifactMutationIntent(intent: EditableArtifactMutationIntent): {
|
|
176
|
+
bytes: Uint8Array;
|
|
177
|
+
requestHash: string;
|
|
178
|
+
} {
|
|
179
|
+
const bytes = encodeEditableArtifactMutationIntent(intent);
|
|
180
|
+
return { bytes, requestHash: `sha256:${bytesToHex(sha256(bytes))}` };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function assertEditableArtifactRequestHash(value: string): string {
|
|
184
|
+
if (!REQUEST_HASH.test(value)) {
|
|
185
|
+
throw new TypeError("editable artifact request hash must be canonical sha256 text");
|
|
186
|
+
}
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function normalizeIntent(
|
|
191
|
+
input: EditableArtifactMutationIntent,
|
|
192
|
+
copyCommandBytes = true,
|
|
193
|
+
): EditableArtifactMutationIntent {
|
|
194
|
+
if (!isPlainRecord(input)) throw new TypeError("editable artifact intent must be a plain record");
|
|
195
|
+
if (input.envelopeVersion !== EDITABLE_ARTIFACT_INTENT_VERSION) {
|
|
196
|
+
throw new TypeError("editable artifact intent envelope version must be 1");
|
|
197
|
+
}
|
|
198
|
+
const protocolVersion = positiveU16(input.protocolVersion, "protocolVersion");
|
|
199
|
+
const modelSchemaVersion = positiveU16(input.modelSchemaVersion, "modelSchemaVersion");
|
|
200
|
+
const commandProtocolVersion = positiveU16(
|
|
201
|
+
input.commandProtocolVersion,
|
|
202
|
+
"commandProtocolVersion",
|
|
203
|
+
);
|
|
204
|
+
const artifactId = stableId(input.artifactId, "artifactId");
|
|
205
|
+
const clientTransactionId = portableTransactionId(
|
|
206
|
+
input.clientTransactionId,
|
|
207
|
+
"clientTransactionId",
|
|
208
|
+
);
|
|
209
|
+
const replicaId = replicaIdentity(input.replicaId, "replicaId");
|
|
210
|
+
const replicaCounter = positiveSafeInteger(input.replicaCounter, "replicaCounter");
|
|
211
|
+
const previousLocalTransactionId =
|
|
212
|
+
input.previousLocalTransactionId === null
|
|
213
|
+
? null
|
|
214
|
+
: portableTransactionId(input.previousLocalTransactionId, "previousLocalTransactionId");
|
|
215
|
+
const observedHeadSequence = nonnegativeSafeInteger(
|
|
216
|
+
input.observedHeadSequence,
|
|
217
|
+
"observedHeadSequence",
|
|
218
|
+
);
|
|
219
|
+
if (!Array.isArray(input.causalBase)) throw new TypeError("causalBase must be an array");
|
|
220
|
+
if (input.causalBase.length > EDITABLE_ARTIFACT_INTENT_MAX_CAUSAL_ACTORS) {
|
|
221
|
+
throw new RangeError("editable artifact causal base exceeds its actor limit");
|
|
222
|
+
}
|
|
223
|
+
const causalByReplica = new Map<string, number>();
|
|
224
|
+
for (const entry of input.causalBase) {
|
|
225
|
+
if (!isPlainRecord(entry)) throw new TypeError("causal entries must be plain records");
|
|
226
|
+
const causalReplicaId = replicaIdentity(entry.replicaId, "causal replicaId");
|
|
227
|
+
if (causalByReplica.has(causalReplicaId)) throw new TypeError("duplicate causal replicaId");
|
|
228
|
+
causalByReplica.set(
|
|
229
|
+
causalReplicaId,
|
|
230
|
+
positiveSafeInteger(entry.counter, `causal counter for ${causalReplicaId}`),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const causalBase = [...causalByReplica]
|
|
234
|
+
.sort(([left], [right]) => compareCodeUnits(left, right))
|
|
235
|
+
.map(([causalReplicaId, counter]) => Object.freeze({ replicaId: causalReplicaId, counter }));
|
|
236
|
+
if (!Array.isArray(input.selectiveUndoOperationIds)) {
|
|
237
|
+
throw new TypeError("selectiveUndoOperationIds must be an array");
|
|
238
|
+
}
|
|
239
|
+
if (input.selectiveUndoOperationIds.length > EDITABLE_ARTIFACT_INTENT_MAX_UNDO_TARGETS) {
|
|
240
|
+
throw new RangeError("editable artifact undo targets exceed their limit");
|
|
241
|
+
}
|
|
242
|
+
const undoSet = new Set<string>();
|
|
243
|
+
for (const value of input.selectiveUndoOperationIds) {
|
|
244
|
+
const operationId = stableId(value, "selective undo operation id");
|
|
245
|
+
if (undoSet.has(operationId)) throw new TypeError("duplicate selective undo operation id");
|
|
246
|
+
undoSet.add(operationId);
|
|
247
|
+
}
|
|
248
|
+
const selectiveUndoOperationIds = [...undoSet].sort(compareCodeUnits);
|
|
249
|
+
if (!(input.commandBytes instanceof Uint8Array)) {
|
|
250
|
+
throw new TypeError("commandBytes must be a Uint8Array");
|
|
251
|
+
}
|
|
252
|
+
if (input.commandBytes.byteLength < 1) throw new TypeError("commandBytes must not be empty");
|
|
253
|
+
if (input.commandBytes.byteLength > EDITABLE_ARTIFACT_COMMAND_MAX_BYTES) {
|
|
254
|
+
throw new RangeError("commandBytes exceeds its byte limit");
|
|
255
|
+
}
|
|
256
|
+
return Object.freeze({
|
|
257
|
+
envelopeVersion: EDITABLE_ARTIFACT_INTENT_VERSION,
|
|
258
|
+
protocolVersion,
|
|
259
|
+
modelSchemaVersion,
|
|
260
|
+
commandProtocolVersion,
|
|
261
|
+
artifactId,
|
|
262
|
+
clientTransactionId,
|
|
263
|
+
replicaId,
|
|
264
|
+
replicaCounter,
|
|
265
|
+
previousLocalTransactionId,
|
|
266
|
+
observedHeadSequence,
|
|
267
|
+
causalBase: Object.freeze(causalBase),
|
|
268
|
+
selectiveUndoOperationIds: Object.freeze(selectiveUndoOperationIds),
|
|
269
|
+
commandBytes: copyCommandBytes ? input.commandBytes.slice() : input.commandBytes,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
274
|
+
return (
|
|
275
|
+
typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function stableId(value: unknown, label: string): string {
|
|
280
|
+
if (typeof value !== "string" || !STABLE_ID.test(value) || /^0+$/u.test(value)) {
|
|
281
|
+
throw new TypeError(`${label} must be nonzero fixed-width lowercase hexadecimal text`);
|
|
282
|
+
}
|
|
283
|
+
return value;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function replicaIdentity(value: unknown, label: string): string {
|
|
287
|
+
if (typeof value !== "string" || !REPLICA_ID.test(value) || /^0+$/u.test(value)) {
|
|
288
|
+
throw new TypeError(`${label} must be nonzero 64-bit lowercase hexadecimal text`);
|
|
289
|
+
}
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function portableTransactionId(value: unknown, label: string): string {
|
|
294
|
+
if (typeof value !== "string" || !CLIENT_TRANSACTION_ID.test(value)) {
|
|
295
|
+
throw new TypeError(`${label} must contain 1-200 portable identifier characters`);
|
|
296
|
+
}
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function positiveU16(value: unknown, label: string): number {
|
|
301
|
+
if (!Number.isInteger(value) || (value as number) < 1 || (value as number) > 0xffff) {
|
|
302
|
+
throw new TypeError(`${label} must be a positive 16-bit integer`);
|
|
303
|
+
}
|
|
304
|
+
return value as number;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function positiveSafeInteger(value: unknown, label: string): number {
|
|
308
|
+
if (!Number.isSafeInteger(value) || (value as number) < 1) {
|
|
309
|
+
throw new TypeError(`${label} must be a positive safe integer`);
|
|
310
|
+
}
|
|
311
|
+
return value as number;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function nonnegativeSafeInteger(value: unknown, label: string): number {
|
|
315
|
+
if (!Number.isSafeInteger(value) || (value as number) < 0) {
|
|
316
|
+
throw new TypeError(`${label} must be a nonnegative safe integer`);
|
|
317
|
+
}
|
|
318
|
+
return value as number;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function compareCodeUnits(left: string, right: string): number {
|
|
322
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function equalBytes(left: Uint8Array, right: Uint8Array): boolean {
|
|
326
|
+
return (
|
|
327
|
+
left.byteLength === right.byteLength && left.every((value, index) => value === right[index])
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
class BinaryWriter {
|
|
332
|
+
private buffer = new Uint8Array(1_024);
|
|
333
|
+
private length = 0;
|
|
334
|
+
|
|
335
|
+
constructor(private readonly maximum: number) {}
|
|
336
|
+
|
|
337
|
+
u8(value: number): void {
|
|
338
|
+
this.ensure(1);
|
|
339
|
+
this.buffer[this.length++] = value;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
u16(value: number): void {
|
|
343
|
+
this.ensure(2);
|
|
344
|
+
this.buffer[this.length++] = value & 0xff;
|
|
345
|
+
this.buffer[this.length++] = (value >>> 8) & 0xff;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
u32(value: number): void {
|
|
349
|
+
this.ensure(4);
|
|
350
|
+
for (let offset = 0; offset < 4; offset += 1) {
|
|
351
|
+
this.buffer[this.length++] = Math.floor(value / 2 ** (offset * 8)) & 0xff;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
u64(value: number): void {
|
|
356
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new TypeError("u64 must be safe");
|
|
357
|
+
this.ensure(8);
|
|
358
|
+
let remaining = BigInt(value);
|
|
359
|
+
for (let offset = 0; offset < 8; offset += 1) {
|
|
360
|
+
this.buffer[this.length++] = Number(remaining & 0xffn);
|
|
361
|
+
remaining >>= 8n;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
string(value: string): void {
|
|
366
|
+
const bytes = textEncoder.encode(value);
|
|
367
|
+
if (bytes.byteLength > 0xffff) throw new RangeError("intent string exceeds 65535 bytes");
|
|
368
|
+
this.u16(bytes.byteLength);
|
|
369
|
+
this.bytes(bytes);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
byteBlock(value: Uint8Array): void {
|
|
373
|
+
this.u32(value.byteLength);
|
|
374
|
+
this.bytes(value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
bytes(value: Uint8Array): void {
|
|
378
|
+
this.ensure(value.byteLength);
|
|
379
|
+
this.buffer.set(value, this.length);
|
|
380
|
+
this.length += value.byteLength;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
finish(): Uint8Array {
|
|
384
|
+
return this.buffer.slice(0, this.length);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private ensure(additional: number): void {
|
|
388
|
+
const needed = this.length + additional;
|
|
389
|
+
if (!Number.isSafeInteger(needed) || needed > this.maximum) {
|
|
390
|
+
throw new RangeError("editable artifact intent exceeds its byte limit");
|
|
391
|
+
}
|
|
392
|
+
if (needed <= this.buffer.byteLength) return;
|
|
393
|
+
let size = this.buffer.byteLength;
|
|
394
|
+
while (size < needed) size = Math.min(this.maximum, size * 2);
|
|
395
|
+
const next = new Uint8Array(size);
|
|
396
|
+
next.set(this.buffer.subarray(0, this.length));
|
|
397
|
+
this.buffer = next;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
class BinaryReader {
|
|
402
|
+
private offset = 0;
|
|
403
|
+
|
|
404
|
+
constructor(private readonly input: Uint8Array) {}
|
|
405
|
+
|
|
406
|
+
u8(): number {
|
|
407
|
+
this.require(1);
|
|
408
|
+
return this.input[this.offset++]!;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
u16(): number {
|
|
412
|
+
this.require(2);
|
|
413
|
+
const value = this.input[this.offset]! | (this.input[this.offset + 1]! << 8);
|
|
414
|
+
this.offset += 2;
|
|
415
|
+
return value;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
u32(): number {
|
|
419
|
+
this.require(4);
|
|
420
|
+
const value =
|
|
421
|
+
this.input[this.offset]! +
|
|
422
|
+
this.input[this.offset + 1]! * 2 ** 8 +
|
|
423
|
+
this.input[this.offset + 2]! * 2 ** 16 +
|
|
424
|
+
this.input[this.offset + 3]! * 2 ** 24;
|
|
425
|
+
this.offset += 4;
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
u64(): number {
|
|
430
|
+
this.require(8);
|
|
431
|
+
let value = 0n;
|
|
432
|
+
for (let offset = 0; offset < 8; offset += 1) {
|
|
433
|
+
value |= BigInt(this.input[this.offset + offset]!) << BigInt(offset * 8);
|
|
434
|
+
}
|
|
435
|
+
this.offset += 8;
|
|
436
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) throw new RangeError("u64 exceeds safe integer");
|
|
437
|
+
return Number(value);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
string(): string {
|
|
441
|
+
return textDecoder.decode(this.bytes(this.u16()));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
byteBlock(maximum: number): Uint8Array {
|
|
445
|
+
const length = this.u32();
|
|
446
|
+
if (length < 1) throw new TypeError("commandBytes must not be empty");
|
|
447
|
+
if (length > maximum) throw new RangeError("commandBytes exceeds its byte limit");
|
|
448
|
+
return this.bytes(length);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
bytes(length: number): Uint8Array {
|
|
452
|
+
this.require(length);
|
|
453
|
+
const output = this.input.subarray(this.offset, this.offset + length);
|
|
454
|
+
this.offset += length;
|
|
455
|
+
return output;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
done(): void {
|
|
459
|
+
if (this.offset !== this.input.byteLength) {
|
|
460
|
+
throw new TypeError("editable artifact intent contains trailing bytes");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private require(length: number): void {
|
|
465
|
+
if (
|
|
466
|
+
!Number.isSafeInteger(length) ||
|
|
467
|
+
length < 0 ||
|
|
468
|
+
this.offset + length > this.input.byteLength
|
|
469
|
+
) {
|
|
470
|
+
throw new TypeError("truncated editable artifact intent");
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
package/src/google-drive.ts
CHANGED
|
@@ -13,8 +13,10 @@ export const GOOGLE_DRIVE_METADATA_READONLY_SCOPE =
|
|
|
13
13
|
"https://www.googleapis.com/auth/drive.metadata.readonly" as const;
|
|
14
14
|
export const GOOGLE_DRIVE_READONLY_SCOPE =
|
|
15
15
|
"https://www.googleapis.com/auth/drive.readonly" as const;
|
|
16
|
+
/** Stable serialized role retained for existing connection rows; not product-facing copy. */
|
|
16
17
|
export const GOOGLE_DRIVE_CREDENTIAL_ROLE = "google_drive_metadata" as const;
|
|
17
|
-
export const GOOGLE_DRIVE_CREDENTIAL_LABEL = "Google Drive
|
|
18
|
+
export const GOOGLE_DRIVE_CREDENTIAL_LABEL = "Google Drive read-only source sync" as const;
|
|
19
|
+
export const GOOGLE_DRIVE_LEGACY_CREDENTIAL_LABEL = "Google Drive metadata browser" as const;
|
|
18
20
|
|
|
19
21
|
export const GoogleDriveOAuthCapability = z.enum([
|
|
20
22
|
"picker_file_read",
|
|
@@ -139,6 +141,8 @@ export const GoogleDriveSelectedSource = z.object({
|
|
|
139
141
|
/** @deprecated Missing destinations resolve to the current workspace boundary. */
|
|
140
142
|
targetScope: GoogleDriveTargetScope.optional(),
|
|
141
143
|
syncCadence: GoogleDriveSyncCadence.default("hourly"),
|
|
144
|
+
syncEnabled: z.boolean().default(false),
|
|
145
|
+
configGeneration: z.number().int().positive().default(1),
|
|
142
146
|
readPolicy: GoogleDriveReadPolicy.default("allow"),
|
|
143
147
|
selectedAt: z.string().datetime({ offset: true }),
|
|
144
148
|
});
|
|
@@ -147,7 +151,10 @@ export type GoogleDriveSelectedSource = z.infer<typeof GoogleDriveSelectedSource
|
|
|
147
151
|
export const GoogleDriveConnectionMetadata = z
|
|
148
152
|
.object({
|
|
149
153
|
credentialRole: z.literal(GOOGLE_DRIVE_CREDENTIAL_ROLE),
|
|
150
|
-
credentialLabel: z.
|
|
154
|
+
credentialLabel: z.union([
|
|
155
|
+
z.literal(GOOGLE_DRIVE_CREDENTIAL_LABEL),
|
|
156
|
+
z.literal(GOOGLE_DRIVE_LEGACY_CREDENTIAL_LABEL),
|
|
157
|
+
]),
|
|
151
158
|
googlePermissionId: z.string().min(1).max(256),
|
|
152
159
|
googleEmail: z.string().email().max(320),
|
|
153
160
|
googleDisplayName: z.string().min(1).max(512).nullable(),
|
|
@@ -207,28 +214,74 @@ export const GoogleDriveBrowseResponse = z.object({
|
|
|
207
214
|
});
|
|
208
215
|
export type GoogleDriveBrowseResponse = z.infer<typeof GoogleDriveBrowseResponse>;
|
|
209
216
|
|
|
217
|
+
const GoogleDriveSourceSelection = z
|
|
218
|
+
.array(
|
|
219
|
+
GoogleDriveBrowseItem.pick({
|
|
220
|
+
id: true,
|
|
221
|
+
name: true,
|
|
222
|
+
mimeType: true,
|
|
223
|
+
driveId: true,
|
|
224
|
+
}),
|
|
225
|
+
)
|
|
226
|
+
.max(100)
|
|
227
|
+
.refine((sources) => new Set(sources.map((source) => source.id)).size === sources.length, {
|
|
228
|
+
message: "Google Drive sources must be unique",
|
|
229
|
+
});
|
|
230
|
+
|
|
210
231
|
export const SaveGoogleDriveSourceRequest = z
|
|
211
232
|
.object({
|
|
212
|
-
sources:
|
|
213
|
-
.array(
|
|
214
|
-
GoogleDriveBrowseItem.pick({
|
|
215
|
-
id: true,
|
|
216
|
-
name: true,
|
|
217
|
-
mimeType: true,
|
|
218
|
-
driveId: true,
|
|
219
|
-
}),
|
|
220
|
-
)
|
|
221
|
-
.max(100)
|
|
222
|
-
.refine((sources) => new Set(sources.map((source) => source.id)).size === sources.length, {
|
|
223
|
-
message: "Google Drive sources must be unique",
|
|
224
|
-
}),
|
|
233
|
+
sources: GoogleDriveSourceSelection,
|
|
225
234
|
destination: ConnectorDocumentDestinationSelection.optional(),
|
|
226
235
|
/** @deprecated Legacy requests are accepted but resolve to workspace authority. */
|
|
227
236
|
targetScope: GoogleDriveTargetScope.optional(),
|
|
228
237
|
syncCadence: GoogleDriveSyncCadence.default("hourly"),
|
|
238
|
+
syncEnabled: z.boolean().default(false),
|
|
229
239
|
readPolicy: GoogleDriveReadPolicy.default("allow"),
|
|
230
240
|
})
|
|
231
241
|
.refine((request) => request.destination !== undefined || request.targetScope !== undefined, {
|
|
232
242
|
message: "Google Drive document destination is required",
|
|
233
243
|
});
|
|
234
244
|
export type SaveGoogleDriveSourceRequest = z.infer<typeof SaveGoogleDriveSourceRequest>;
|
|
245
|
+
|
|
246
|
+
export const GoogleDriveKnowledgeSourceItem = z.object({
|
|
247
|
+
id: z.string().min(1).max(512),
|
|
248
|
+
name: z.string().min(1).max(1024),
|
|
249
|
+
mimeType: z.string().min(1).max(256),
|
|
250
|
+
driveId: z.string().min(1).max(512).optional(),
|
|
251
|
+
sourceKind: z.enum(["my_drive", "shared_drive", "folder"]),
|
|
252
|
+
includeDescendants: z.boolean(),
|
|
253
|
+
});
|
|
254
|
+
export type GoogleDriveKnowledgeSourceItem = z.infer<typeof GoogleDriveKnowledgeSourceItem>;
|
|
255
|
+
|
|
256
|
+
export const GoogleDriveKnowledgeSourceDestination = z.object({
|
|
257
|
+
authorityKind: z.enum(["organization", "workspace", "personal"]),
|
|
258
|
+
authorityAccountId: z.string().min(1).max(128),
|
|
259
|
+
authorityWorkspaceId: z.string().min(1).max(128).optional(),
|
|
260
|
+
authoritySubjectId: z.string().min(1).max(512).optional(),
|
|
261
|
+
collectionId: z.string().min(1).max(512).optional(),
|
|
262
|
+
});
|
|
263
|
+
export type GoogleDriveKnowledgeSourceDestination = z.infer<
|
|
264
|
+
typeof GoogleDriveKnowledgeSourceDestination
|
|
265
|
+
>;
|
|
266
|
+
|
|
267
|
+
export const GoogleDriveKnowledgeSourceConfig = z.object({
|
|
268
|
+
sources: z.array(GoogleDriveKnowledgeSourceItem).min(1).max(100),
|
|
269
|
+
destination: GoogleDriveKnowledgeSourceDestination,
|
|
270
|
+
syncCadence: GoogleDriveSyncCadence,
|
|
271
|
+
readPolicy: GoogleDriveReadPolicy,
|
|
272
|
+
});
|
|
273
|
+
export type GoogleDriveKnowledgeSourceConfig = z.infer<typeof GoogleDriveKnowledgeSourceConfig>;
|
|
274
|
+
|
|
275
|
+
export const SaveGoogleDriveIntegrationSourceRequest = z.intersection(
|
|
276
|
+
SaveGoogleDriveSourceRequest,
|
|
277
|
+
z.object({
|
|
278
|
+
sources: GoogleDriveSourceSelection.refine((sources) => sources.length > 0, {
|
|
279
|
+
message: "At least one Google Drive source is required",
|
|
280
|
+
}),
|
|
281
|
+
expectedVersion: z.number().int().positive().optional(),
|
|
282
|
+
idempotencyKey: z.string().uuid(),
|
|
283
|
+
}),
|
|
284
|
+
);
|
|
285
|
+
export type SaveGoogleDriveIntegrationSourceRequest = z.infer<
|
|
286
|
+
typeof SaveGoogleDriveIntegrationSourceRequest
|
|
287
|
+
>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RETAINED_OUTPUT_MAX_PAGE_BYTES, RetainedArtifactReferenceSchema } from "./retained-output";
|
|
3
|
+
|
|
4
|
+
// Codex accepts five references, while the current Gateway GPT Image 2 route
|
|
5
|
+
// accepts four. Keep the provider-neutral tool at the reliable shared limit.
|
|
6
|
+
export const IMAGE_GENERATION_MAX_REFERENCES = 4;
|
|
7
|
+
|
|
8
|
+
const WorkspaceImagePathSchema = z
|
|
9
|
+
.string()
|
|
10
|
+
.max(512)
|
|
11
|
+
// Keep the provider-visible pattern within the portable JSON Schema regex
|
|
12
|
+
// subset. Codex rejects lookaround before inference.
|
|
13
|
+
.regex(/^\/workspace\/.+$/)
|
|
14
|
+
// Path traversal remains an exact runtime validation concern. Zod does not
|
|
15
|
+
// project custom refinements into JSON Schema, so this preserves the guard
|
|
16
|
+
// without sending unsupported regex syntax to model providers.
|
|
17
|
+
.refine((path) => path.split("/").every((segment) => segment !== "." && segment !== ".."), {
|
|
18
|
+
message: "Sandbox image paths cannot contain dot segments",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/** One ordered, workspace-owned input used to guide or edit an image. */
|
|
22
|
+
export const ImageGenerationReferenceSchema = z.discriminatedUnion("kind", [
|
|
23
|
+
z
|
|
24
|
+
.object({
|
|
25
|
+
kind: z.literal("sandbox_path"),
|
|
26
|
+
path: WorkspaceImagePathSchema,
|
|
27
|
+
})
|
|
28
|
+
.strict(),
|
|
29
|
+
z
|
|
30
|
+
.object({
|
|
31
|
+
kind: z.literal("file"),
|
|
32
|
+
fileId: z.string().uuid(),
|
|
33
|
+
})
|
|
34
|
+
.strict(),
|
|
35
|
+
z
|
|
36
|
+
.object({
|
|
37
|
+
kind: z.literal("artifact"),
|
|
38
|
+
artifactId: z.string().uuid(),
|
|
39
|
+
})
|
|
40
|
+
.strict(),
|
|
41
|
+
]);
|
|
42
|
+
export type ImageGenerationReference = z.infer<typeof ImageGenerationReferenceSchema>;
|
|
43
|
+
|
|
44
|
+
/** Provider-neutral minimum shared by native and adapter-backed image tools. */
|
|
45
|
+
export const GenerateImageToolInput = z
|
|
46
|
+
.object({
|
|
47
|
+
prompt: z.string().trim().min(1).max(32_000),
|
|
48
|
+
references: z
|
|
49
|
+
.array(ImageGenerationReferenceSchema)
|
|
50
|
+
.max(IMAGE_GENERATION_MAX_REFERENCES)
|
|
51
|
+
.optional()
|
|
52
|
+
.default([]),
|
|
53
|
+
})
|
|
54
|
+
.strict();
|
|
55
|
+
export type GenerateImageToolInput = z.infer<typeof GenerateImageToolInput>;
|
|
56
|
+
|
|
57
|
+
/** Closed durable result shared by native and adapter-backed image tools. */
|
|
58
|
+
export const GeneratedImageReceiptSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
type: z.literal("generated_image"),
|
|
61
|
+
artifact: RetainedArtifactReferenceSchema,
|
|
62
|
+
sandboxPath: z
|
|
63
|
+
.string()
|
|
64
|
+
.max(256)
|
|
65
|
+
.regex(
|
|
66
|
+
/^\/workspace\/generated-images\/generated-image-[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.(png|jpg|webp)$/,
|
|
67
|
+
),
|
|
68
|
+
})
|
|
69
|
+
.strict()
|
|
70
|
+
.superRefine((value, ctx) => {
|
|
71
|
+
if (value.artifact.kind !== "generated_image") {
|
|
72
|
+
ctx.addIssue({
|
|
73
|
+
code: "custom",
|
|
74
|
+
path: ["artifact", "kind"],
|
|
75
|
+
message: "generated-image receipt requires a generated-image artifact",
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (value.artifact.retrieval.maxRangeBytes !== RETAINED_OUTPUT_MAX_PAGE_BYTES) {
|
|
80
|
+
ctx.addIssue({
|
|
81
|
+
code: "custom",
|
|
82
|
+
path: ["artifact", "retrieval", "maxRangeBytes"],
|
|
83
|
+
message: "generated-image receipt requires the canonical range size",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const extension =
|
|
87
|
+
value.artifact.contentType === "image/png"
|
|
88
|
+
? "png"
|
|
89
|
+
: value.artifact.contentType === "image/jpeg"
|
|
90
|
+
? "jpg"
|
|
91
|
+
: value.artifact.contentType === "image/webp"
|
|
92
|
+
? "webp"
|
|
93
|
+
: null;
|
|
94
|
+
if (
|
|
95
|
+
extension === null ||
|
|
96
|
+
value.sandboxPath !==
|
|
97
|
+
`/workspace/generated-images/generated-image-${value.artifact.artifactId}.${extension}`
|
|
98
|
+
) {
|
|
99
|
+
ctx.addIssue({
|
|
100
|
+
code: "custom",
|
|
101
|
+
path: ["sandboxPath"],
|
|
102
|
+
message: "generated-image sandbox path does not match its artifact",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
export type GeneratedImageReceipt = z.infer<typeof GeneratedImageReceiptSchema>;
|