@gibwork/sdk 0.0.5 → 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-BNAVP5XZ.js → chunk-HJ5D5SOE.js} +329 -37
- package/dist/chunk-HJ5D5SOE.js.map +1 -0
- package/dist/index.cjs +329 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -3
- package/dist/index.d.ts +159 -3
- package/dist/index.js +1 -1
- package/dist/node.cjs +329 -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-BNAVP5XZ.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`;
|
|
@@ -369,6 +612,25 @@ var SubmissionsResource = class {
|
|
|
369
612
|
...options ? { options } : {}
|
|
370
613
|
});
|
|
371
614
|
}
|
|
615
|
+
async get(taskId, submissionId, options) {
|
|
616
|
+
const path = `/v2/int/tasks/${encodeURIComponent(taskId)}/submissions/${encodeURIComponent(submissionId)}`;
|
|
617
|
+
const headers = await createWalletAuthHeaders(this.signer, {
|
|
618
|
+
operation: "gibwork:view-task-submission",
|
|
619
|
+
method: "GET",
|
|
620
|
+
path,
|
|
621
|
+
resourceFields: [
|
|
622
|
+
["taskId", taskId],
|
|
623
|
+
["taskSubmissionId", submissionId]
|
|
624
|
+
],
|
|
625
|
+
hash: ["queryHash", sha256Json({})]
|
|
626
|
+
});
|
|
627
|
+
return this.transport.request({
|
|
628
|
+
method: "GET",
|
|
629
|
+
path,
|
|
630
|
+
headers,
|
|
631
|
+
...options ? { options } : {}
|
|
632
|
+
});
|
|
633
|
+
}
|
|
372
634
|
async approve(taskId, submissionId, input, options) {
|
|
373
635
|
const prepared = await this.prepareApproval(
|
|
374
636
|
taskId,
|
|
@@ -520,6 +782,23 @@ var TasksResource = class {
|
|
|
520
782
|
...options ? { options } : {}
|
|
521
783
|
});
|
|
522
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
|
+
}
|
|
523
802
|
async update(taskId, input, options) {
|
|
524
803
|
const path = `/v2/int/tasks/${encodeURIComponent(taskId)}`;
|
|
525
804
|
const body = normalizeUpdateTask(input, this.walletAddress);
|
|
@@ -665,6 +944,16 @@ var HttpTransport = class {
|
|
|
665
944
|
);
|
|
666
945
|
}
|
|
667
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
|
+
}
|
|
668
957
|
async request(request) {
|
|
669
958
|
const controller = new AbortController();
|
|
670
959
|
const callerSignal = request.options?.signal;
|
|
@@ -674,12 +963,6 @@ var HttpTransport = class {
|
|
|
674
963
|
cause: callerSignal.reason
|
|
675
964
|
});
|
|
676
965
|
}
|
|
677
|
-
const abortFromCaller = () => controller.abort(callerSignal?.reason);
|
|
678
|
-
callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
679
|
-
const timeout = setTimeout(() => {
|
|
680
|
-
timedOut = true;
|
|
681
|
-
controller.abort();
|
|
682
|
-
}, this.timeoutMs);
|
|
683
966
|
const headers = {
|
|
684
967
|
accept: "application/json",
|
|
685
968
|
...request.headers,
|
|
@@ -694,13 +977,40 @@ var HttpTransport = class {
|
|
|
694
977
|
headers["content-type"] = "application/json";
|
|
695
978
|
init.body = JSON.stringify(request.body);
|
|
696
979
|
}
|
|
697
|
-
|
|
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);
|
|
698
994
|
try {
|
|
699
|
-
response = await
|
|
700
|
-
`${this.baseUrl}${request.path}`,
|
|
701
|
-
|
|
702
|
-
);
|
|
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;
|
|
703
1012
|
} catch (cause) {
|
|
1013
|
+
if (cause instanceof GibworkApiError && cause.status < 500) throw cause;
|
|
704
1014
|
if (request.ambiguousSubmit) {
|
|
705
1015
|
throw new GibworkAmbiguousSubmitError(
|
|
706
1016
|
request.method,
|
|
@@ -709,6 +1019,8 @@ var HttpTransport = class {
|
|
|
709
1019
|
{ cause }
|
|
710
1020
|
);
|
|
711
1021
|
}
|
|
1022
|
+
if (cause instanceof GibworkApiError || cause instanceof GibworkProtocolError)
|
|
1023
|
+
throw cause;
|
|
712
1024
|
if (timedOut) {
|
|
713
1025
|
throw new GibworkTimeoutError(
|
|
714
1026
|
request.method,
|
|
@@ -723,7 +1035,7 @@ var HttpTransport = class {
|
|
|
723
1035
|
});
|
|
724
1036
|
}
|
|
725
1037
|
throw new GibworkNetworkError(
|
|
726
|
-
"Could not
|
|
1038
|
+
"Could not read the Gibwork API response",
|
|
727
1039
|
request.method,
|
|
728
1040
|
request.path,
|
|
729
1041
|
{ cause }
|
|
@@ -731,28 +1043,8 @@ var HttpTransport = class {
|
|
|
731
1043
|
} finally {
|
|
732
1044
|
clearTimeout(timeout);
|
|
733
1045
|
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
1046
|
+
controller.signal.removeEventListener("abort", rejectOnAbort);
|
|
734
1047
|
}
|
|
735
|
-
const body = await parseResponseBody(response);
|
|
736
|
-
if (!response.ok) {
|
|
737
|
-
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
738
|
-
const apiError = new GibworkApiError(
|
|
739
|
-
response.status,
|
|
740
|
-
body,
|
|
741
|
-
request.method,
|
|
742
|
-
request.path,
|
|
743
|
-
requestId
|
|
744
|
-
);
|
|
745
|
-
if (request.ambiguousSubmit && response.status >= 500) {
|
|
746
|
-
throw new GibworkAmbiguousSubmitError(
|
|
747
|
-
request.method,
|
|
748
|
-
request.path,
|
|
749
|
-
request.ambiguousSubmit,
|
|
750
|
-
{ cause: apiError }
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
throw apiError;
|
|
754
|
-
}
|
|
755
|
-
return body;
|
|
756
1048
|
}
|
|
757
1049
|
};
|
|
758
1050
|
function normalizeBaseUrl(value) {
|
|
@@ -811,6 +1103,6 @@ function assertSigner(signer) {
|
|
|
811
1103
|
}
|
|
812
1104
|
}
|
|
813
1105
|
|
|
814
|
-
export { DEFAULT_GIBWORK_API_URL, GibworkAmbiguousSubmitError, GibworkApiError, GibworkClient, GibworkConfigurationError, GibworkError, GibworkNetworkError, GibworkRequestAbortedError, GibworkTimeoutError, signPreparedTransaction };
|
|
815
|
-
//# sourceMappingURL=chunk-
|
|
816
|
-
//# 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
|