@volter/world-core 3.0.4 → 3.0.5

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.
@@ -296,6 +296,21 @@ export type ScreenDecl = {
296
296
  /** the vendor's documentation of the round trip or the screen */
297
297
  source: string;
298
298
  };
299
+ /** A protocol hook's arguments: the root's executor (it applies the sealed credential; `issued` carries one the vendor
300
+ * issued instead), the group and its first entry's recorded input, the perform's context, the derived perform of an
301
+ * input (`send`: the recorded request, or one the hook changed), the stored id the World's id of a type resolves to,
302
+ * the surface's base path, and the World's blobs of this twin. */
303
+ export type PerformHookArgs = {
304
+ execute: import('./remote-execute.js').RemoteExecute;
305
+ group: import('./actions.js').TwinAction[];
306
+ input: Record<string, unknown>;
307
+ ctx: import('./head.js').PerformContext;
308
+ send: (input: Record<string, unknown>) => Promise<import('./head.js').PushOutcome>;
309
+ resolve: (type: string, localId: string) => string;
310
+ basePath: string;
311
+ blob: (key: string) => Promise<Uint8Array | null>;
312
+ };
313
+ export type PerformHook = (args: PerformHookArgs) => Promise<import('./head.js').PushOutcome>;
299
314
  export type DerivedManifest = {
300
315
  /** The pack's descriptor, as data (docs/contributing/architecture.md, "The descriptor"), every field but `vendor`, which
301
316
  * is the manifest's: the pack registers `packOf(manifest)`, so its index is a fixed file. A lane has none. */
@@ -384,6 +399,14 @@ export type DerivedManifest = {
384
399
  vendorBacked?: {
385
400
  none: string;
386
401
  };
402
+ /** the resource the vendor's paths name the account by (Cloudflare's `accounts/{account_id}`): with a root, the
403
+ * World's account is the one account the root's credential reaches, which refresh observes ("The account a root
404
+ * is", architecture) */
405
+ account?: string;
406
+ /** a vendor protocol one recorded request cannot express, by the operation that ends it: a session whose answer
407
+ * issues the credential its next calls carry (Cloudflare's assets upload), performed by the hook in place of the
408
+ * derived request, which it composes (`send`) ("Protocols a request cannot express", architecture) */
409
+ performs?: Record<string, PerformHook>;
387
410
  /** `withParam`: the error names the path parameter that held the unknown id */
388
411
  notFound: {
389
412
  status: number;
@@ -77,7 +77,9 @@ function resolvedDeep(value, resolve) {
77
77
  const o = object(value);
78
78
  return o ? Object.fromEntries(Object.entries(o).map(([k, v]) => [k, resolvedDeep(v, resolve)])) : value;
79
79
  }
80
- /** A multipart body: the recorded fields, then each recorded file part read back from the World's blob store. */
80
+ /** A multipart body: the recorded fields, then each recorded file part read back from the World's blob store. An
81
+ * operation the vendor takes as multipart is sent so with no file part too (a Workers upload of assets alone carries
82
+ * only its `metadata` field). */
81
83
  async function multipart(body, files, ctx) {
82
84
  const boundary = `----volter${hashFieldValue({ body, files }).slice(0, 24)}`;
83
85
  const chunks = [];
@@ -123,9 +125,9 @@ function unitOf(units, input) {
123
125
  ?? (input.graphql ? units[0] : undefined);
124
126
  }
125
127
  function performOf(units) {
126
- return async (execute, group, ctx) => {
128
+ // the request a group's first entry recorded (or one a protocol hook changed), sent to the vendor
129
+ const derived = async (execute, group, ctx, input) => {
127
130
  const first = group[0];
128
- const input = (first.input ?? {});
129
131
  const unit = unitOf(units, input);
130
132
  if (!unit)
131
133
  throw new RefusedWriteError('vendor', `the write records no operation of the vendor's surface (${String(input.operationId ?? 'none')})`, first.id);
@@ -183,7 +185,7 @@ function performOf(units) {
183
185
  const asCame = object(input.body);
184
186
  const raw = asCame && typeof asCame.$text === 'string' ? { body: asCame.$text } : asCame && typeof asCame.$base64 === 'string' ? { body: new Uint8Array(Buffer.from(asCame.$base64, 'base64')) } : undefined;
185
187
  const sent = raw ? { ...raw, ...(typeof input.contentType === 'string' ? { type: input.contentType } : {}) }
186
- : files.length ? await multipart(body, files, ctx) : op ? encode(op, body) : { body: JSON.stringify(body), type: 'application/json' };
188
+ : files.length || op?.bodyEncoding === 'multipart' ? await multipart(body, files, ctx) : op ? encode(op, body) : { body: JSON.stringify(body), type: 'application/json' };
187
189
  const headers = { ...(object(input.headers) ?? {}), ...(sent.type ? { 'content-type': sent.type } : {}) };
188
190
  // a retried deploy makes nothing twice, and two Worlds deploying into one account never collide
189
191
  if (m.idempotency)
@@ -228,6 +230,22 @@ function performOf(units) {
228
230
  }
229
231
  return { externalId, actionId: primary.id, data: obj, ...(also.length ? { also } : {}) };
230
232
  };
233
+ return async (execute, group, ctx) => {
234
+ const input = (group[0].input ?? {});
235
+ const unit = unitOf(units, input);
236
+ // a protocol one request cannot express is the pack's hook, which composes the derived perform ("Protocols a
237
+ // request cannot express")
238
+ const hook = unit && typeof input.operationId === 'string' ? unit.manifest.performs?.[input.operationId] : undefined;
239
+ if (!hook || !unit)
240
+ return derived(execute, group, ctx, input);
241
+ return hook({
242
+ execute, group, input, ctx,
243
+ send: (changed) => derived(execute, group, ctx, changed),
244
+ resolve: (type, localId) => ctx.resolve(type, localId),
245
+ basePath: unit.surface.basePath ?? '',
246
+ blob: (key) => readResourceBlob(ctx.service ?? '', key, ctx.root),
247
+ });
248
+ };
231
249
  }
232
250
  /** Path parameters that name a subject by a field rather than its id, sent as the vendor's value of that field, read
233
251
  * from the adopted landed copy ("Perform", step 1): a parent found by `parent.where` (a repository addressed as
@@ -400,6 +418,21 @@ function adopt(service, root, units, observed) {
400
418
  list.push({ id: e.subject.id, fields: held.fields });
401
419
  pending.set(e.subject.type, list);
402
420
  }
421
+ // the account a root is ("The account a root is"): the root's credential reaches one account of the type the pack's
422
+ // paths name it by; observed alone, it is the World's own account (made by the World's door, so no deploy settled it)
423
+ for (const u of units) {
424
+ if (!u.manifest.account)
425
+ continue;
426
+ const type = storedType(u.manifest, u.manifest.account);
427
+ const seen = observed.filter((o) => o.type === type);
428
+ if (seen.length !== 1 || tree.has(`${type}:${seen[0].id}`))
429
+ continue;
430
+ const local = readTree(service, root).find((r) => r.type === type && r.deleted !== true && !aliases.has(`${type}:${String(r.id)}`) && String(r.id) !== seen[0].id);
431
+ if (local) {
432
+ seen[0].adopts = String(local.id);
433
+ aliases.set(`${type}:${String(local.id)}`, seen[0].id);
434
+ }
435
+ }
403
436
  if (!pending.size)
404
437
  return;
405
438
  const declOf = (type) => {
@@ -148,7 +148,7 @@ function budgeted(vendor, execute, token) {
148
148
  }
149
149
  /** The call made as the root's credential is applied by the strategy (header replacement when none). */
150
150
  function direct(origin, credential, auth, vendorHosts) {
151
- return async ({ method, path, headers, body, responseType, presigned }) => {
151
+ return async ({ method, path, headers, body, responseType, presigned, issued }) => {
152
152
  // A PRESIGNED UPLOAD URL the vendor returned: its own signature is its authorization, so the
153
153
  // sealed credential never goes with it, whatever host it names. A host other than the root's
154
154
  // passes the same validation the root does; the root's own origin (a twin standing in for the
@@ -205,8 +205,12 @@ function direct(origin, credential, auth, vendorHosts) {
205
205
  throw new Error('remote execute: path escaped the validated origin');
206
206
  }
207
207
  const outbound = new Headers(headers ?? {});
208
- for (const [name, value] of Object.entries(credential.headers))
209
- outbound.set(name, value);
208
+ // a credential the vendor issued in this perform is the request's authorization; the sealed one stays home
209
+ if (issued !== undefined)
210
+ outbound.set('authorization', issued);
211
+ else
212
+ for (const [name, value] of Object.entries(credential.headers))
213
+ outbound.set(name, value);
210
214
  // ── THE STRATEGIES BEYOND HEADER REPLACEMENT ──────────────────────────────────────────────
211
215
  // Applied AFTER the anchoring check above, so nothing here can move the request off the
212
216
  // validated origin: `searchParams.set` only ever touches the query, and a header is a header.
@@ -214,7 +218,7 @@ function direct(origin, credential, auth, vendorHosts) {
214
218
  // FAIL CLOSED. A strategy with no secret must never send a request that merely LOOKS
215
219
  // authenticated — that silence is the whole defect this exists to remove. The refusals name the
216
220
  // strategy and the parameter, never the secret.
217
- if (auth !== undefined) {
221
+ if (auth !== undefined && issued === undefined) {
218
222
  const secret = credential.secret;
219
223
  if (typeof secret !== 'string' || secret === '') {
220
224
  throw new Error(`remote execute: the ${auth.in} credential strategy needs \`secret\` on the sealed credential, and it is absent`);
@@ -379,7 +383,7 @@ function exchangeExecute(origin, sealed, auth, vendorHosts, custody) {
379
383
  return anchored({ ...request, headers });
380
384
  };
381
385
  return async (request) => {
382
- if (request.presigned)
386
+ if (request.presigned || request.issued !== undefined)
383
387
  return anchored(request);
384
388
  const held = current();
385
389
  const first = await call(request, held);
@@ -14,7 +14,7 @@ export declare const packOf: (manifest: {
14
14
  }>) => PackDescriptor;
15
15
  /** The pack registered, so the World finds it. */
16
16
  export declare const registerPack: (pack: PackDescriptor) => PackDescriptor;
17
- export type { Actor, CoreScope, DerivedManifest, ErrorSpec, LaneRoute, LanesDecl, VendorManifest, FieldRule, ResourceDecl, ScreenDecl, SeedCall, StateField, Transition } from './derived-core.js';
17
+ export type { Actor, CoreScope, DerivedManifest, PerformHook, PerformHookArgs, ErrorSpec, LaneRoute, LanesDecl, VendorManifest, FieldRule, ResourceDecl, ScreenDecl, SeedCall, StateField, Transition } from './derived-core.js';
18
18
  export type { ApplicationAnswer, EndpointsDecl, EventRender, EventScheme, EventsDecl, EventTransport, EventValues, EventWrite } from './events.js';
19
19
  export { verifyEvent } from './events.js';
20
20
  export { deriveStateSystem, deriveVendorStateSystem } from './derived-real.js';
@@ -12,6 +12,10 @@ export type RemoteExecuteRequest = {
12
12
  * the API, and the request goes WITHOUT the sealed credential. An upload the vendor authorizes
13
13
  * with the API token (LinkedIn's images) is not presigned and cannot use this. */
14
14
  presigned?: true;
15
+ /** An Authorization the vendor ISSUED earlier in the same perform (Cloudflare's assets upload session answers a JWT
16
+ * that its upload calls carry instead of the API token), on the root's own origin: it is sent as the request's
17
+ * Authorization and the sealed credential does not go with it. */
18
+ issued?: string;
15
19
  };
16
20
  export type RemoteExecuteResponse = {
17
21
  status: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-core",
3
- "version": "3.0.4",
3
+ "version": "3.0.5",
4
4
  "description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
5
5
  "keywords": [
6
6
  "twin",
@@ -239,6 +239,22 @@ export type ScreenDecl = {
239
239
  source: string;
240
240
  };
241
241
 
242
+ /** A protocol hook's arguments: the root's executor (it applies the sealed credential; `issued` carries one the vendor
243
+ * issued instead), the group and its first entry's recorded input, the perform's context, the derived perform of an
244
+ * input (`send`: the recorded request, or one the hook changed), the stored id the World's id of a type resolves to,
245
+ * the surface's base path, and the World's blobs of this twin. */
246
+ export type PerformHookArgs = {
247
+ execute: import('./remote-execute.ts').RemoteExecute;
248
+ group: import('./actions.ts').TwinAction[];
249
+ input: Record<string, unknown>;
250
+ ctx: import('./head.ts').PerformContext;
251
+ send: (input: Record<string, unknown>) => Promise<import('./head.ts').PushOutcome>;
252
+ resolve: (type: string, localId: string) => string;
253
+ basePath: string;
254
+ blob: (key: string) => Promise<Uint8Array | null>;
255
+ };
256
+ export type PerformHook = (args: PerformHookArgs) => Promise<import('./head.ts').PushOutcome>;
257
+
242
258
  export type DerivedManifest = {
243
259
  /** The pack's descriptor, as data (docs/contributing/architecture.md, "The descriptor"), every field but `vendor`, which
244
260
  * is the manifest's: the pack registers `packOf(manifest)`, so its index is a fixed file. A lane has none. */
@@ -293,6 +309,14 @@ export type DerivedManifest = {
293
309
  /** a pack whose wire has no derived perform (a socket, a line protocol, a managed database): binding a root is refused
294
310
  * with this reason */
295
311
  vendorBacked?: { none: string };
312
+ /** the resource the vendor's paths name the account by (Cloudflare's `accounts/{account_id}`): with a root, the
313
+ * World's account is the one account the root's credential reaches, which refresh observes ("The account a root
314
+ * is", architecture) */
315
+ account?: string;
316
+ /** a vendor protocol one recorded request cannot express, by the operation that ends it: a session whose answer
317
+ * issues the credential its next calls carry (Cloudflare's assets upload), performed by the hook in place of the
318
+ * derived request, which it composes (`send`) ("Protocols a request cannot express", architecture) */
319
+ performs?: Record<string, PerformHook>;
296
320
  /** `withParam`: the error names the path parameter that held the unknown id */
297
321
  notFound: { status: number; message: string; code?: string; kind?: string; withParam?: boolean };
298
322
  /** the list envelope (placeholders `{data}`, `{has_more}`, `{url}`, `{first_id}`, `{last_id}`),
@@ -70,7 +70,9 @@ function resolvedDeep(value: unknown, resolve: (v: string) => string): unknown {
70
70
  return o ? Object.fromEntries(Object.entries(o).map(([k, v]) => [k, resolvedDeep(v, resolve)])) : value;
71
71
  }
72
72
 
73
- /** A multipart body: the recorded fields, then each recorded file part read back from the World's blob store. */
73
+ /** A multipart body: the recorded fields, then each recorded file part read back from the World's blob store. An
74
+ * operation the vendor takes as multipart is sent so with no file part too (a Workers upload of assets alone carries
75
+ * only its `metadata` field). */
74
76
  async function multipart(body: unknown, files: Row[], ctx: PerformContext): Promise<{ body: Uint8Array; type: string }> {
75
77
  const boundary = `----volter${hashFieldValue({ body, files }).slice(0, 24)}`;
76
78
  const chunks: Uint8Array[] = [];
@@ -110,9 +112,9 @@ function unitOf(units: Unit[], input: Row): Unit | undefined {
110
112
  }
111
113
 
112
114
  function performOf(units: Unit[]): PerformAction {
113
- return async (execute: RemoteExecute, group: TwinAction[], ctx: PerformContext): Promise<PushOutcome> => {
115
+ // the request a group's first entry recorded (or one a protocol hook changed), sent to the vendor
116
+ const derived = async (execute: RemoteExecute, group: TwinAction[], ctx: PerformContext, input: Row): Promise<PushOutcome> => {
114
117
  const first = group[0]!;
115
- const input = (first.input ?? {}) as Row;
116
118
  const unit = unitOf(units, input);
117
119
  if (!unit) throw new RefusedWriteError('vendor', `the write records no operation of the vendor's surface (${String(input.operationId ?? 'none')})`, first.id);
118
120
  const { manifest: m, surface } = unit;
@@ -153,7 +155,7 @@ function performOf(units: Unit[]): PerformAction {
153
155
  const asCame = object(input.body);
154
156
  const raw = asCame && typeof asCame.$text === 'string' ? { body: asCame.$text as string } : asCame && typeof asCame.$base64 === 'string' ? { body: new Uint8Array(Buffer.from(asCame.$base64 as string, 'base64')) } : undefined;
155
157
  const sent: { body?: string | Uint8Array; type?: string } = raw ? { ...raw, ...(typeof input.contentType === 'string' ? { type: input.contentType } : {}) }
156
- : files.length ? await multipart(body, files, ctx) : op ? encode(op, body) : { body: JSON.stringify(body), type: 'application/json' };
158
+ : files.length || op?.bodyEncoding === 'multipart' ? await multipart(body, files, ctx) : op ? encode(op, body) : { body: JSON.stringify(body), type: 'application/json' };
157
159
  const headers: Record<string, string> = { ...((object(input.headers) ?? {}) as Record<string, string>), ...(sent.type ? { 'content-type': sent.type } : {}) };
158
160
  // a retried deploy makes nothing twice, and two Worlds deploying into one account never collide
159
161
  if (m.idempotency) headers[m.idempotency.header] = hashFieldValue({ credential: ctx.credential ?? '', entry: first.id });
@@ -193,6 +195,21 @@ function performOf(units: Unit[]): PerformAction {
193
195
  }
194
196
  return { externalId, actionId: primary.id, data: obj, ...(also.length ? { also } : {}) };
195
197
  };
198
+ return async (execute: RemoteExecute, group: TwinAction[], ctx: PerformContext): Promise<PushOutcome> => {
199
+ const input = (group[0]!.input ?? {}) as Row;
200
+ const unit = unitOf(units, input);
201
+ // a protocol one request cannot express is the pack's hook, which composes the derived perform ("Protocols a
202
+ // request cannot express")
203
+ const hook = unit && typeof input.operationId === 'string' ? unit.manifest.performs?.[input.operationId] : undefined;
204
+ if (!hook || !unit) return derived(execute, group, ctx, input);
205
+ return hook({
206
+ execute, group, input, ctx,
207
+ send: (changed) => derived(execute, group, ctx, changed),
208
+ resolve: (type, localId) => ctx.resolve(type, localId),
209
+ basePath: unit.surface.basePath ?? '',
210
+ blob: (key) => readResourceBlob(ctx.service ?? '', key, ctx.root),
211
+ });
212
+ };
196
213
  }
197
214
 
198
215
  /** Path parameters that name a subject by a field rather than its id, sent as the vendor's value of that field, read
@@ -336,6 +353,16 @@ function adopt(service: string, root: string | undefined, units: Unit[], observe
336
353
  if (!list.some((p) => p.id === e.subject.id)) list.push({ id: e.subject.id, fields: held.fields });
337
354
  pending.set(e.subject.type, list);
338
355
  }
356
+ // the account a root is ("The account a root is"): the root's credential reaches one account of the type the pack's
357
+ // paths name it by; observed alone, it is the World's own account (made by the World's door, so no deploy settled it)
358
+ for (const u of units) {
359
+ if (!u.manifest.account) continue;
360
+ const type = storedType(u.manifest, u.manifest.account);
361
+ const seen = observed.filter((o) => o.type === type);
362
+ if (seen.length !== 1 || tree.has(`${type}:${seen[0]!.id}`)) continue;
363
+ const local = (readTree(service, root) as Row[]).find((r) => r.type === type && r.deleted !== true && !aliases.has(`${type}:${String(r.id)}`) && String(r.id) !== seen[0]!.id);
364
+ if (local) { seen[0]!.adopts = String(local.id); aliases.set(`${type}:${String(local.id)}`, seen[0]!.id); }
365
+ }
339
366
  if (!pending.size) return;
340
367
  const declOf = (type: string): { m: DerivedManifest; decl: ResourceDecl } | undefined => {
341
368
  for (const u of units) { const hit = Object.entries(u.manifest.resources).find(([r]) => storedType(u.manifest, r) === type); if (hit) return { m: u.manifest, decl: hit[1] }; }
package/src/executor.ts CHANGED
@@ -243,7 +243,7 @@ function budgeted(vendor: string, execute: RemoteExecute, token: string): Remote
243
243
 
244
244
  /** The call made as the root's credential is applied by the strategy (header replacement when none). */
245
245
  function direct(origin: URL, credential: CredentialPayload, auth?: Exclude<TwinAuthStrategy, { in: 'exchange' }>, vendorHosts?: readonly HostRule[]): RemoteExecute {
246
- return async ({ method, path, headers, body, responseType, presigned }) => {
246
+ return async ({ method, path, headers, body, responseType, presigned, issued }) => {
247
247
  // A PRESIGNED UPLOAD URL the vendor returned: its own signature is its authorization, so the
248
248
  // sealed credential never goes with it, whatever host it names. A host other than the root's
249
249
  // passes the same validation the root does; the root's own origin (a twin standing in for the
@@ -288,7 +288,9 @@ function direct(origin: URL, credential: CredentialPayload, auth?: Exclude<TwinA
288
288
  if (target.origin !== origin.origin || !target.pathname.startsWith(origin.pathname.replace(/\/+$/, ''))) throw new Error('remote execute: path escaped the validated origin');
289
289
  }
290
290
  const outbound = new Headers(headers ?? {});
291
- for (const [name, value] of Object.entries(credential.headers)) outbound.set(name, value);
291
+ // a credential the vendor issued in this perform is the request's authorization; the sealed one stays home
292
+ if (issued !== undefined) outbound.set('authorization', issued);
293
+ else for (const [name, value] of Object.entries(credential.headers)) outbound.set(name, value);
292
294
 
293
295
  // ── THE STRATEGIES BEYOND HEADER REPLACEMENT ──────────────────────────────────────────────
294
296
  // Applied AFTER the anchoring check above, so nothing here can move the request off the
@@ -297,7 +299,7 @@ function direct(origin: URL, credential: CredentialPayload, auth?: Exclude<TwinA
297
299
  // FAIL CLOSED. A strategy with no secret must never send a request that merely LOOKS
298
300
  // authenticated — that silence is the whole defect this exists to remove. The refusals name the
299
301
  // strategy and the parameter, never the secret.
300
- if (auth !== undefined) {
302
+ if (auth !== undefined && issued === undefined) {
301
303
  const secret = credential.secret;
302
304
  if (typeof secret !== 'string' || secret === '') {
303
305
  throw new Error(`remote execute: the ${auth.in} credential strategy needs \`secret\` on the sealed credential, and it is absent`);
@@ -437,7 +439,7 @@ function exchangeExecute(origin: URL, sealed: CredentialPayload, auth: Extract<T
437
439
  return anchored({ ...request, headers });
438
440
  };
439
441
  return async (request) => {
440
- if (request.presigned) return anchored(request);
442
+ if (request.presigned || request.issued !== undefined) return anchored(request);
441
443
  const held = current();
442
444
  const first = await call(request, held);
443
445
  if (!retryOn.includes(first.status)) return first;
package/src/index.ts CHANGED
@@ -21,7 +21,7 @@ export const packOf = (
21
21
  export const registerPack = (pack: PackDescriptor): PackDescriptor => registerAny(pack);
22
22
 
23
23
  // ── the manifest ───────────────────────────────────────────────────────────────────────────────
24
- export type { Actor, CoreScope, DerivedManifest, ErrorSpec, LaneRoute, LanesDecl, VendorManifest, FieldRule, ResourceDecl, ScreenDecl, SeedCall, StateField, Transition } from './derived-core.ts';
24
+ export type { Actor, CoreScope, DerivedManifest, PerformHook, PerformHookArgs, ErrorSpec, LaneRoute, LanesDecl, VendorManifest, FieldRule, ResourceDecl, ScreenDecl, SeedCall, StateField, Transition } from './derived-core.ts';
25
25
  export type { ApplicationAnswer, EndpointsDecl, EventRender, EventScheme, EventsDecl, EventTransport, EventValues, EventWrite } from './events.ts';
26
26
  export { verifyEvent } from './events.ts';
27
27
  export { deriveStateSystem, deriveVendorStateSystem } from './derived-real.ts';
@@ -16,6 +16,10 @@ export type RemoteExecuteRequest = {
16
16
  * the API, and the request goes WITHOUT the sealed credential. An upload the vendor authorizes
17
17
  * with the API token (LinkedIn's images) is not presigned and cannot use this. */
18
18
  presigned?: true;
19
+ /** An Authorization the vendor ISSUED earlier in the same perform (Cloudflare's assets upload session answers a JWT
20
+ * that its upload calls carry instead of the API token), on the root's own origin: it is sent as the request's
21
+ * Authorization and the sealed credential does not go with it. */
22
+ issued?: string;
19
23
  };
20
24
  export type RemoteExecuteResponse = {
21
25
  status: number;