@putdotio/sdk 9.1.8 → 9.3.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/README.md +69 -38
- package/dist/forms-DCO3Ckbx.js +254 -0
- package/dist/forms-DCO3Ckbx.js.map +1 -0
- package/dist/index-C4NwsF9x.d.ts +7388 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +584 -350
- package/dist/index.js.map +1 -1
- package/dist/utilities.d.ts +2 -2
- package/dist/utilities.js +12 -12
- package/dist/utilities.js.map +1 -1
- package/package.json +27 -14
- package/dist/forms-BoZMwEUj.js +0 -182
- package/dist/forms-BoZMwEUj.js.map +0 -1
- package/dist/index-Irv7Wz_0.d.ts +0 -7473
package/README.md
CHANGED
|
@@ -29,11 +29,14 @@ npm install @putdotio/sdk
|
|
|
29
29
|
|
|
30
30
|
## Quick Start
|
|
31
31
|
|
|
32
|
+
`userAccessToken` in these examples is an already-issued user token from your app or auth flow.
|
|
33
|
+
The SDK itself can be constructed without a token.
|
|
34
|
+
|
|
32
35
|
```ts
|
|
33
36
|
import { createPutioSdkPromiseClient } from "@putdotio/sdk";
|
|
34
37
|
|
|
35
38
|
const sdk = createPutioSdkPromiseClient({
|
|
36
|
-
accessToken:
|
|
39
|
+
accessToken: userAccessToken,
|
|
37
40
|
});
|
|
38
41
|
|
|
39
42
|
const account = await sdk.account.getInfo({
|
|
@@ -46,7 +49,13 @@ The SDK can also be created without a default token:
|
|
|
46
49
|
```ts
|
|
47
50
|
const sdk = createPutioSdkPromiseClient();
|
|
48
51
|
|
|
49
|
-
const validation = await sdk.auth.validateToken(
|
|
52
|
+
const validation = await sdk.auth.validateToken(tokenToCheck);
|
|
53
|
+
const login = await sdk.auth.login({
|
|
54
|
+
clientId,
|
|
55
|
+
clientSecret,
|
|
56
|
+
password,
|
|
57
|
+
username,
|
|
58
|
+
});
|
|
50
59
|
```
|
|
51
60
|
|
|
52
61
|
## Utilities
|
|
@@ -70,7 +79,12 @@ const duration = secondsToReadableDuration(444);
|
|
|
70
79
|
|
|
71
80
|
```ts
|
|
72
81
|
import { Effect } from "effect";
|
|
73
|
-
import {
|
|
82
|
+
import {
|
|
83
|
+
PutioSdk,
|
|
84
|
+
createPutioSdkEffectClient,
|
|
85
|
+
makePutioSdkLiveClientLayer,
|
|
86
|
+
makePutioSdkLiveLayer,
|
|
87
|
+
} from "@putdotio/sdk";
|
|
74
88
|
|
|
75
89
|
const sdk = createPutioSdkEffectClient();
|
|
76
90
|
|
|
@@ -79,17 +93,29 @@ const program = sdk.files
|
|
|
79
93
|
per_page: 20,
|
|
80
94
|
total: 1,
|
|
81
95
|
})
|
|
82
|
-
.pipe(Effect.provide(makePutioSdkLiveLayer({ accessToken:
|
|
96
|
+
.pipe(Effect.provide(makePutioSdkLiveLayer({ accessToken: userAccessToken })));
|
|
83
97
|
|
|
84
98
|
const result = await Effect.runPromise(program);
|
|
85
99
|
```
|
|
86
100
|
|
|
87
|
-
|
|
88
|
-
|
|
101
|
+
Effect workflows can also depend on the SDK as a service:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const serviceProgram = Effect.gen(function* () {
|
|
105
|
+
const sdk = yield* PutioSdk;
|
|
106
|
+
return yield* sdk.files.list(0, { per_page: 20 });
|
|
107
|
+
}).pipe(Effect.provide(makePutioSdkLiveClientLayer({ accessToken: userAccessToken })));
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`makePutioSdkLiveClientLayer(...)` provides the SDK service, SDK config, and default fetch-backed transport.
|
|
111
|
+
`makePutioSdkLiveLayer(...)` provides both the SDK config and the default fetch-backed transport.
|
|
112
|
+
Use `makePutioSdkLayer(...)` with `makePutioFetchLayer(...)` or your own `PutioHttpClient` service when you want to supply custom transport.
|
|
89
113
|
|
|
90
114
|
## Side-By-Side Usage
|
|
91
115
|
|
|
92
|
-
Both client styles expose the same domain surface
|
|
116
|
+
Both client styles expose the same domain surface. The Promise client also exposes
|
|
117
|
+
`dispose()` for runtime teardown and `files.createUploadFormData(...)` for pure
|
|
118
|
+
FormData construction.
|
|
93
119
|
|
|
94
120
|
```ts
|
|
95
121
|
promiseClient.files.list(0, { per_page: 20 });
|
|
@@ -163,19 +189,21 @@ For upload flows, the host should also provide file-compatible inputs such as `F
|
|
|
163
189
|
|
|
164
190
|
If a target runtime is missing these APIs, provide them with host-level polyfills or adapters instead of patching the SDK surface.
|
|
165
191
|
|
|
192
|
+
The package compatibility gate installs the packed tarball into external consumers and runs strict Node type/runtime checks, bundled browser checks in Chromium, Firefox, and WebKit, and a Bun runtime import check.
|
|
193
|
+
|
|
166
194
|
## Error Handling
|
|
167
195
|
|
|
168
196
|
Promise consumers receive tagged SDK error objects:
|
|
169
197
|
|
|
170
198
|
```ts
|
|
171
199
|
import {
|
|
172
|
-
PutioOperationError,
|
|
173
|
-
PutioRateLimitError,
|
|
174
200
|
createPutioSdkPromiseClient,
|
|
201
|
+
isPutioOperationError,
|
|
202
|
+
isPutioRateLimitError,
|
|
175
203
|
} from "@putdotio/sdk";
|
|
176
204
|
|
|
177
205
|
const sdk = createPutioSdkPromiseClient({
|
|
178
|
-
accessToken:
|
|
206
|
+
accessToken: userAccessToken,
|
|
179
207
|
});
|
|
180
208
|
|
|
181
209
|
try {
|
|
@@ -184,13 +212,13 @@ try {
|
|
|
184
212
|
parent_id: 0,
|
|
185
213
|
});
|
|
186
214
|
} catch (error) {
|
|
187
|
-
if (error
|
|
215
|
+
if (isPutioOperationError(error)) {
|
|
188
216
|
if (error.operation === "createFolder") {
|
|
189
217
|
console.log(error.body.error_type);
|
|
190
218
|
}
|
|
191
219
|
}
|
|
192
220
|
|
|
193
|
-
if (error
|
|
221
|
+
if (isPutioRateLimitError(error)) {
|
|
194
222
|
console.log(error.retryAfter);
|
|
195
223
|
}
|
|
196
224
|
}
|
|
@@ -200,25 +228,24 @@ Effect consumers keep errors in the typed error channel instead of throwing:
|
|
|
200
228
|
|
|
201
229
|
```ts
|
|
202
230
|
import { Effect } from "effect";
|
|
203
|
-
import {
|
|
231
|
+
import { PutioSdk, makePutioSdkLiveClientLayer } from "@putdotio/sdk";
|
|
204
232
|
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
.createFolder({
|
|
233
|
+
const handled = Effect.gen(function* () {
|
|
234
|
+
const sdk = yield* PutioSdk;
|
|
235
|
+
return yield* sdk.files.createFolder({
|
|
209
236
|
name: "",
|
|
210
237
|
parent_id: 0,
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
238
|
+
});
|
|
239
|
+
}).pipe(
|
|
240
|
+
Effect.catchTag("PutioOperationError", (error) => {
|
|
241
|
+
if (error.operation === "createFolder") {
|
|
242
|
+
return Effect.succeed(error.body.error_type);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return Effect.fail(error);
|
|
246
|
+
}),
|
|
247
|
+
Effect.provide(makePutioSdkLiveClientLayer({ accessToken: userAccessToken })),
|
|
248
|
+
);
|
|
222
249
|
```
|
|
223
250
|
|
|
224
251
|
## Direct File Access
|
|
@@ -262,10 +289,9 @@ The Effect client also works well when you want the canonical typed API:
|
|
|
262
289
|
```ts
|
|
263
290
|
import { useQuery } from "@tanstack/react-query";
|
|
264
291
|
import { Effect } from "effect";
|
|
265
|
-
import {
|
|
292
|
+
import { PutioSdk, makePutioSdkLiveClientLayer } from "@putdotio/sdk";
|
|
266
293
|
|
|
267
|
-
const
|
|
268
|
-
const sdkLayer = makePutioSdkLiveLayer({
|
|
294
|
+
const sdkLayer = makePutioSdkLiveClientLayer({
|
|
269
295
|
accessToken: token,
|
|
270
296
|
});
|
|
271
297
|
|
|
@@ -273,21 +299,26 @@ export const useFiles = (parentId: number) =>
|
|
|
273
299
|
useQuery({
|
|
274
300
|
queryKey: ["files", parentId],
|
|
275
301
|
queryFn: () =>
|
|
276
|
-
Effect.runPromise(
|
|
302
|
+
Effect.runPromise(
|
|
303
|
+
Effect.gen(function* () {
|
|
304
|
+
const sdk = yield* PutioSdk;
|
|
305
|
+
return yield* sdk.files.list(parentId, { per_page: 50 });
|
|
306
|
+
}).pipe(Effect.provide(sdkLayer)),
|
|
307
|
+
),
|
|
277
308
|
});
|
|
278
309
|
```
|
|
279
310
|
|
|
280
311
|
## Docs
|
|
281
312
|
|
|
282
|
-
- [
|
|
283
|
-
- [
|
|
284
|
-
- [
|
|
285
|
-
- [
|
|
286
|
-
- [
|
|
313
|
+
- [Architecture](./docs/ARCHITECTURE.md) for package shape and boundaries
|
|
314
|
+
- [Testing](./docs/TESTING.md) for local and live verification
|
|
315
|
+
- [Readiness](./docs/READINESS.md) for domain readiness
|
|
316
|
+
- [Distribution](./docs/DISTRIBUTION.md) for release automation
|
|
317
|
+
- [Security](./SECURITY.md) for private-first vulnerability disclosure
|
|
287
318
|
|
|
288
319
|
## Contributing
|
|
289
320
|
|
|
290
|
-
Contributor setup, validation, and live-test workflow live in [
|
|
321
|
+
Contributor setup, validation, and live-test workflow live in [Contributing](./CONTRIBUTING.md).
|
|
291
322
|
|
|
292
323
|
## License
|
|
293
324
|
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer, Schema } from "effect";
|
|
2
|
+
//#region src/core/errors.ts
|
|
3
|
+
const PutioErrorEnvelopeSchema = Schema.Struct({
|
|
4
|
+
error_message: Schema.optional(Schema.String),
|
|
5
|
+
error_type: Schema.optional(Schema.String),
|
|
6
|
+
status_code: Schema.optional(Schema.Int),
|
|
7
|
+
details: Schema.optional(Schema.Unknown)
|
|
8
|
+
});
|
|
9
|
+
const isKnownContractMatch = (contract, error) => {
|
|
10
|
+
if (contract.errorType !== void 0) {
|
|
11
|
+
if (error.body.error_type !== contract.errorType) return false;
|
|
12
|
+
return contract.statusCode === void 0 || error.status === contract.statusCode;
|
|
13
|
+
}
|
|
14
|
+
if (contract.statusCode !== void 0) return error.status === contract.statusCode;
|
|
15
|
+
return false;
|
|
16
|
+
};
|
|
17
|
+
const isMatchableApiError = (error) => error._tag === "PutioApiError" || error._tag === "PutioAuthError";
|
|
18
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
19
|
+
const hasOptionalString = (record, key) => !(key in record) || record[key] === void 0 || typeof record[key] === "string";
|
|
20
|
+
const hasOptionalInteger = (record, key) => !(key in record) || record[key] === void 0 || typeof record[key] === "number" && Number.isInteger(record[key]);
|
|
21
|
+
const isKnownOperationErrorContract = (value) => isRecord(value) && (typeof value.errorType === "string" || typeof value.statusCode === "number") && hasOptionalString(value, "errorType") && hasOptionalInteger(value, "statusCode");
|
|
22
|
+
const isOperationReason = (value) => {
|
|
23
|
+
if (!isRecord(value)) return false;
|
|
24
|
+
if (value.kind === "error_type") return typeof value.errorType === "string";
|
|
25
|
+
if (value.kind === "status_code") return typeof value.statusCode === "number";
|
|
26
|
+
return false;
|
|
27
|
+
};
|
|
28
|
+
function toOperationReason(contract) {
|
|
29
|
+
if (contract.errorType !== void 0) return {
|
|
30
|
+
kind: "error_type",
|
|
31
|
+
errorType: contract.errorType
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
kind: "status_code",
|
|
35
|
+
statusCode: contract.statusCode
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var PutioTransportError = class extends Data.TaggedError("PutioTransportError") {};
|
|
39
|
+
var PutioConfigurationError = class extends Data.TaggedError("PutioConfigurationError") {};
|
|
40
|
+
var PutioValidationError = class extends Data.TaggedError("PutioValidationError") {};
|
|
41
|
+
const PutioResponseErrorFields = {
|
|
42
|
+
status: Schema.Int,
|
|
43
|
+
body: PutioErrorEnvelopeSchema
|
|
44
|
+
};
|
|
45
|
+
var PutioApiError = class extends Schema.TaggedErrorClass()("PutioApiError", { ...PutioResponseErrorFields }) {};
|
|
46
|
+
var PutioAuthError = class extends Schema.TaggedErrorClass()("PutioAuthError", { ...PutioResponseErrorFields }) {};
|
|
47
|
+
var PutioRateLimitError = class extends Schema.TaggedErrorClass()("PutioRateLimitError", {
|
|
48
|
+
...PutioResponseErrorFields,
|
|
49
|
+
action: Schema.optional(Schema.String),
|
|
50
|
+
id: Schema.optional(Schema.String),
|
|
51
|
+
limit: Schema.optional(Schema.String),
|
|
52
|
+
remaining: Schema.optional(Schema.String),
|
|
53
|
+
retryAfter: Schema.optional(Schema.String),
|
|
54
|
+
reset: Schema.optional(Schema.String)
|
|
55
|
+
}) {};
|
|
56
|
+
var PutioOperationError = class extends Data.TaggedError("PutioOperationError") {};
|
|
57
|
+
const definePutioOperationErrorSpec = (spec) => spec;
|
|
58
|
+
const decodePutioErrorEnvelope = Schema.decodeUnknownEffect(PutioErrorEnvelopeSchema);
|
|
59
|
+
const isPutioErrorEnvelope = (value) => isRecord(value) && hasOptionalString(value, "error_message") && hasOptionalString(value, "error_type") && hasOptionalInteger(value, "status_code");
|
|
60
|
+
const hasStatusAndBody = (value, tag) => isRecord(value) && value._tag === tag && typeof value.status === "number" && isPutioErrorEnvelope(value.body);
|
|
61
|
+
const isPutioApiError = (value) => hasStatusAndBody(value, "PutioApiError");
|
|
62
|
+
const isPutioAuthError = (value) => hasStatusAndBody(value, "PutioAuthError");
|
|
63
|
+
const isPutioRateLimitError = (value) => hasStatusAndBody(value, "PutioRateLimitError") && isRecord(value) && hasOptionalString(value, "action") && hasOptionalString(value, "id") && hasOptionalString(value, "limit") && hasOptionalString(value, "remaining") && hasOptionalString(value, "retryAfter") && hasOptionalString(value, "reset");
|
|
64
|
+
const isPutioOperationError = (value) => isRecord(value) && value._tag === "PutioOperationError" && isPutioErrorEnvelope(value.body) && isKnownOperationErrorContract(value.contract) && typeof value.domain === "string" && typeof value.operation === "string" && isOperationReason(value.reason) && typeof value.status === "number";
|
|
65
|
+
const fallbackPutioErrorEnvelope = (status) => ({
|
|
66
|
+
error_message: `put.io API request failed with status ${status}`,
|
|
67
|
+
status_code: status
|
|
68
|
+
});
|
|
69
|
+
const getHeader = (headers, name) => headers.get(name) ?? void 0;
|
|
70
|
+
const responseRateLimitHeaders = (headers) => ({
|
|
71
|
+
action: getHeader(headers, "x-ratelimit-action"),
|
|
72
|
+
id: getHeader(headers, "x-ratelimit-id"),
|
|
73
|
+
limit: getHeader(headers, "x-ratelimit-limit"),
|
|
74
|
+
remaining: getHeader(headers, "x-ratelimit-remaining"),
|
|
75
|
+
retryAfter: getHeader(headers, "retry-after"),
|
|
76
|
+
reset: getHeader(headers, "x-ratelimit-reset")
|
|
77
|
+
});
|
|
78
|
+
const mapDecodeErrorToValidationError = (cause) => new PutioValidationError({ cause });
|
|
79
|
+
const mapConfigurationError = (cause) => new PutioConfigurationError({ cause });
|
|
80
|
+
const mapTransportError = (cause) => new PutioTransportError({ cause });
|
|
81
|
+
const makeResponseError = (status, headers, body) => {
|
|
82
|
+
if (status === 429) return new PutioRateLimitError({
|
|
83
|
+
status,
|
|
84
|
+
body,
|
|
85
|
+
...responseRateLimitHeaders(headers)
|
|
86
|
+
});
|
|
87
|
+
if (status === 401 || status === 403) return new PutioAuthError({
|
|
88
|
+
status,
|
|
89
|
+
body
|
|
90
|
+
});
|
|
91
|
+
return new PutioApiError({
|
|
92
|
+
status,
|
|
93
|
+
body
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
const parseErrorBody = (status, json) => decodePutioErrorEnvelope(json).pipe(Effect.orElseSucceed(() => fallbackPutioErrorEnvelope(status)));
|
|
97
|
+
function withOperationErrors(effectOrSpec, maybeSpec) {
|
|
98
|
+
if (maybeSpec === void 0) {
|
|
99
|
+
const spec = effectOrSpec;
|
|
100
|
+
return (effect) => withOperationErrors(effect, spec);
|
|
101
|
+
}
|
|
102
|
+
const effect = effectOrSpec;
|
|
103
|
+
const spec = maybeSpec;
|
|
104
|
+
return effect.pipe(Effect.mapError((error) => {
|
|
105
|
+
if (!isMatchableApiError(error)) return error;
|
|
106
|
+
const contract = spec.knownErrors.find((candidate) => isKnownContractMatch(candidate, error));
|
|
107
|
+
if (!contract) return error;
|
|
108
|
+
return new PutioOperationError({
|
|
109
|
+
body: error.body,
|
|
110
|
+
contract,
|
|
111
|
+
domain: spec.domain,
|
|
112
|
+
operation: spec.operation,
|
|
113
|
+
reason: toOperationReason(contract),
|
|
114
|
+
status: error.status
|
|
115
|
+
});
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/core/defaults.ts
|
|
120
|
+
const DEFAULT_PUTIO_API_BASE_URL = "https://api.put.io";
|
|
121
|
+
const DEFAULT_PUTIO_UPLOAD_BASE_URL = "https://upload.put.io";
|
|
122
|
+
const DEFAULT_PUTIO_WEB_APP_URL = "https://app.put.io";
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/core/http.ts
|
|
125
|
+
var PutioSdkConfig = class extends Context.Service()("PutioSdkConfig") {};
|
|
126
|
+
var PutioHttpClient = class extends Context.Service()("PutioHttpClient") {};
|
|
127
|
+
const makePutioSdkConfig = (config) => ({
|
|
128
|
+
accessToken: config.accessToken,
|
|
129
|
+
baseUrl: config.baseUrl ?? "https://api.put.io",
|
|
130
|
+
uploadBaseUrl: config.uploadBaseUrl ?? "https://upload.put.io",
|
|
131
|
+
webAppUrl: config.webAppUrl ?? "https://app.put.io"
|
|
132
|
+
});
|
|
133
|
+
const makePutioSdkLayer = (config) => Layer.succeed(PutioSdkConfig, makePutioSdkConfig(config));
|
|
134
|
+
const makePutioSdkLiveLayer = (config) => Layer.mergeAll(makePutioSdkLayer(config), makePutioFetchLayer());
|
|
135
|
+
const makePutioFetchLayer = (fetchImplementation = globalThis.fetch) => Layer.succeed(PutioHttpClient, makePutioFetchClient(fetchImplementation));
|
|
136
|
+
const makePutioFetchClient = (fetchImplementation = globalThis.fetch) => ({ execute: (request) => Effect.tryPromise({
|
|
137
|
+
try: async (signal) => {
|
|
138
|
+
const response = await fetchImplementation(request.url, {
|
|
139
|
+
body: request.body,
|
|
140
|
+
headers: request.headers,
|
|
141
|
+
method: request.method,
|
|
142
|
+
signal
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
arrayBuffer: Effect.tryPromise({
|
|
146
|
+
try: () => response.arrayBuffer(),
|
|
147
|
+
catch: mapTransportError
|
|
148
|
+
}),
|
|
149
|
+
headers: response.headers,
|
|
150
|
+
json: Effect.tryPromise({
|
|
151
|
+
try: () => response.json(),
|
|
152
|
+
catch: mapTransportError
|
|
153
|
+
}),
|
|
154
|
+
status: response.status
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
catch: mapTransportError
|
|
158
|
+
}) });
|
|
159
|
+
const encodePathSegment = (value) => encodeURIComponent(String(value));
|
|
160
|
+
const absoluteUrlPattern = /^(?:[a-z][a-z\d+.-]*:|\/\/)/i;
|
|
161
|
+
const normalizeApiPath = (path) => {
|
|
162
|
+
if (absoluteUrlPattern.test(path)) throw mapConfigurationError("SDK API request paths must be relative to the configured baseUrl");
|
|
163
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
164
|
+
};
|
|
165
|
+
const buildPutioUrl = (baseUrl, path, query) => {
|
|
166
|
+
const url = new URL(normalizeApiPath(path), baseUrl);
|
|
167
|
+
if (query) {
|
|
168
|
+
for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
|
|
169
|
+
}
|
|
170
|
+
return url.toString();
|
|
171
|
+
};
|
|
172
|
+
const mapUrlBuildError = (cause) => cause instanceof PutioConfigurationError ? cause : mapConfigurationError(cause);
|
|
173
|
+
const OkResponseSchema = Schema.Struct({ status: Schema.Literal("OK") });
|
|
174
|
+
const isSuccessStatus = (status) => status >= 200 && status < 300;
|
|
175
|
+
const decodeSuccessJson = (schema, response) => response.json.pipe(Effect.flatMap(Schema.decodeUnknownEffect(schema)), Effect.mapError(mapDecodeErrorToValidationError));
|
|
176
|
+
const decodeFailure = (response, headers) => response.json.pipe(Effect.flatMap((json) => parseErrorBody(response.status, json)), Effect.orElseSucceed(() => fallbackPutioErrorEnvelope(response.status)), Effect.map((body) => makeResponseError(response.status, headers, body)));
|
|
177
|
+
const toBasicAuthorization = (username, password) => {
|
|
178
|
+
if (typeof globalThis.btoa === "function") return `Basic ${globalThis.btoa(`${username}:${password}`)}`;
|
|
179
|
+
throw mapConfigurationError("This runtime does not provide btoa(), so Basic auth cannot be encoded safely");
|
|
180
|
+
};
|
|
181
|
+
const resolveAuthorization = (config, auth) => {
|
|
182
|
+
const resolvedAuth = auth ?? { type: "config-token" };
|
|
183
|
+
switch (resolvedAuth.type) {
|
|
184
|
+
case "none": return Effect.succeed(void 0);
|
|
185
|
+
case "token": return Effect.succeed(`Token ${resolvedAuth.token}`);
|
|
186
|
+
case "basic": return Effect.try({
|
|
187
|
+
try: () => toBasicAuthorization(resolvedAuth.username, resolvedAuth.password),
|
|
188
|
+
catch: mapConfigurationError
|
|
189
|
+
});
|
|
190
|
+
case "config-token":
|
|
191
|
+
if (!config.accessToken) return Effect.fail(mapConfigurationError("This endpoint requires an access token, but PutioSdkConfig.accessToken is missing"));
|
|
192
|
+
return Effect.succeed(`Token ${config.accessToken}`);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const normalizeFormValue = (value) => {
|
|
196
|
+
if (value === null || value === void 0) return "";
|
|
197
|
+
if (typeof value === "string") return value;
|
|
198
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
199
|
+
return JSON.stringify(value);
|
|
200
|
+
};
|
|
201
|
+
const withBody = (body) => {
|
|
202
|
+
switch (body.type) {
|
|
203
|
+
case "none": return Effect.succeed(void 0);
|
|
204
|
+
case "json": return Effect.try({
|
|
205
|
+
try: () => JSON.stringify(body.value),
|
|
206
|
+
catch: mapDecodeErrorToValidationError
|
|
207
|
+
});
|
|
208
|
+
case "form": return Effect.succeed(new URLSearchParams(Object.entries(body.value).flatMap(([key, value]) => value === void 0 ? [] : [[key, normalizeFormValue(value)]])));
|
|
209
|
+
case "form-data": return Effect.succeed(body.value);
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const makeRequest = (url, options, authorization) => Effect.gen(function* () {
|
|
213
|
+
const headers = new Headers(options.headers);
|
|
214
|
+
const body = options.body ?? { type: "none" };
|
|
215
|
+
headers.set("accept", "application/json");
|
|
216
|
+
if (authorization) headers.set("authorization", authorization);
|
|
217
|
+
if (body.type === "json" && !headers.has("content-type")) headers.set("content-type", "application/json");
|
|
218
|
+
return {
|
|
219
|
+
body: yield* withBody(body),
|
|
220
|
+
headers,
|
|
221
|
+
method: options.method,
|
|
222
|
+
url
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
const executeRequest = (options) => Effect.gen(function* () {
|
|
226
|
+
const config = yield* PutioSdkConfig;
|
|
227
|
+
const httpClient = yield* PutioHttpClient;
|
|
228
|
+
const authorization = yield* resolveAuthorization(config, options.auth);
|
|
229
|
+
const request = yield* makeRequest(yield* Effect.try({
|
|
230
|
+
try: () => buildPutioUrl(options.baseUrl ?? config.baseUrl ?? "https://api.put.io", options.path, options.query),
|
|
231
|
+
catch: mapUrlBuildError
|
|
232
|
+
}), options, authorization);
|
|
233
|
+
return yield* httpClient.execute(request);
|
|
234
|
+
});
|
|
235
|
+
const requestJson = (schema, options) => executeRequest(options).pipe(Effect.flatMap((response) => isSuccessStatus(response.status) ? decodeSuccessJson(schema, response) : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail))));
|
|
236
|
+
const selectJsonField = (field) => (effect) => effect.pipe(Effect.map((value) => value[field]));
|
|
237
|
+
const selectJsonFields = (...fields) => (effect) => effect.pipe(Effect.map((value) => Object.fromEntries(fields.map((field) => [field, value[field]]))));
|
|
238
|
+
const requestArrayBuffer = (options) => executeRequest(options).pipe(Effect.flatMap((response) => isSuccessStatus(response.status) ? response.arrayBuffer.pipe(Effect.mapError(mapTransportError), Effect.map((buffer) => new Uint8Array(buffer))) : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail))));
|
|
239
|
+
const requestVoid = (options) => executeRequest(options).pipe(Effect.flatMap((response) => isSuccessStatus(response.status) ? Effect.void : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail))));
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region src/core/forms.ts
|
|
242
|
+
const joinCsv = (values) => values && values.length > 0 ? values.join(",") : void 0;
|
|
243
|
+
const toCursorSelectionForm = (selection, idsFieldName) => {
|
|
244
|
+
const resolvedIdsFieldName = idsFieldName ?? "file_ids";
|
|
245
|
+
return {
|
|
246
|
+
cursor: selection.cursor,
|
|
247
|
+
exclude_ids: joinCsv(selection.excludeIds),
|
|
248
|
+
[resolvedIdsFieldName]: joinCsv(selection.ids)
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
252
|
+
export { definePutioOperationErrorSpec as A, mapTransportError as B, PutioConfigurationError as C, PutioTransportError as D, PutioRateLimitError as E, isPutioOperationError as F, responseRateLimitHeaders as H, isPutioRateLimitError as I, makeResponseError as L, isPutioApiError as M, isPutioAuthError as N, PutioValidationError as O, isPutioErrorEnvelope as P, mapConfigurationError as R, PutioAuthError as S, PutioOperationError as T, withOperationErrors as U, parseErrorBody as V, selectJsonFields as _, PutioSdkConfig as a, DEFAULT_PUTIO_WEB_APP_URL as b, makePutioFetchClient as c, makePutioSdkLayer as d, makePutioSdkLiveLayer as f, selectJsonField as g, requestVoid as h, PutioHttpClient as i, fallbackPutioErrorEnvelope as j, decodePutioErrorEnvelope as k, makePutioFetchLayer as l, requestJson as m, toCursorSelectionForm as n, buildPutioUrl as o, requestArrayBuffer as p, OkResponseSchema as r, encodePathSegment as s, joinCsv as t, makePutioSdkConfig as u, DEFAULT_PUTIO_API_BASE_URL as v, PutioErrorEnvelopeSchema as w, PutioApiError as x, DEFAULT_PUTIO_UPLOAD_BASE_URL as y, mapDecodeErrorToValidationError as z };
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=forms-DCO3Ckbx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms-DCO3Ckbx.js","names":[],"sources":["../src/core/errors.ts","../src/core/defaults.ts","../src/core/http.ts","../src/core/forms.ts"],"sourcesContent":["import { Data, Effect, Schema } from \"effect\";\n\nexport const PutioErrorEnvelopeSchema = Schema.Struct({\n error_message: Schema.optional(Schema.String),\n error_type: Schema.optional(Schema.String),\n status_code: Schema.optional(Schema.Int),\n details: Schema.optional(Schema.Unknown),\n});\n\nexport type PutioErrorEnvelope = Schema.Schema.Type<typeof PutioErrorEnvelopeSchema>;\n\nexport interface PutioKnownErrorContract<\n TType extends string = string,\n TStatus extends number = number,\n> {\n readonly errorType?: TType | undefined;\n readonly statusCode?: TStatus | undefined;\n}\n\ntype ContractErrorType<TContract extends PutioKnownErrorContract> =\n TContract extends PutioKnownErrorContract<infer TType, number> ? TType : never;\n\ntype ContractStatusCode<TContract extends PutioKnownErrorContract> =\n TContract extends PutioKnownErrorContract<string, infer TStatus> ? TStatus : never;\n\nexport type PutioTypedErrorEnvelope<TContract extends PutioKnownErrorContract> = Omit<\n PutioErrorEnvelope,\n \"error_message\" | \"error_type\" | \"status_code\"\n> & {\n readonly error_message?: string;\n readonly error_type?: [ContractErrorType<TContract>] extends [never]\n ? string\n : ContractErrorType<TContract>;\n readonly status_code?: [ContractStatusCode<TContract>] extends [never]\n ? number\n : ContractStatusCode<TContract>;\n};\n\nexport interface PutioOperationErrorSpec<\n TDomain extends string = string,\n TOperation extends string = string,\n TContracts extends ReadonlyArray<PutioKnownErrorContract> =\n ReadonlyArray<PutioKnownErrorContract>,\n> {\n readonly domain: TDomain;\n readonly operation: TOperation;\n readonly knownErrors: TContracts;\n}\n\ntype OperationContractOf<TSpec extends PutioOperationErrorSpec> = Extract<\n TSpec[\"knownErrors\"][number],\n PutioKnownOperationErrorContract\n>;\n\ntype OperationContractOfParts<\n TDomain extends string,\n TOperation extends string,\n TContracts extends ReadonlyArray<PutioKnownErrorContract>,\n> = OperationContractOf<PutioOperationErrorSpec<TDomain, TOperation, TContracts>>;\n\ntype PutioOperationErrorReason<TContract extends PutioKnownErrorContract> = TContract extends {\n readonly errorType: infer TType extends string;\n}\n ? {\n readonly kind: \"error_type\";\n readonly errorType: TType;\n }\n : TContract extends { readonly statusCode: infer TStatus extends number }\n ? {\n readonly kind: \"status_code\";\n readonly statusCode: TStatus;\n }\n : never;\n\nexport type PutioKnownOperationErrorContract =\n | {\n readonly errorType: string;\n readonly statusCode?: number;\n }\n | {\n readonly errorType?: undefined;\n readonly statusCode: number;\n };\n\nconst isKnownContractMatch = <TContract extends PutioKnownErrorContract>(\n contract: TContract,\n error: PutioApiError | PutioAuthError,\n): contract is Extract<TContract, PutioKnownOperationErrorContract> => {\n if (contract.errorType !== undefined) {\n if (error.body.error_type !== contract.errorType) {\n return false;\n }\n\n return contract.statusCode === undefined || error.status === contract.statusCode;\n }\n\n if (contract.statusCode !== undefined) {\n return error.status === contract.statusCode;\n }\n\n return false;\n};\n\nconst isMatchableApiError = (error: PutioSdkError): error is PutioApiError | PutioAuthError =>\n error._tag === \"PutioApiError\" || error._tag === \"PutioAuthError\";\n\nconst isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>\n typeof value === \"object\" && value !== null;\n\nconst hasOptionalString = (record: Readonly<Record<string, unknown>>, key: string): boolean =>\n !(key in record) || record[key] === undefined || typeof record[key] === \"string\";\n\nconst hasOptionalInteger = (record: Readonly<Record<string, unknown>>, key: string): boolean =>\n !(key in record) ||\n record[key] === undefined ||\n (typeof record[key] === \"number\" && Number.isInteger(record[key]));\n\nconst isKnownOperationErrorContract = (value: unknown): value is PutioKnownOperationErrorContract =>\n isRecord(value) &&\n (typeof value.errorType === \"string\" || typeof value.statusCode === \"number\") &&\n hasOptionalString(value, \"errorType\") &&\n hasOptionalInteger(value, \"statusCode\");\n\nconst isOperationReason = (\n value: unknown,\n): value is PutioOperationErrorReason<PutioKnownOperationErrorContract> => {\n if (!isRecord(value)) {\n return false;\n }\n\n if (value.kind === \"error_type\") {\n return typeof value.errorType === \"string\";\n }\n\n if (value.kind === \"status_code\") {\n return typeof value.statusCode === \"number\";\n }\n\n return false;\n};\n\nfunction toOperationReason<TContract extends { readonly errorType: string }>(\n contract: TContract,\n): PutioOperationErrorReason<TContract>;\nfunction toOperationReason<TContract extends { readonly statusCode: number }>(\n contract: TContract,\n): PutioOperationErrorReason<TContract>;\nfunction toOperationReason(\n contract: PutioKnownOperationErrorContract,\n): PutioOperationErrorReason<PutioKnownOperationErrorContract> {\n if (contract.errorType !== undefined) {\n return {\n kind: \"error_type\",\n errorType: contract.errorType,\n };\n }\n\n return {\n kind: \"status_code\",\n statusCode: contract.statusCode,\n };\n}\n\nexport class PutioTransportError extends Data.TaggedError(\"PutioTransportError\")<{\n readonly cause: unknown;\n}> {}\n\nexport class PutioConfigurationError extends Data.TaggedError(\"PutioConfigurationError\")<{\n readonly cause: unknown;\n}> {}\n\nexport class PutioValidationError extends Data.TaggedError(\"PutioValidationError\")<{\n readonly cause: unknown;\n}> {}\n\nconst PutioResponseErrorFields = {\n status: Schema.Int,\n body: PutioErrorEnvelopeSchema,\n};\n\nexport class PutioApiError extends Schema.TaggedErrorClass<PutioApiError>()(\"PutioApiError\", {\n ...PutioResponseErrorFields,\n}) {}\n\nexport class PutioAuthError extends Schema.TaggedErrorClass<PutioAuthError>()(\"PutioAuthError\", {\n ...PutioResponseErrorFields,\n}) {}\n\nexport class PutioRateLimitError extends Schema.TaggedErrorClass<PutioRateLimitError>()(\n \"PutioRateLimitError\",\n {\n ...PutioResponseErrorFields,\n action: Schema.optional(Schema.String),\n id: Schema.optional(Schema.String),\n limit: Schema.optional(Schema.String),\n remaining: Schema.optional(Schema.String),\n retryAfter: Schema.optional(Schema.String),\n reset: Schema.optional(Schema.String),\n },\n) {}\n\nexport class PutioOperationError<\n TDomain extends string,\n TOperation extends string,\n TContract extends PutioKnownOperationErrorContract,\n> extends Data.TaggedError(\"PutioOperationError\")<{\n readonly body: PutioTypedErrorEnvelope<TContract>;\n readonly contract: TContract;\n readonly domain: TDomain;\n readonly operation: TOperation;\n readonly reason: PutioOperationErrorReason<TContract>;\n readonly status: number;\n}> {}\n\nexport type PutioSdkError =\n | PutioConfigurationError\n | PutioTransportError\n | PutioValidationError\n | PutioApiError\n | PutioAuthError\n | PutioRateLimitError;\n\nexport type PutioUnhandledSdkError =\n | PutioConfigurationError\n | PutioTransportError\n | PutioValidationError\n | PutioApiError\n | PutioAuthError\n | PutioRateLimitError;\n\nexport type PutioOperationErrorFromSpec<TSpec extends PutioOperationErrorSpec> =\n PutioOperationError<TSpec[\"domain\"], TSpec[\"operation\"], OperationContractOf<TSpec>>;\n\nexport type PutioOperationFailure<TSpec extends PutioOperationErrorSpec> =\n | PutioUnhandledSdkError\n | PutioOperationErrorFromSpec<TSpec>;\n\nexport type AnyPutioOperationError = PutioOperationError<\n string,\n string,\n PutioKnownOperationErrorContract\n>;\n\nexport const definePutioOperationErrorSpec = <\n const TDomain extends string,\n const TOperation extends string,\n const TContracts extends ReadonlyArray<PutioKnownErrorContract>,\n>(\n spec: PutioOperationErrorSpec<TDomain, TOperation, TContracts>,\n) => spec;\n\nexport const decodePutioErrorEnvelope = Schema.decodeUnknownEffect(PutioErrorEnvelopeSchema);\n\nexport const isPutioErrorEnvelope = (value: unknown): value is PutioErrorEnvelope =>\n isRecord(value) &&\n hasOptionalString(value, \"error_message\") &&\n hasOptionalString(value, \"error_type\") &&\n hasOptionalInteger(value, \"status_code\");\n\nconst hasStatusAndBody = <TTag extends string>(\n value: unknown,\n tag: TTag,\n): value is {\n readonly _tag: TTag;\n readonly body: PutioErrorEnvelope;\n readonly status: number;\n} =>\n isRecord(value) &&\n value._tag === tag &&\n typeof value.status === \"number\" &&\n isPutioErrorEnvelope(value.body);\n\nexport const isPutioApiError = (value: unknown): value is PutioApiError =>\n hasStatusAndBody(value, \"PutioApiError\");\n\nexport const isPutioAuthError = (value: unknown): value is PutioAuthError =>\n hasStatusAndBody(value, \"PutioAuthError\");\n\nexport const isPutioRateLimitError = (value: unknown): value is PutioRateLimitError =>\n hasStatusAndBody(value, \"PutioRateLimitError\") &&\n isRecord(value) &&\n hasOptionalString(value, \"action\") &&\n hasOptionalString(value, \"id\") &&\n hasOptionalString(value, \"limit\") &&\n hasOptionalString(value, \"remaining\") &&\n hasOptionalString(value, \"retryAfter\") &&\n hasOptionalString(value, \"reset\");\n\nexport const isPutioOperationError = (value: unknown): value is AnyPutioOperationError =>\n isRecord(value) &&\n value._tag === \"PutioOperationError\" &&\n isPutioErrorEnvelope(value.body) &&\n isKnownOperationErrorContract(value.contract) &&\n typeof value.domain === \"string\" &&\n typeof value.operation === \"string\" &&\n isOperationReason(value.reason) &&\n typeof value.status === \"number\";\n\nexport const fallbackPutioErrorEnvelope = (status: number): PutioErrorEnvelope => ({\n error_message: `put.io API request failed with status ${status}`,\n status_code: status,\n});\n\nconst getHeader = (headers: Headers, name: string): string | undefined =>\n headers.get(name) ?? undefined;\n\nexport const responseRateLimitHeaders = (headers: Headers) => ({\n action: getHeader(headers, \"x-ratelimit-action\"),\n id: getHeader(headers, \"x-ratelimit-id\"),\n limit: getHeader(headers, \"x-ratelimit-limit\"),\n remaining: getHeader(headers, \"x-ratelimit-remaining\"),\n retryAfter: getHeader(headers, \"retry-after\"),\n reset: getHeader(headers, \"x-ratelimit-reset\"),\n});\n\nexport const mapDecodeErrorToValidationError = (cause: unknown) =>\n new PutioValidationError({ cause });\n\nexport const mapConfigurationError = (cause: unknown) => new PutioConfigurationError({ cause });\n\nexport const mapTransportError = (cause: unknown) => new PutioTransportError({ cause });\n\nexport const makeResponseError = (\n status: number,\n headers: Headers,\n body: PutioErrorEnvelope,\n): PutioSdkError => {\n if (status === 429) {\n return new PutioRateLimitError({\n status,\n body,\n ...responseRateLimitHeaders(headers),\n });\n }\n\n if (status === 401 || status === 403) {\n return new PutioAuthError({ status, body });\n }\n\n return new PutioApiError({ status, body });\n};\n\nexport const parseErrorBody = (status: number, json: unknown) =>\n decodePutioErrorEnvelope(json).pipe(\n Effect.orElseSucceed(() => fallbackPutioErrorEnvelope(status)),\n );\n\nexport function withOperationErrors<\n A,\n E extends PutioSdkError,\n R,\n const TDomain extends string,\n const TOperation extends string,\n const TContracts extends ReadonlyArray<PutioKnownErrorContract>,\n>(\n effect: Effect.Effect<A, E, R>,\n spec: PutioOperationErrorSpec<TDomain, TOperation, TContracts>,\n): Effect.Effect<\n A,\n | E\n | PutioOperationError<\n TDomain,\n TOperation,\n OperationContractOfParts<TDomain, TOperation, TContracts>\n >,\n R\n>;\nexport function withOperationErrors<\n const TDomain extends string,\n const TOperation extends string,\n const TContracts extends ReadonlyArray<PutioKnownErrorContract>,\n>(\n spec: PutioOperationErrorSpec<TDomain, TOperation, TContracts>,\n): <A, E extends PutioSdkError, R>(\n effect: Effect.Effect<A, E, R>,\n) => Effect.Effect<\n A,\n | E\n | PutioOperationError<\n TDomain,\n TOperation,\n OperationContractOfParts<TDomain, TOperation, TContracts>\n >,\n R\n>;\nexport function withOperationErrors<\n A,\n E extends PutioSdkError,\n R,\n const TDomain extends string,\n const TOperation extends string,\n const TContracts extends ReadonlyArray<PutioKnownErrorContract>,\n>(\n effectOrSpec: Effect.Effect<A, E, R> | PutioOperationErrorSpec<TDomain, TOperation, TContracts>,\n maybeSpec?: PutioOperationErrorSpec<TDomain, TOperation, TContracts>,\n):\n | Effect.Effect<\n A,\n | E\n | PutioOperationError<\n TDomain,\n TOperation,\n OperationContractOfParts<TDomain, TOperation, TContracts>\n >,\n R\n >\n | (<A2, E2 extends PutioSdkError, R2>(\n effect: Effect.Effect<A2, E2, R2>,\n ) => Effect.Effect<\n A2,\n | E2\n | PutioOperationError<\n TDomain,\n TOperation,\n OperationContractOfParts<TDomain, TOperation, TContracts>\n >,\n R2\n >) {\n if (maybeSpec === undefined) {\n const spec = effectOrSpec as PutioOperationErrorSpec<TDomain, TOperation, TContracts>;\n\n return <A2, E2 extends PutioSdkError, R2>(effect: Effect.Effect<A2, E2, R2>) =>\n withOperationErrors(effect, spec);\n }\n\n const effect = effectOrSpec as Effect.Effect<A, E, R>;\n const spec = maybeSpec;\n\n return effect.pipe(\n Effect.mapError((error) => {\n if (!isMatchableApiError(error)) {\n return error;\n }\n\n const contract = spec.knownErrors.find((candidate) => isKnownContractMatch(candidate, error));\n\n if (!contract) {\n return error;\n }\n\n return new PutioOperationError({\n body: error.body as PutioTypedErrorEnvelope<\n OperationContractOfParts<TDomain, TOperation, TContracts>\n >,\n contract,\n domain: spec.domain,\n operation: spec.operation,\n reason: toOperationReason(contract),\n status: error.status,\n });\n }),\n );\n}\n","export const DEFAULT_PUTIO_API_BASE_URL = \"https://api.put.io\";\nexport const DEFAULT_PUTIO_UPLOAD_BASE_URL = \"https://upload.put.io\";\nexport const DEFAULT_PUTIO_WEB_APP_URL = \"https://app.put.io\";\n","import { Context, Effect, Layer, Schema } from \"effect\";\n\nimport {\n DEFAULT_PUTIO_API_BASE_URL,\n DEFAULT_PUTIO_UPLOAD_BASE_URL,\n DEFAULT_PUTIO_WEB_APP_URL,\n} from \"./defaults.js\";\nimport {\n fallbackPutioErrorEnvelope,\n makeResponseError,\n mapConfigurationError,\n mapDecodeErrorToValidationError,\n mapTransportError,\n parseErrorBody,\n PutioConfigurationError,\n type PutioSdkError,\n} from \"./errors.js\";\n\nexport type PutioQueryValue = string | number | boolean | null | undefined;\n\nexport type PutioQuery = Readonly<Record<string, PutioQueryValue>>;\n\nexport type PutioPathSegment = string | number | boolean;\n\nexport interface PutioSdkConfigShape {\n readonly accessToken?: string;\n readonly baseUrl?: string | URL;\n readonly uploadBaseUrl?: string | URL;\n readonly webAppUrl?: string | URL;\n}\n\nexport class PutioSdkConfig extends Context.Service<PutioSdkConfig, PutioSdkConfigShape>()(\n \"PutioSdkConfig\",\n) {}\n\nexport interface PutioHttpRequest {\n readonly body?: BodyInit;\n readonly headers: Headers;\n readonly method: PutioRequestMethod;\n readonly url: string;\n}\n\nexport interface PutioHttpResponse {\n readonly arrayBuffer: Effect.Effect<ArrayBuffer, PutioSdkError>;\n readonly headers: Headers;\n readonly json: Effect.Effect<unknown, PutioSdkError>;\n readonly status: number;\n}\n\nexport interface PutioHttpClientShape {\n readonly execute: (request: PutioHttpRequest) => Effect.Effect<PutioHttpResponse, PutioSdkError>;\n}\n\nexport class PutioHttpClient extends Context.Service<PutioHttpClient, PutioHttpClientShape>()(\n \"PutioHttpClient\",\n) {}\n\nexport type PutioSdkContext = PutioSdkConfig | PutioHttpClient;\n\nexport const makePutioSdkConfig = (config: PutioSdkConfigShape): PutioSdkConfigShape => ({\n accessToken: config.accessToken,\n baseUrl: config.baseUrl ?? DEFAULT_PUTIO_API_BASE_URL,\n uploadBaseUrl: config.uploadBaseUrl ?? DEFAULT_PUTIO_UPLOAD_BASE_URL,\n webAppUrl: config.webAppUrl ?? DEFAULT_PUTIO_WEB_APP_URL,\n});\n\nexport const makePutioSdkLayer = (config: PutioSdkConfigShape) =>\n Layer.succeed(PutioSdkConfig, makePutioSdkConfig(config));\n\nexport const makePutioSdkLiveLayer = (config: PutioSdkConfigShape) =>\n Layer.mergeAll(makePutioSdkLayer(config), makePutioFetchLayer());\n\nexport const makePutioFetchLayer = (\n fetchImplementation: typeof globalThis.fetch = globalThis.fetch,\n) => Layer.succeed(PutioHttpClient, makePutioFetchClient(fetchImplementation));\n\nexport const makePutioFetchClient = (\n fetchImplementation: typeof globalThis.fetch = globalThis.fetch,\n): PutioHttpClientShape => ({\n execute: (request) =>\n Effect.tryPromise({\n try: async (signal) => {\n const response = await fetchImplementation(request.url, {\n body: request.body,\n headers: request.headers,\n method: request.method,\n signal,\n });\n\n return {\n arrayBuffer: Effect.tryPromise({\n try: () => response.arrayBuffer(),\n catch: mapTransportError,\n }),\n headers: response.headers,\n json: Effect.tryPromise({\n try: () => response.json(),\n catch: mapTransportError,\n }),\n status: response.status,\n };\n },\n catch: mapTransportError,\n }),\n});\n\nexport const encodePathSegment = (value: PutioPathSegment): string =>\n encodeURIComponent(String(value));\n\nconst absoluteUrlPattern = /^(?:[a-z][a-z\\d+.-]*:|\\/\\/)/i;\n\nconst normalizeApiPath = (path: string): string => {\n if (absoluteUrlPattern.test(path)) {\n throw mapConfigurationError(\"SDK API request paths must be relative to the configured baseUrl\");\n }\n\n return path.startsWith(\"/\") ? path : `/${path}`;\n};\n\nexport const buildPutioUrl = (baseUrl: string | URL, path: string, query?: PutioQuery): string => {\n const url = new URL(normalizeApiPath(path), baseUrl);\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n};\n\nconst mapUrlBuildError = (cause: unknown) =>\n cause instanceof PutioConfigurationError ? cause : mapConfigurationError(cause);\n\nexport const OkResponseSchema = Schema.Struct({\n status: Schema.Literal(\"OK\"),\n});\n\nexport type PutioAuth =\n | { readonly type: \"config-token\" }\n | { readonly type: \"token\"; readonly token: string }\n | { readonly type: \"basic\"; readonly username: string; readonly password: string }\n | { readonly type: \"none\" };\n\ntype PutioRequestMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\ntype PutioRequestBody =\n | { readonly type: \"none\" }\n | { readonly type: \"json\"; readonly value: unknown }\n | { readonly type: \"form\"; readonly value: Record<string, unknown> }\n | { readonly type: \"form-data\"; readonly value: FormData };\n\ninterface PutioRequestOptions {\n readonly method: PutioRequestMethod;\n readonly path: string;\n readonly baseUrl?: string | URL;\n readonly query?: PutioQuery;\n readonly headers?: HeadersInit;\n readonly auth?: PutioAuth;\n readonly body?: PutioRequestBody;\n}\n\nconst isSuccessStatus = (status: number) => status >= 200 && status < 300;\n\nconst decodeSuccessJson = <S extends Schema.Top>(schema: S, response: PutioHttpResponse) =>\n response.json.pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(schema)),\n Effect.mapError(mapDecodeErrorToValidationError),\n );\n\nconst decodeFailure = (response: PutioHttpResponse, headers: Headers) =>\n response.json.pipe(\n Effect.flatMap((json) => parseErrorBody(response.status, json)),\n Effect.orElseSucceed(() => fallbackPutioErrorEnvelope(response.status)),\n Effect.map((body) => makeResponseError(response.status, headers, body)),\n );\n\nconst toBasicAuthorization = (username: string, password: string) => {\n if (typeof globalThis.btoa === \"function\") {\n return `Basic ${globalThis.btoa(`${username}:${password}`)}`;\n }\n\n throw mapConfigurationError(\n \"This runtime does not provide btoa(), so Basic auth cannot be encoded safely\",\n );\n};\n\nconst resolveAuthorization = (\n config: PutioSdkConfigShape,\n auth: PutioAuth | undefined,\n): Effect.Effect<string | undefined, PutioSdkError> => {\n const resolvedAuth = auth ?? { type: \"config-token\" as const };\n\n switch (resolvedAuth.type) {\n case \"none\":\n return Effect.succeed(undefined);\n case \"token\":\n return Effect.succeed(`Token ${resolvedAuth.token}`);\n case \"basic\":\n return Effect.try({\n try: () => toBasicAuthorization(resolvedAuth.username, resolvedAuth.password),\n catch: mapConfigurationError,\n });\n case \"config-token\":\n if (!config.accessToken) {\n return Effect.fail(\n mapConfigurationError(\n \"This endpoint requires an access token, but PutioSdkConfig.accessToken is missing\",\n ),\n );\n }\n\n return Effect.succeed(`Token ${config.accessToken}`);\n }\n};\n\nconst normalizeFormValue = (value: unknown): string => {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n return JSON.stringify(value);\n};\n\nconst withBody = (body: PutioRequestBody): Effect.Effect<BodyInit | undefined, PutioSdkError> => {\n switch (body.type) {\n case \"none\":\n return Effect.succeed(undefined);\n case \"json\":\n return Effect.try({\n try: () => JSON.stringify(body.value),\n catch: mapDecodeErrorToValidationError,\n });\n case \"form\":\n return Effect.succeed(\n new URLSearchParams(\n Object.entries(body.value).flatMap(([key, value]) =>\n value === undefined ? [] : [[key, normalizeFormValue(value)]],\n ),\n ),\n );\n case \"form-data\":\n return Effect.succeed(body.value);\n }\n};\n\nconst makeRequest = (url: string, options: PutioRequestOptions, authorization?: string) =>\n Effect.gen(function* () {\n const headers = new Headers(options.headers);\n\n const body = options.body ?? { type: \"none\" as const };\n headers.set(\"accept\", \"application/json\");\n\n if (authorization) {\n headers.set(\"authorization\", authorization);\n }\n\n if (body.type === \"json\" && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n return {\n body: yield* withBody(body),\n headers,\n method: options.method,\n url,\n };\n });\n\nconst executeRequest = (options: PutioRequestOptions) =>\n Effect.gen(function* () {\n const config = yield* PutioSdkConfig;\n const httpClient = yield* PutioHttpClient;\n const authorization = yield* resolveAuthorization(config, options.auth);\n const url = yield* Effect.try({\n try: () =>\n buildPutioUrl(\n options.baseUrl ?? config.baseUrl ?? DEFAULT_PUTIO_API_BASE_URL,\n options.path,\n options.query,\n ),\n catch: mapUrlBuildError,\n });\n const request = yield* makeRequest(url, options, authorization);\n\n return yield* httpClient.execute(request);\n });\n\nexport const requestJson = <S extends Schema.Top>(\n schema: S,\n options: PutioRequestOptions,\n): Effect.Effect<S[\"Type\"], PutioSdkError, PutioSdkContext | S[\"DecodingServices\"]> =>\n executeRequest(options).pipe(\n Effect.flatMap((response) =>\n isSuccessStatus(response.status)\n ? decodeSuccessJson(schema, response)\n : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail)),\n ),\n );\n\nexport const selectJsonField =\n <K extends string>(field: K) =>\n <A extends { readonly [P in K]: unknown }, E, R>(\n effect: Effect.Effect<A, E, R>,\n ): Effect.Effect<A[K], E, R> =>\n effect.pipe(Effect.map((value) => value[field]));\n\nexport const selectJsonFields =\n <const K extends readonly string[]>(...fields: K) =>\n <A extends { readonly [P in K[number]]: unknown }, E, R>(\n effect: Effect.Effect<A, E, R>,\n ): Effect.Effect<Pick<A, K[number]>, E, R> =>\n effect.pipe(\n Effect.map(\n (value) =>\n Object.fromEntries(fields.map((field) => [field, value[field as K[number]]])) as Pick<\n A,\n K[number]\n >,\n ),\n );\n\nexport const requestArrayBuffer = (\n options: PutioRequestOptions,\n): Effect.Effect<Uint8Array, PutioSdkError, PutioSdkContext> =>\n executeRequest(options).pipe(\n Effect.flatMap((response) =>\n isSuccessStatus(response.status)\n ? response.arrayBuffer.pipe(\n Effect.mapError(mapTransportError),\n Effect.map((buffer) => new Uint8Array(buffer)),\n )\n : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail)),\n ),\n );\n\nexport const requestVoid = (\n options: PutioRequestOptions,\n): Effect.Effect<void, PutioSdkError, PutioSdkContext> =>\n executeRequest(options).pipe(\n Effect.flatMap((response) =>\n isSuccessStatus(response.status)\n ? Effect.void\n : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail)),\n ),\n );\n","type CsvValue = string | number;\n\nexport interface CursorSelectionInput<TValue extends CsvValue = number> {\n readonly cursor?: string;\n readonly excludeIds?: ReadonlyArray<TValue>;\n readonly ids?: ReadonlyArray<TValue>;\n}\n\nexport const joinCsv = <TValue extends CsvValue>(\n values: ReadonlyArray<TValue> | undefined,\n): string | undefined => (values && values.length > 0 ? values.join(\",\") : undefined);\n\nexport const toCursorSelectionForm = <\n TValue extends CsvValue,\n const TIdsFieldName extends string = \"file_ids\",\n>(\n selection: CursorSelectionInput<TValue>,\n idsFieldName?: TIdsFieldName,\n): {\n readonly cursor?: string;\n readonly exclude_ids?: string;\n} & Record<TIdsFieldName, string | undefined> => {\n const resolvedIdsFieldName = (idsFieldName ?? \"file_ids\") as TIdsFieldName;\n\n return {\n cursor: selection.cursor,\n exclude_ids: joinCsv(selection.excludeIds),\n [resolvedIdsFieldName]: joinCsv(selection.ids),\n } as {\n readonly cursor?: string;\n readonly exclude_ids?: string;\n } & Record<TIdsFieldName, string | undefined>;\n};\n"],"mappings":";;AAEA,MAAa,2BAA2B,OAAO,OAAO;CACpD,eAAe,OAAO,SAAS,OAAO,OAAO;CAC7C,YAAY,OAAO,SAAS,OAAO,OAAO;CAC1C,aAAa,OAAO,SAAS,OAAO,IAAI;CACxC,SAAS,OAAO,SAAS,OAAO,QAAQ;CACzC,CAAC;AA6EF,MAAM,wBACJ,UACA,UACqE;AACrE,KAAI,SAAS,cAAc,KAAA,GAAW;AACpC,MAAI,MAAM,KAAK,eAAe,SAAS,UACrC,QAAO;AAGT,SAAO,SAAS,eAAe,KAAA,KAAa,MAAM,WAAW,SAAS;;AAGxE,KAAI,SAAS,eAAe,KAAA,EAC1B,QAAO,MAAM,WAAW,SAAS;AAGnC,QAAO;;AAGT,MAAM,uBAAuB,UAC3B,MAAM,SAAS,mBAAmB,MAAM,SAAS;AAEnD,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,UAAU;AAEzC,MAAM,qBAAqB,QAA2C,QACpE,EAAE,OAAO,WAAW,OAAO,SAAS,KAAA,KAAa,OAAO,OAAO,SAAS;AAE1E,MAAM,sBAAsB,QAA2C,QACrE,EAAE,OAAO,WACT,OAAO,SAAS,KAAA,KACf,OAAO,OAAO,SAAS,YAAY,OAAO,UAAU,OAAO,KAAK;AAEnE,MAAM,iCAAiC,UACrC,SAAS,MAAM,KACd,OAAO,MAAM,cAAc,YAAY,OAAO,MAAM,eAAe,aACpE,kBAAkB,OAAO,YAAY,IACrC,mBAAmB,OAAO,aAAa;AAEzC,MAAM,qBACJ,UACyE;AACzE,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO;AAGT,KAAI,MAAM,SAAS,aACjB,QAAO,OAAO,MAAM,cAAc;AAGpC,KAAI,MAAM,SAAS,cACjB,QAAO,OAAO,MAAM,eAAe;AAGrC,QAAO;;AAST,SAAS,kBACP,UAC6D;AAC7D,KAAI,SAAS,cAAc,KAAA,EACzB,QAAO;EACL,MAAM;EACN,WAAW,SAAS;EACrB;AAGH,QAAO;EACL,MAAM;EACN,YAAY,SAAS;EACtB;;AAGH,IAAa,sBAAb,cAAyC,KAAK,YAAY,sBAAsB,CAE7E;AAEH,IAAa,0BAAb,cAA6C,KAAK,YAAY,0BAA0B,CAErF;AAEH,IAAa,uBAAb,cAA0C,KAAK,YAAY,uBAAuB,CAE/E;AAEH,MAAM,2BAA2B;CAC/B,QAAQ,OAAO;CACf,MAAM;CACP;AAED,IAAa,gBAAb,cAAmC,OAAO,kBAAiC,CAAC,iBAAiB,EAC3F,GAAG,0BACJ,CAAC,CAAC;AAEH,IAAa,iBAAb,cAAoC,OAAO,kBAAkC,CAAC,kBAAkB,EAC9F,GAAG,0BACJ,CAAC,CAAC;AAEH,IAAa,sBAAb,cAAyC,OAAO,kBAAuC,CACrF,uBACA;CACE,GAAG;CACH,QAAQ,OAAO,SAAS,OAAO,OAAO;CACtC,IAAI,OAAO,SAAS,OAAO,OAAO;CAClC,OAAO,OAAO,SAAS,OAAO,OAAO;CACrC,WAAW,OAAO,SAAS,OAAO,OAAO;CACzC,YAAY,OAAO,SAAS,OAAO,OAAO;CAC1C,OAAO,OAAO,SAAS,OAAO,OAAO;CACtC,CACF,CAAC;AAEF,IAAa,sBAAb,cAIU,KAAK,YAAY,sBAAsB,CAO9C;AA+BH,MAAa,iCAKX,SACG;AAEL,MAAa,2BAA2B,OAAO,oBAAoB,yBAAyB;AAE5F,MAAa,wBAAwB,UACnC,SAAS,MAAM,IACf,kBAAkB,OAAO,gBAAgB,IACzC,kBAAkB,OAAO,aAAa,IACtC,mBAAmB,OAAO,cAAc;AAE1C,MAAM,oBACJ,OACA,QAMA,SAAS,MAAM,IACf,MAAM,SAAS,OACf,OAAO,MAAM,WAAW,YACxB,qBAAqB,MAAM,KAAK;AAElC,MAAa,mBAAmB,UAC9B,iBAAiB,OAAO,gBAAgB;AAE1C,MAAa,oBAAoB,UAC/B,iBAAiB,OAAO,iBAAiB;AAE3C,MAAa,yBAAyB,UACpC,iBAAiB,OAAO,sBAAsB,IAC9C,SAAS,MAAM,IACf,kBAAkB,OAAO,SAAS,IAClC,kBAAkB,OAAO,KAAK,IAC9B,kBAAkB,OAAO,QAAQ,IACjC,kBAAkB,OAAO,YAAY,IACrC,kBAAkB,OAAO,aAAa,IACtC,kBAAkB,OAAO,QAAQ;AAEnC,MAAa,yBAAyB,UACpC,SAAS,MAAM,IACf,MAAM,SAAS,yBACf,qBAAqB,MAAM,KAAK,IAChC,8BAA8B,MAAM,SAAS,IAC7C,OAAO,MAAM,WAAW,YACxB,OAAO,MAAM,cAAc,YAC3B,kBAAkB,MAAM,OAAO,IAC/B,OAAO,MAAM,WAAW;AAE1B,MAAa,8BAA8B,YAAwC;CACjF,eAAe,yCAAyC;CACxD,aAAa;CACd;AAED,MAAM,aAAa,SAAkB,SACnC,QAAQ,IAAI,KAAK,IAAI,KAAA;AAEvB,MAAa,4BAA4B,aAAsB;CAC7D,QAAQ,UAAU,SAAS,qBAAqB;CAChD,IAAI,UAAU,SAAS,iBAAiB;CACxC,OAAO,UAAU,SAAS,oBAAoB;CAC9C,WAAW,UAAU,SAAS,wBAAwB;CACtD,YAAY,UAAU,SAAS,cAAc;CAC7C,OAAO,UAAU,SAAS,oBAAoB;CAC/C;AAED,MAAa,mCAAmC,UAC9C,IAAI,qBAAqB,EAAE,OAAO,CAAC;AAErC,MAAa,yBAAyB,UAAmB,IAAI,wBAAwB,EAAE,OAAO,CAAC;AAE/F,MAAa,qBAAqB,UAAmB,IAAI,oBAAoB,EAAE,OAAO,CAAC;AAEvF,MAAa,qBACX,QACA,SACA,SACkB;AAClB,KAAI,WAAW,IACb,QAAO,IAAI,oBAAoB;EAC7B;EACA;EACA,GAAG,yBAAyB,QAAQ;EACrC,CAAC;AAGJ,KAAI,WAAW,OAAO,WAAW,IAC/B,QAAO,IAAI,eAAe;EAAE;EAAQ;EAAM,CAAC;AAG7C,QAAO,IAAI,cAAc;EAAE;EAAQ;EAAM,CAAC;;AAG5C,MAAa,kBAAkB,QAAgB,SAC7C,yBAAyB,KAAK,CAAC,KAC7B,OAAO,oBAAoB,2BAA2B,OAAO,CAAC,CAC/D;AAwCH,SAAgB,oBAQd,cACA,WAuBK;AACL,KAAI,cAAc,KAAA,GAAW;EAC3B,MAAM,OAAO;AAEb,UAA0C,WACxC,oBAAoB,QAAQ,KAAK;;CAGrC,MAAM,SAAS;CACf,MAAM,OAAO;AAEb,QAAO,OAAO,KACZ,OAAO,UAAU,UAAU;AACzB,MAAI,CAAC,oBAAoB,MAAM,CAC7B,QAAO;EAGT,MAAM,WAAW,KAAK,YAAY,MAAM,cAAc,qBAAqB,WAAW,MAAM,CAAC;AAE7F,MAAI,CAAC,SACH,QAAO;AAGT,SAAO,IAAI,oBAAoB;GAC7B,MAAM,MAAM;GAGZ;GACA,QAAQ,KAAK;GACb,WAAW,KAAK;GAChB,QAAQ,kBAAkB,SAAS;GACnC,QAAQ,MAAM;GACf,CAAC;GACF,CACH;;;;ACncH,MAAa,6BAA6B;AAC1C,MAAa,gCAAgC;AAC7C,MAAa,4BAA4B;;;AC6BzC,IAAa,iBAAb,cAAoC,QAAQ,SAA8C,CACxF,iBACD,CAAC;AAoBF,IAAa,kBAAb,cAAqC,QAAQ,SAAgD,CAC3F,kBACD,CAAC;AAIF,MAAa,sBAAsB,YAAsD;CACvF,aAAa,OAAO;CACpB,SAAS,OAAO,WAAA;CAChB,eAAe,OAAO,iBAAA;CACtB,WAAW,OAAO,aAAA;CACnB;AAED,MAAa,qBAAqB,WAChC,MAAM,QAAQ,gBAAgB,mBAAmB,OAAO,CAAC;AAE3D,MAAa,yBAAyB,WACpC,MAAM,SAAS,kBAAkB,OAAO,EAAE,qBAAqB,CAAC;AAElE,MAAa,uBACX,sBAA+C,WAAW,UACvD,MAAM,QAAQ,iBAAiB,qBAAqB,oBAAoB,CAAC;AAE9E,MAAa,wBACX,sBAA+C,WAAW,WAChC,EAC1B,UAAU,YACR,OAAO,WAAW;CAChB,KAAK,OAAO,WAAW;EACrB,MAAM,WAAW,MAAM,oBAAoB,QAAQ,KAAK;GACtD,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB;GACD,CAAC;AAEF,SAAO;GACL,aAAa,OAAO,WAAW;IAC7B,WAAW,SAAS,aAAa;IACjC,OAAO;IACR,CAAC;GACF,SAAS,SAAS;GAClB,MAAM,OAAO,WAAW;IACtB,WAAW,SAAS,MAAM;IAC1B,OAAO;IACR,CAAC;GACF,QAAQ,SAAS;GAClB;;CAEH,OAAO;CACR,CAAC,EACL;AAED,MAAa,qBAAqB,UAChC,mBAAmB,OAAO,MAAM,CAAC;AAEnC,MAAM,qBAAqB;AAE3B,MAAM,oBAAoB,SAAyB;AACjD,KAAI,mBAAmB,KAAK,KAAK,CAC/B,OAAM,sBAAsB,mEAAmE;AAGjG,QAAO,KAAK,WAAW,IAAI,GAAG,OAAO,IAAI;;AAG3C,MAAa,iBAAiB,SAAuB,MAAc,UAA+B;CAChG,MAAM,MAAM,IAAI,IAAI,iBAAiB,KAAK,EAAE,QAAQ;AAEpD,KAAI;OACG,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,CAC9C,KAAI,UAAU,KAAA,KAAa,UAAU,KACnC,KAAI,aAAa,IAAI,KAAK,OAAO,MAAM,CAAC;;AAK9C,QAAO,IAAI,UAAU;;AAGvB,MAAM,oBAAoB,UACxB,iBAAiB,0BAA0B,QAAQ,sBAAsB,MAAM;AAEjF,MAAa,mBAAmB,OAAO,OAAO,EAC5C,QAAQ,OAAO,QAAQ,KAAK,EAC7B,CAAC;AA0BF,MAAM,mBAAmB,WAAmB,UAAU,OAAO,SAAS;AAEtE,MAAM,qBAA2C,QAAW,aAC1D,SAAS,KAAK,KACZ,OAAO,QAAQ,OAAO,oBAAoB,OAAO,CAAC,EAClD,OAAO,SAAS,gCAAgC,CACjD;AAEH,MAAM,iBAAiB,UAA6B,YAClD,SAAS,KAAK,KACZ,OAAO,SAAS,SAAS,eAAe,SAAS,QAAQ,KAAK,CAAC,EAC/D,OAAO,oBAAoB,2BAA2B,SAAS,OAAO,CAAC,EACvE,OAAO,KAAK,SAAS,kBAAkB,SAAS,QAAQ,SAAS,KAAK,CAAC,CACxE;AAEH,MAAM,wBAAwB,UAAkB,aAAqB;AACnE,KAAI,OAAO,WAAW,SAAS,WAC7B,QAAO,SAAS,WAAW,KAAK,GAAG,SAAS,GAAG,WAAW;AAG5D,OAAM,sBACJ,+EACD;;AAGH,MAAM,wBACJ,QACA,SACqD;CACrD,MAAM,eAAe,QAAQ,EAAE,MAAM,gBAAyB;AAE9D,SAAQ,aAAa,MAArB;EACE,KAAK,OACH,QAAO,OAAO,QAAQ,KAAA,EAAU;EAClC,KAAK,QACH,QAAO,OAAO,QAAQ,SAAS,aAAa,QAAQ;EACtD,KAAK,QACH,QAAO,OAAO,IAAI;GAChB,WAAW,qBAAqB,aAAa,UAAU,aAAa,SAAS;GAC7E,OAAO;GACR,CAAC;EACJ,KAAK;AACH,OAAI,CAAC,OAAO,YACV,QAAO,OAAO,KACZ,sBACE,oFACD,CACF;AAGH,UAAO,OAAO,QAAQ,SAAS,OAAO,cAAc;;;AAI1D,MAAM,sBAAsB,UAA2B;AACrD,KAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B,QAAO;AAGT,KAAI,OAAO,UAAU,SACnB,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAChD,QAAO,OAAO,MAAM;AAGtB,QAAO,KAAK,UAAU,MAAM;;AAG9B,MAAM,YAAY,SAA+E;AAC/F,SAAQ,KAAK,MAAb;EACE,KAAK,OACH,QAAO,OAAO,QAAQ,KAAA,EAAU;EAClC,KAAK,OACH,QAAO,OAAO,IAAI;GAChB,WAAW,KAAK,UAAU,KAAK,MAAM;GACrC,OAAO;GACR,CAAC;EACJ,KAAK,OACH,QAAO,OAAO,QACZ,IAAI,gBACF,OAAO,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,KAAK,WACxC,UAAU,KAAA,IAAY,EAAE,GAAG,CAAC,CAAC,KAAK,mBAAmB,MAAM,CAAC,CAAC,CAC9D,CACF,CACF;EACH,KAAK,YACH,QAAO,OAAO,QAAQ,KAAK,MAAM;;;AAIvC,MAAM,eAAe,KAAa,SAA8B,kBAC9D,OAAO,IAAI,aAAa;CACtB,MAAM,UAAU,IAAI,QAAQ,QAAQ,QAAQ;CAE5C,MAAM,OAAO,QAAQ,QAAQ,EAAE,MAAM,QAAiB;AACtD,SAAQ,IAAI,UAAU,mBAAmB;AAEzC,KAAI,cACF,SAAQ,IAAI,iBAAiB,cAAc;AAG7C,KAAI,KAAK,SAAS,UAAU,CAAC,QAAQ,IAAI,eAAe,CACtD,SAAQ,IAAI,gBAAgB,mBAAmB;AAGjD,QAAO;EACL,MAAM,OAAO,SAAS,KAAK;EAC3B;EACA,QAAQ,QAAQ;EAChB;EACD;EACD;AAEJ,MAAM,kBAAkB,YACtB,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,aAAa,OAAO;CAC1B,MAAM,gBAAgB,OAAO,qBAAqB,QAAQ,QAAQ,KAAK;CAUvE,MAAM,UAAU,OAAO,YAAY,OAThB,OAAO,IAAI;EAC5B,WACE,cACE,QAAQ,WAAW,OAAO,WAAA,sBAC1B,QAAQ,MACR,QAAQ,MACT;EACH,OAAO;EACR,CAAC,EACsC,SAAS,cAAc;AAE/D,QAAO,OAAO,WAAW,QAAQ,QAAQ;EACzC;AAEJ,MAAa,eACX,QACA,YAEA,eAAe,QAAQ,CAAC,KACtB,OAAO,SAAS,aACd,gBAAgB,SAAS,OAAO,GAC5B,kBAAkB,QAAQ,SAAS,GACnC,cAAc,UAAU,SAAS,QAAQ,CAAC,KAAK,OAAO,QAAQ,OAAO,KAAK,CAAC,CAChF,CACF;AAEH,MAAa,mBACQ,WAEjB,WAEA,OAAO,KAAK,OAAO,KAAK,UAAU,MAAM,OAAO,CAAC;AAEpD,MAAa,oBACyB,GAAG,YAErC,WAEA,OAAO,KACL,OAAO,KACJ,UACC,OAAO,YAAY,OAAO,KAAK,UAAU,CAAC,OAAO,MAAM,OAAoB,CAAC,CAAC,CAIhF,CACF;AAEL,MAAa,sBACX,YAEA,eAAe,QAAQ,CAAC,KACtB,OAAO,SAAS,aACd,gBAAgB,SAAS,OAAO,GAC5B,SAAS,YAAY,KACnB,OAAO,SAAS,kBAAkB,EAClC,OAAO,KAAK,WAAW,IAAI,WAAW,OAAO,CAAC,CAC/C,GACD,cAAc,UAAU,SAAS,QAAQ,CAAC,KAAK,OAAO,QAAQ,OAAO,KAAK,CAAC,CAChF,CACF;AAEH,MAAa,eACX,YAEA,eAAe,QAAQ,CAAC,KACtB,OAAO,SAAS,aACd,gBAAgB,SAAS,OAAO,GAC5B,OAAO,OACP,cAAc,UAAU,SAAS,QAAQ,CAAC,KAAK,OAAO,QAAQ,OAAO,KAAK,CAAC,CAChF,CACF;;;AC3VH,MAAa,WACX,WACwB,UAAU,OAAO,SAAS,IAAI,OAAO,KAAK,IAAI,GAAG,KAAA;AAE3E,MAAa,yBAIX,WACA,iBAI+C;CAC/C,MAAM,uBAAwB,gBAAgB;AAE9C,QAAO;EACL,QAAQ,UAAU;EAClB,aAAa,QAAQ,UAAU,WAAW;GACzC,uBAAuB,QAAQ,UAAU,IAAI;EAC/C"}
|