@gibwork/sdk 0.0.6 → 0.1.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/CHANGELOG.md +7 -0
- package/README.md +85 -1
- package/dist/{chunk-3MLFNEQ5.js → chunk-HJ5D5SOE.js} +310 -37
- package/dist/chunk-HJ5D5SOE.js.map +1 -0
- package/dist/index.cjs +310 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +130 -3
- package/dist/index.d.ts +130 -3
- package/dist/index.js +1 -1
- package/dist/node.cjs +310 -34
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-3MLFNEQ5.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ All notable changes to this package will be documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
- Add cross-creator task discovery with `tasks.listAvailable`.
|
|
8
|
+
- Add paid submission creation, prepare/submit methods, and intent status reads.
|
|
9
|
+
- Preserve idempotency and payment recovery context without automatic retries.
|
|
10
|
+
- Validate submission inputs and intent responses, and expose `Retry-After`.
|
|
11
|
+
- Keep timeouts, cancellation, and ambiguous-submit handling active through response body reads.
|
|
12
|
+
- Add thirteen API signing vectors, participation/recovery tests, and a persisted stage example.
|
|
13
|
+
|
|
7
14
|
- Add the typed Gibwork client with complete External API route coverage.
|
|
8
15
|
- Add high-level task creation, refund, and submission approval workflows.
|
|
9
16
|
- Add injected-wallet and Node private-key signer support.
|
package/README.md
CHANGED
|
@@ -120,16 +120,100 @@ All request methods accept an optional final `{ signal }` argument for
|
|
|
120
120
|
cancellation. Set the default request timeout with `timeoutMs` when creating
|
|
121
121
|
the client.
|
|
122
122
|
|
|
123
|
+
## Discover tasks and submit work
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const available = await gibwork.tasks.listAvailable({ page: 1, limit: 15 });
|
|
127
|
+
|
|
128
|
+
// Persist the key and exact input before sending. Supply your own UUIDv4.
|
|
129
|
+
const input = {
|
|
130
|
+
content: '<p>Completed work: https://example.com/work</p>',
|
|
131
|
+
idempotencyKey: savedIdempotencyKey,
|
|
132
|
+
};
|
|
133
|
+
const intent = await gibwork.submissions.create(taskId, input);
|
|
134
|
+
|
|
135
|
+
if (intent.status === 'submitted') {
|
|
136
|
+
const current = await gibwork.submissions.getIntent(taskId, intent.intentId);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Discovery is free and wallet-authenticated across creators; `tasks.list` lists
|
|
141
|
+
created tasks. Discovery accepts only `page` and `limit` (defaults 1/15, maximum
|
|
142
|
+
limit 100). Results show eligibility requirements, not a guarantee that your
|
|
143
|
+
wallet can submit. `asset.amount` and `minSubmissionAmount` are strings in base
|
|
144
|
+
units; the asset amount is the original reward pool, not remaining funds.
|
|
145
|
+
|
|
146
|
+
Submitting work requires an active platform wallet, eligibility, and currently
|
|
147
|
+
**0.15 USDC**. Network costs are sponsored. Read the returned `fee` for amounts.
|
|
148
|
+
Optional `referral` and `mediaIds` are supported; media must already be uploaded
|
|
149
|
+
and owned by the caller. The SDK preserves submission content/referral exactly
|
|
150
|
+
when signing, including whitespace and HTML.
|
|
151
|
+
|
|
152
|
+
For separate phases use:
|
|
153
|
+
|
|
154
|
+
- `submissions.prepareCreate(taskId, input)`
|
|
155
|
+
- `signPreparedTransaction(prepared.serializedTransaction, signer)`
|
|
156
|
+
- `submissions.submitCreate(taskId, intentId, { paymentAttemptId, signedTransaction })`
|
|
157
|
+
- `submissions.getIntent(taskId, intentId)`
|
|
158
|
+
|
|
159
|
+
Prepare can return an existing intent without a transaction. `submissions.create`
|
|
160
|
+
signs only a pending intent with a transaction and returns the state after one
|
|
161
|
+
submit; it does not poll or retry automatically.
|
|
162
|
+
|
|
163
|
+
| State | Meaning and recovery |
|
|
164
|
+
| -------------------- | -------------------------------------------------------------------------------------- |
|
|
165
|
+
| `pending` | Not submitted. Retry prepare with the original input/key to obtain the transaction. |
|
|
166
|
+
| `submitted` | Unresolved. Read the same intent later. |
|
|
167
|
+
| `fulfilled` | Fee confirmed and submission created. |
|
|
168
|
+
| `failed` / `expired` | Resolve the attempt before explicitly choosing a new key. |
|
|
169
|
+
| `requires_review` | Fee paid; operator attention required. Retain the intent ID/hash and do not pay again. |
|
|
170
|
+
|
|
171
|
+
Only `fulfilled` confirms creation. `taskSubmissionId` is allocated in advance;
|
|
172
|
+
its presence and HTTP 200 alone do not prove success. Intent status does not
|
|
173
|
+
report subsequent creator review/payout, and existing creator submission reads
|
|
174
|
+
have not been extended to participants.
|
|
175
|
+
|
|
176
|
+
After an interrupted prepare, reuse the exact input/key with the same wallet
|
|
177
|
+
and environment. After an uncertain submit, use `getIntent` with the original
|
|
178
|
+
wallet, including after wallet replacement. Each call generates fresh auth.
|
|
179
|
+
The same key still returns the original intent after failure/expiry. A 409 error
|
|
180
|
+
may contain an existing intent ID in its structured body.
|
|
181
|
+
|
|
182
|
+
The upstream wallet limits are discovery 30/minute, prepare 2/minute, submit
|
|
183
|
+
5/minute, and status 60/minute. Respect `GibworkApiError.retryAfter` (seconds or an
|
|
184
|
+
HTTP date) before another request; it is optional. The
|
|
185
|
+
[stage example](examples/create-submission.mjs) persists recovery data before
|
|
186
|
+
payment and uses explicit status reads on later invocations:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
npm run build
|
|
190
|
+
node --env-file=.env examples/create-submission.mjs work.json recovery.json
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`work.json` contains `{ "taskId": "UUID", "input": { "content": "...",
|
|
194
|
+
"idempotencyKey": "UUIDv4" } }`. This example may charge the stage participation
|
|
195
|
+
fee. Once it records an intent, rerunning only reads status. No media upload or
|
|
196
|
+
operator resolution endpoint is provided by this SDK.
|
|
197
|
+
|
|
123
198
|
## Errors
|
|
124
199
|
|
|
125
200
|
API failures throw `GibworkApiError` with `status` and the parsed response
|
|
126
|
-
`body`. Network failures and timeouts use typed SDK errors.
|
|
201
|
+
`body`, plus optional `requestId` and raw `retryAfter`. Network failures and timeouts use typed SDK errors.
|
|
127
202
|
|
|
128
203
|
Transaction submits are never retried automatically. If the network or server
|
|
129
204
|
fails while submitting, the SDK throws `GibworkAmbiguousSubmitError` with safe
|
|
130
205
|
task, submission, and intent identifiers. Do not resubmit the same intent
|
|
131
206
|
blindly.
|
|
132
207
|
|
|
208
|
+
`GibworkValidationError` reports invalid discovery/submission input before a
|
|
209
|
+
request. `GibworkProtocolError` reports an unusable intent response. The
|
|
210
|
+
`submissions.create` convenience method wraps non-ambiguous failures in
|
|
211
|
+
`GibworkSubmissionOperationError`: `context` retains the phase, original
|
|
212
|
+
idempotency key, wallet/environment/API location, and intent identifiers when
|
|
213
|
+
known; `cause` retains the original typed error. Ambiguous payments remain
|
|
214
|
+
`GibworkAmbiguousSubmitError` with enriched context. A wallet rejection or
|
|
215
|
+
cancellation before dispatch is not classified as a broadcast payment.
|
|
216
|
+
|
|
133
217
|
## Development
|
|
134
218
|
|
|
135
219
|
```bash
|
|
@@ -14,19 +14,21 @@ var GibworkConfigurationError = class extends GibworkError {
|
|
|
14
14
|
name = "GibworkConfigurationError";
|
|
15
15
|
};
|
|
16
16
|
var GibworkApiError = class extends GibworkError {
|
|
17
|
-
constructor(status, body, method, path, requestId) {
|
|
17
|
+
constructor(status, body, method, path, requestId, retryAfter) {
|
|
18
18
|
super(`Gibwork API request failed with HTTP ${status}`);
|
|
19
19
|
this.status = status;
|
|
20
20
|
this.body = body;
|
|
21
21
|
this.method = method;
|
|
22
22
|
this.path = path;
|
|
23
23
|
this.requestId = requestId;
|
|
24
|
+
this.retryAfter = retryAfter;
|
|
24
25
|
}
|
|
25
26
|
status;
|
|
26
27
|
body;
|
|
27
28
|
method;
|
|
28
29
|
path;
|
|
29
30
|
requestId;
|
|
31
|
+
retryAfter;
|
|
30
32
|
name = "GibworkApiError";
|
|
31
33
|
};
|
|
32
34
|
var GibworkNetworkError = class extends GibworkError {
|
|
@@ -71,6 +73,51 @@ var GibworkAmbiguousSubmitError = class extends GibworkNetworkError {
|
|
|
71
73
|
context;
|
|
72
74
|
name = "GibworkAmbiguousSubmitError";
|
|
73
75
|
};
|
|
76
|
+
var GibworkValidationError = class extends GibworkError {
|
|
77
|
+
name = "GibworkValidationError";
|
|
78
|
+
};
|
|
79
|
+
var GibworkProtocolError = class extends GibworkError {
|
|
80
|
+
name = "GibworkProtocolError";
|
|
81
|
+
};
|
|
82
|
+
var GibworkSubmissionOperationError = class extends GibworkError {
|
|
83
|
+
constructor(context, options) {
|
|
84
|
+
super(
|
|
85
|
+
"Submission creation interrupted; recover using the original input/key or intent",
|
|
86
|
+
options
|
|
87
|
+
);
|
|
88
|
+
this.context = context;
|
|
89
|
+
}
|
|
90
|
+
context;
|
|
91
|
+
name = "GibworkSubmissionOperationError";
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/auth/validation.ts
|
|
95
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
96
|
+
var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
97
|
+
function isRecord(value) {
|
|
98
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
99
|
+
}
|
|
100
|
+
function assertObjectKeys(value, keys) {
|
|
101
|
+
if (!isRecord(value) || Object.keys(value).some((key) => !keys.includes(key))) {
|
|
102
|
+
throw new GibworkValidationError(
|
|
103
|
+
`Expected an object containing only: ${keys.join(", ")}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function isUuid(value, v4 = false) {
|
|
108
|
+
return typeof value === "string" && (v4 ? UUID_V4 : UUID).test(value);
|
|
109
|
+
}
|
|
110
|
+
function assertUuid(value, name, v4 = false) {
|
|
111
|
+
if (!isUuid(value, v4))
|
|
112
|
+
throw new GibworkValidationError(`${name} must be a UUID${v4 ? "v4" : ""}`);
|
|
113
|
+
}
|
|
114
|
+
function assertText(value, name, min, max) {
|
|
115
|
+
if (typeof value !== "string" || Array.from(value).length < min || Array.from(value).length > max) {
|
|
116
|
+
throw new GibworkValidationError(
|
|
117
|
+
`${name} must contain ${min}\u2013${max} characters`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
74
121
|
var HTML_SANITIZE_OPTIONS = {
|
|
75
122
|
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
|
|
76
123
|
allowedAttributes: {
|
|
@@ -225,6 +272,42 @@ function trimOptional(value) {
|
|
|
225
272
|
const trimmed = value.trim();
|
|
226
273
|
return trimmed === "" ? void 0 : trimmed;
|
|
227
274
|
}
|
|
275
|
+
function normalizeAvailableTasksQuery(query = {}) {
|
|
276
|
+
assertObjectKeys(query, ["page", "limit"]);
|
|
277
|
+
const page = query.page === void 0 ? 1 : query.page;
|
|
278
|
+
const limit = query.limit === void 0 ? 15 : query.limit;
|
|
279
|
+
if (!Number.isSafeInteger(page) || page < 1 || !Number.isSafeInteger(limit) || limit < 1 || limit > 100 || !Number.isSafeInteger((page - 1) * limit)) {
|
|
280
|
+
throw new GibworkValidationError(
|
|
281
|
+
"page must be a positive safe integer, limit must be 1\u2013100, and the offset must be safe"
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
return { page, limit };
|
|
285
|
+
}
|
|
286
|
+
function normalizeCreateSubmission(input, walletAddress) {
|
|
287
|
+
assertObjectKeys(input, [
|
|
288
|
+
"content",
|
|
289
|
+
"referral",
|
|
290
|
+
"mediaIds",
|
|
291
|
+
"idempotencyKey"
|
|
292
|
+
]);
|
|
293
|
+
assertText(input.content, "content", 1, 5e4);
|
|
294
|
+
if (input.referral != null) assertText(input.referral, "referral", 0, 200);
|
|
295
|
+
assertUuid(input.idempotencyKey, "idempotencyKey", true);
|
|
296
|
+
const mediaIds = input.mediaIds ?? [];
|
|
297
|
+
if (!Array.isArray(mediaIds) || mediaIds.length > 10 || new Set(mediaIds).size !== mediaIds.length) {
|
|
298
|
+
throw new GibworkValidationError(
|
|
299
|
+
"mediaIds must contain at most ten distinct UUIDv4 values"
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
for (const id of mediaIds) assertUuid(id, "mediaIds", true);
|
|
303
|
+
return {
|
|
304
|
+
walletAddress,
|
|
305
|
+
content: input.content,
|
|
306
|
+
referral: input.referral ?? null,
|
|
307
|
+
mediaIds: [...mediaIds],
|
|
308
|
+
idempotencyKey: input.idempotencyKey
|
|
309
|
+
};
|
|
310
|
+
}
|
|
228
311
|
async function createWalletAuthHeaders(signer, descriptor, dependencies = {}) {
|
|
229
312
|
const values = {
|
|
230
313
|
walletAddress: signer.publicKey.toBase58(),
|
|
@@ -261,6 +344,30 @@ function buildWalletAuthMessage(descriptor, values) {
|
|
|
261
344
|
`${descriptor.hash[0]}:${descriptor.hash[1]}`
|
|
262
345
|
].join("\n");
|
|
263
346
|
}
|
|
347
|
+
|
|
348
|
+
// src/resources/submissions/submission-intent.ts
|
|
349
|
+
function submissionIntentPath(taskId, intentId) {
|
|
350
|
+
assertUuid(taskId, "taskId");
|
|
351
|
+
if (intentId !== void 0) assertUuid(intentId, "intentId");
|
|
352
|
+
return `/v2/int/tasks/${taskId}/submission-intents${intentId === void 0 ? "" : `/${intentId}`}`;
|
|
353
|
+
}
|
|
354
|
+
var statuses = [
|
|
355
|
+
"pending",
|
|
356
|
+
"submitted",
|
|
357
|
+
"fulfilled",
|
|
358
|
+
"failed",
|
|
359
|
+
"expired",
|
|
360
|
+
"requires_review"
|
|
361
|
+
];
|
|
362
|
+
var nonempty = (value) => typeof value === "string" && value.length > 0;
|
|
363
|
+
var decimal = (value) => typeof value === "string" && /^\d+(\.\d+)?$/.test(value);
|
|
364
|
+
var natural = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
365
|
+
var sameId = (value, expected) => value.toLowerCase() === expected.toLowerCase();
|
|
366
|
+
function validateSubmissionIntent(value, taskId, intentId, paymentAttemptId) {
|
|
367
|
+
if (!isRecord(value) || !isUuid(value.intentId) || !isUuid(value.taskId) || !isUuid(value.taskSubmissionId) || !isUuid(value.paymentAttemptId, true) || !sameId(value.taskId, taskId) || intentId !== void 0 && !sameId(value.intentId, intentId) || paymentAttemptId !== void 0 && !sameId(value.paymentAttemptId, paymentAttemptId) || typeof value.status !== "string" || !statuses.includes(value.status) || !(value.txHash === null || nonempty(value.txHash)) || !nonempty(value.expiresAt) || !Number.isFinite(Date.parse(value.expiresAt)) || !natural(value.lastValidBlockHeight) || value.reviewReason !== void 0 && typeof value.reviewReason !== "string" || value.serializedTransaction !== void 0 && !nonempty(value.serializedTransaction) || !isRecord(value.fee) || !decimal(value.fee.amount) || !decimal(value.fee.totalDebit) || typeof value.fee.amountBaseUnits !== "string" || !/^\d+$/.test(value.fee.amountBaseUnits) || value.fee.symbol !== "USDC" || !natural(value.fee.decimals) || !nonempty(value.fee.mintAddress) || !nonempty(value.fee.destinationAddress)) {
|
|
368
|
+
throw new GibworkProtocolError("Invalid submission intent response");
|
|
369
|
+
}
|
|
370
|
+
}
|
|
264
371
|
async function signPreparedTransaction(serializedTransaction, signer) {
|
|
265
372
|
if (typeof serializedTransaction !== "string" || !serializedTransaction) {
|
|
266
373
|
throw new GibworkConfigurationError(
|
|
@@ -350,6 +457,142 @@ var SubmissionsResource = class {
|
|
|
350
457
|
transport;
|
|
351
458
|
signer;
|
|
352
459
|
comments;
|
|
460
|
+
/** Creates work through a participation fee; only fulfilled confirms creation. */
|
|
461
|
+
async create(taskId, input, options) {
|
|
462
|
+
const path = submissionIntentPath(taskId);
|
|
463
|
+
const { walletAddress, ...snapshot } = normalizeCreateSubmission(
|
|
464
|
+
input,
|
|
465
|
+
this.walletAddress
|
|
466
|
+
);
|
|
467
|
+
let context = {
|
|
468
|
+
taskId,
|
|
469
|
+
idempotencyKey: snapshot.idempotencyKey,
|
|
470
|
+
walletAddress,
|
|
471
|
+
...this.transport.recoveryLocation,
|
|
472
|
+
phase: "prepare"
|
|
473
|
+
};
|
|
474
|
+
try {
|
|
475
|
+
assertNotAborted(options, path);
|
|
476
|
+
const prepared = await this.prepareCreate(taskId, snapshot, options);
|
|
477
|
+
context = {
|
|
478
|
+
...context,
|
|
479
|
+
intentId: prepared.intentId,
|
|
480
|
+
paymentAttemptId: prepared.paymentAttemptId,
|
|
481
|
+
submissionId: prepared.taskSubmissionId,
|
|
482
|
+
phase: "sign"
|
|
483
|
+
};
|
|
484
|
+
if (prepared.status !== "pending") return prepared;
|
|
485
|
+
if (!prepared.serializedTransaction)
|
|
486
|
+
throw new GibworkProtocolError(
|
|
487
|
+
"Pending prepare response is missing its transaction"
|
|
488
|
+
);
|
|
489
|
+
assertNotAborted(options, path);
|
|
490
|
+
const signedTransaction = await signPreparedTransaction(
|
|
491
|
+
prepared.serializedTransaction,
|
|
492
|
+
this.signer
|
|
493
|
+
);
|
|
494
|
+
assertNotAborted(options, path);
|
|
495
|
+
context = { ...context, phase: "submit" };
|
|
496
|
+
return await this.submitCreate(
|
|
497
|
+
taskId,
|
|
498
|
+
prepared.intentId,
|
|
499
|
+
{ paymentAttemptId: prepared.paymentAttemptId, signedTransaction },
|
|
500
|
+
options
|
|
501
|
+
);
|
|
502
|
+
} catch (cause) {
|
|
503
|
+
if (cause instanceof GibworkAmbiguousSubmitError) {
|
|
504
|
+
throw new GibworkAmbiguousSubmitError(
|
|
505
|
+
cause.method,
|
|
506
|
+
cause.path,
|
|
507
|
+
{
|
|
508
|
+
...cause.context,
|
|
509
|
+
...context,
|
|
510
|
+
operation: "create-submission",
|
|
511
|
+
intentId: cause.context.intentId
|
|
512
|
+
},
|
|
513
|
+
{ cause }
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
throw new GibworkSubmissionOperationError(context, { cause });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
/** Reuse the exact input and idempotency key after an interrupted prepare. */
|
|
520
|
+
async prepareCreate(taskId, input, options) {
|
|
521
|
+
const path = submissionIntentPath(taskId);
|
|
522
|
+
const body = normalizeCreateSubmission(input, this.walletAddress);
|
|
523
|
+
assertNotAborted(options, path);
|
|
524
|
+
const headers = await createWalletAuthHeaders(this.signer, {
|
|
525
|
+
operation: "gibwork:create-task-submission-intent",
|
|
526
|
+
method: "POST",
|
|
527
|
+
path,
|
|
528
|
+
resourceFields: [["taskId", taskId]],
|
|
529
|
+
hash: ["payloadHash", sha256Json(body)]
|
|
530
|
+
});
|
|
531
|
+
return this.transport.request({
|
|
532
|
+
method: "POST",
|
|
533
|
+
path,
|
|
534
|
+
headers,
|
|
535
|
+
body,
|
|
536
|
+
...options ? { options } : {},
|
|
537
|
+
validateResponse: (value) => validateSubmissionIntent(value, taskId)
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
/** Never automatically retries. Recover an uncertain payment with getIntent. */
|
|
541
|
+
async submitCreate(taskId, intentId, input, options) {
|
|
542
|
+
const path = `${submissionIntentPath(taskId, intentId)}/submit`;
|
|
543
|
+
assertObjectKeys(input, ["paymentAttemptId", "signedTransaction"]);
|
|
544
|
+
assertUuid(input.paymentAttemptId, "paymentAttemptId", true);
|
|
545
|
+
assertText(input.signedTransaction, "signedTransaction", 1, 1e4);
|
|
546
|
+
const body = {
|
|
547
|
+
paymentAttemptId: input.paymentAttemptId,
|
|
548
|
+
signedTransaction: input.signedTransaction
|
|
549
|
+
};
|
|
550
|
+
return this.transport.request({
|
|
551
|
+
method: "POST",
|
|
552
|
+
path,
|
|
553
|
+
body,
|
|
554
|
+
...options ? { options } : {},
|
|
555
|
+
ambiguousSubmit: {
|
|
556
|
+
operation: "create-submission",
|
|
557
|
+
taskId,
|
|
558
|
+
intentId,
|
|
559
|
+
paymentAttemptId: body.paymentAttemptId,
|
|
560
|
+
walletAddress: this.walletAddress,
|
|
561
|
+
...this.transport.recoveryLocation
|
|
562
|
+
},
|
|
563
|
+
validateResponse: (value) => validateSubmissionIntent(
|
|
564
|
+
value,
|
|
565
|
+
taskId,
|
|
566
|
+
intentId,
|
|
567
|
+
body.paymentAttemptId
|
|
568
|
+
)
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
/** Reads/reconciles creation using the original wallet; does not report review/payout. */
|
|
572
|
+
async getIntent(taskId, intentId, options) {
|
|
573
|
+
const path = submissionIntentPath(taskId, intentId);
|
|
574
|
+
if (options?.signal?.aborted)
|
|
575
|
+
throw new GibworkRequestAbortedError("GET", path, {
|
|
576
|
+
cause: options.signal.reason
|
|
577
|
+
});
|
|
578
|
+
const headers = await createWalletAuthHeaders(this.signer, {
|
|
579
|
+
operation: "gibwork:view-task-submission-intent",
|
|
580
|
+
method: "GET",
|
|
581
|
+
path,
|
|
582
|
+
resourceFields: [
|
|
583
|
+
["taskId", taskId],
|
|
584
|
+
["intentId", intentId]
|
|
585
|
+
],
|
|
586
|
+
hash: ["queryHash", sha256Json({})]
|
|
587
|
+
});
|
|
588
|
+
return this.transport.request({
|
|
589
|
+
method: "GET",
|
|
590
|
+
path,
|
|
591
|
+
headers,
|
|
592
|
+
...options ? { options } : {},
|
|
593
|
+
validateResponse: (value) => validateSubmissionIntent(value, taskId, intentId)
|
|
594
|
+
});
|
|
595
|
+
}
|
|
353
596
|
async list(taskId, query = {}, options) {
|
|
354
597
|
const normalized = normalizeSubmissionPagination(query);
|
|
355
598
|
const path = `/v2/int/tasks/${encodeURIComponent(taskId)}/submissions`;
|
|
@@ -539,6 +782,23 @@ var TasksResource = class {
|
|
|
539
782
|
...options ? { options } : {}
|
|
540
783
|
});
|
|
541
784
|
}
|
|
785
|
+
/** Discover tasks across creators. Eligibility is checked when preparing work. */
|
|
786
|
+
async listAvailable(query = {}, options) {
|
|
787
|
+
const normalized = normalizeAvailableTasksQuery(query);
|
|
788
|
+
const path = "/v2/int/tasks/available";
|
|
789
|
+
const headers = await this.auth({
|
|
790
|
+
operation: "gibwork:view-available-tasks",
|
|
791
|
+
method: "GET",
|
|
792
|
+
path,
|
|
793
|
+
hash: ["queryHash", sha256Json(normalized)]
|
|
794
|
+
});
|
|
795
|
+
return this.transport.request({
|
|
796
|
+
method: "GET",
|
|
797
|
+
path: `${path}?${toQueryString(normalized)}`,
|
|
798
|
+
headers,
|
|
799
|
+
...options ? { options } : {}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
542
802
|
async update(taskId, input, options) {
|
|
543
803
|
const path = `/v2/int/tasks/${encodeURIComponent(taskId)}`;
|
|
544
804
|
const body = normalizeUpdateTask(input, this.walletAddress);
|
|
@@ -684,6 +944,16 @@ var HttpTransport = class {
|
|
|
684
944
|
);
|
|
685
945
|
}
|
|
686
946
|
}
|
|
947
|
+
/** Recovery location without URL credentials. Retains reverse-proxy path prefixes. */
|
|
948
|
+
get recoveryLocation() {
|
|
949
|
+
const url = new URL(this.baseUrl);
|
|
950
|
+
url.username = "";
|
|
951
|
+
url.password = "";
|
|
952
|
+
return {
|
|
953
|
+
apiUrl: url.toString().replace(/\/+$/, ""),
|
|
954
|
+
environment: this.production ? "prod" : "stage"
|
|
955
|
+
};
|
|
956
|
+
}
|
|
687
957
|
async request(request) {
|
|
688
958
|
const controller = new AbortController();
|
|
689
959
|
const callerSignal = request.options?.signal;
|
|
@@ -693,12 +963,6 @@ var HttpTransport = class {
|
|
|
693
963
|
cause: callerSignal.reason
|
|
694
964
|
});
|
|
695
965
|
}
|
|
696
|
-
const abortFromCaller = () => controller.abort(callerSignal?.reason);
|
|
697
|
-
callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
698
|
-
const timeout = setTimeout(() => {
|
|
699
|
-
timedOut = true;
|
|
700
|
-
controller.abort();
|
|
701
|
-
}, this.timeoutMs);
|
|
702
966
|
const headers = {
|
|
703
967
|
accept: "application/json",
|
|
704
968
|
...request.headers,
|
|
@@ -713,13 +977,40 @@ var HttpTransport = class {
|
|
|
713
977
|
headers["content-type"] = "application/json";
|
|
714
978
|
init.body = JSON.stringify(request.body);
|
|
715
979
|
}
|
|
716
|
-
|
|
980
|
+
const abortFromCaller = () => controller.abort(callerSignal?.reason);
|
|
981
|
+
callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
982
|
+
let rejectOnAbort = () => {
|
|
983
|
+
};
|
|
984
|
+
const aborted = new Promise((_, reject) => {
|
|
985
|
+
rejectOnAbort = () => reject(controller.signal.reason);
|
|
986
|
+
controller.signal.addEventListener("abort", rejectOnAbort, {
|
|
987
|
+
once: true
|
|
988
|
+
});
|
|
989
|
+
});
|
|
990
|
+
const timeout = setTimeout(() => {
|
|
991
|
+
timedOut = true;
|
|
992
|
+
controller.abort();
|
|
993
|
+
}, this.timeoutMs);
|
|
717
994
|
try {
|
|
718
|
-
response = await
|
|
719
|
-
`${this.baseUrl}${request.path}`,
|
|
720
|
-
|
|
721
|
-
);
|
|
995
|
+
const response = await Promise.race([
|
|
996
|
+
this.fetchImplementation(`${this.baseUrl}${request.path}`, init),
|
|
997
|
+
aborted
|
|
998
|
+
]);
|
|
999
|
+
const body = await Promise.race([parseResponseBody(response), aborted]);
|
|
1000
|
+
if (!response.ok) {
|
|
1001
|
+
throw new GibworkApiError(
|
|
1002
|
+
response.status,
|
|
1003
|
+
body,
|
|
1004
|
+
request.method,
|
|
1005
|
+
request.path,
|
|
1006
|
+
response.headers.get("x-request-id") ?? void 0,
|
|
1007
|
+
response.headers.get("retry-after") ?? void 0
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
request.validateResponse?.(body);
|
|
1011
|
+
return body;
|
|
722
1012
|
} catch (cause) {
|
|
1013
|
+
if (cause instanceof GibworkApiError && cause.status < 500) throw cause;
|
|
723
1014
|
if (request.ambiguousSubmit) {
|
|
724
1015
|
throw new GibworkAmbiguousSubmitError(
|
|
725
1016
|
request.method,
|
|
@@ -728,6 +1019,8 @@ var HttpTransport = class {
|
|
|
728
1019
|
{ cause }
|
|
729
1020
|
);
|
|
730
1021
|
}
|
|
1022
|
+
if (cause instanceof GibworkApiError || cause instanceof GibworkProtocolError)
|
|
1023
|
+
throw cause;
|
|
731
1024
|
if (timedOut) {
|
|
732
1025
|
throw new GibworkTimeoutError(
|
|
733
1026
|
request.method,
|
|
@@ -742,7 +1035,7 @@ var HttpTransport = class {
|
|
|
742
1035
|
});
|
|
743
1036
|
}
|
|
744
1037
|
throw new GibworkNetworkError(
|
|
745
|
-
"Could not
|
|
1038
|
+
"Could not read the Gibwork API response",
|
|
746
1039
|
request.method,
|
|
747
1040
|
request.path,
|
|
748
1041
|
{ cause }
|
|
@@ -750,28 +1043,8 @@ var HttpTransport = class {
|
|
|
750
1043
|
} finally {
|
|
751
1044
|
clearTimeout(timeout);
|
|
752
1045
|
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
1046
|
+
controller.signal.removeEventListener("abort", rejectOnAbort);
|
|
753
1047
|
}
|
|
754
|
-
const body = await parseResponseBody(response);
|
|
755
|
-
if (!response.ok) {
|
|
756
|
-
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
757
|
-
const apiError = new GibworkApiError(
|
|
758
|
-
response.status,
|
|
759
|
-
body,
|
|
760
|
-
request.method,
|
|
761
|
-
request.path,
|
|
762
|
-
requestId
|
|
763
|
-
);
|
|
764
|
-
if (request.ambiguousSubmit && response.status >= 500) {
|
|
765
|
-
throw new GibworkAmbiguousSubmitError(
|
|
766
|
-
request.method,
|
|
767
|
-
request.path,
|
|
768
|
-
request.ambiguousSubmit,
|
|
769
|
-
{ cause: apiError }
|
|
770
|
-
);
|
|
771
|
-
}
|
|
772
|
-
throw apiError;
|
|
773
|
-
}
|
|
774
|
-
return body;
|
|
775
1048
|
}
|
|
776
1049
|
};
|
|
777
1050
|
function normalizeBaseUrl(value) {
|
|
@@ -830,6 +1103,6 @@ function assertSigner(signer) {
|
|
|
830
1103
|
}
|
|
831
1104
|
}
|
|
832
1105
|
|
|
833
|
-
export { DEFAULT_GIBWORK_API_URL, GibworkAmbiguousSubmitError, GibworkApiError, GibworkClient, GibworkConfigurationError, GibworkError, GibworkNetworkError, GibworkRequestAbortedError, GibworkTimeoutError, signPreparedTransaction };
|
|
834
|
-
//# sourceMappingURL=chunk-
|
|
835
|
-
//# sourceMappingURL=chunk-
|
|
1106
|
+
export { DEFAULT_GIBWORK_API_URL, GibworkAmbiguousSubmitError, GibworkApiError, GibworkClient, GibworkConfigurationError, GibworkError, GibworkNetworkError, GibworkProtocolError, GibworkRequestAbortedError, GibworkSubmissionOperationError, GibworkTimeoutError, GibworkValidationError, signPreparedTransaction };
|
|
1107
|
+
//# sourceMappingURL=chunk-HJ5D5SOE.js.map
|
|
1108
|
+
//# sourceMappingURL=chunk-HJ5D5SOE.js.map
|