@putdotio/sdk 9.0.0 → 9.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/README.md CHANGED
@@ -15,32 +15,58 @@
15
15
  <p>
16
16
  <a href="https://github.com/putdotio/putio-sdk-typescript/actions/workflows/ci.yml?query=branch%3Amain" style="text-decoration:none;"><img src="https://img.shields.io/github/actions/workflow/status/putdotio/putio-sdk-typescript/ci.yml?branch=main&style=flat&label=ci&colorA=000000&colorB=000000" alt="CI"></a>
17
17
  <a href="https://www.npmjs.com/package/@putdotio/sdk" style="text-decoration:none;"><img src="https://img.shields.io/npm/v/%40putdotio%2Fsdk?style=flat&colorA=000000&colorB=000000" alt="npm version"></a>
18
- <a href="https://www.npmjs.com/package/@putdotio/sdk" style="text-decoration:none;"><img src="https://img.shields.io/npm/dm/%40putdotio%2Fsdk?style=flat&colorA=000000&colorB=000000" alt="npm downloads"></a>
18
+ <a href="https://bundlephobia.com/package/@putdotio/sdk" style="text-decoration:none;"><img src="https://img.shields.io/bundlephobia/minzip/%40putdotio%2Fsdk?style=flat&label=bundle%20size&colorA=000000&colorB=000000" alt="bundle size"></a>
19
19
  <a href="https://github.com/putdotio/putio-sdk-typescript/blob/main/LICENSE" style="text-decoration:none;"><img src="https://img.shields.io/github/license/putdotio/putio-sdk-typescript?style=flat&colorA=000000&colorB=000000" alt="license"></a>
20
20
  </p>
21
21
  </div>
22
22
 
23
23
  ## Installation
24
24
 
25
+ Install with npm:
26
+
25
27
  ```bash
26
- pnpm install @putdotio/sdk
28
+ npm install @putdotio/sdk
29
+ ```
30
+
31
+ ## Utilities
32
+
33
+ Shared formatting, URL, and error-localization helpers are available from the utilities subpath:
34
+
35
+ ```ts
36
+ import {
37
+ FileURLProvider,
38
+ secondsToReadableDuration,
39
+ toHumanFileSize,
40
+ } from "@putdotio/sdk/utilities";
41
+ ```
42
+
43
+ ```ts
44
+ const size = toHumanFileSize(1_572_864);
45
+ const duration = secondsToReadableDuration(444);
27
46
  ```
28
47
 
29
- ## Promise Example
48
+ ## Quick Start
30
49
 
31
50
  ```ts
32
51
  import { createPutioSdkPromiseClient } from "@putdotio/sdk";
33
52
 
34
53
  const sdk = createPutioSdkPromiseClient({
35
- accessToken: process.env.PUTIO_TOKEN_FIRST_PARTY,
54
+ accessToken: process.env.PUTIO_TOKEN,
36
55
  });
37
56
 
38
- const info = await sdk.account.getInfo({
57
+ const account = await sdk.account.getInfo({
39
58
  download_token: 1,
40
- pas: 1,
41
59
  });
42
60
  ```
43
61
 
62
+ The SDK can also be created without a default token:
63
+
64
+ ```ts
65
+ const sdk = createPutioSdkPromiseClient();
66
+
67
+ const validation = await sdk.auth.validateToken(process.env.PUTIO_TOKEN!);
68
+ ```
69
+
44
70
  ## Effect Example
45
71
 
46
72
  ```ts
@@ -57,7 +83,7 @@ const program = sdk.files
57
83
  .pipe(
58
84
  Effect.provide(
59
85
  makePutioSdkLayer({
60
- accessToken: process.env.PUTIO_TOKEN_FIRST_PARTY!,
86
+ accessToken: process.env.PUTIO_TOKEN!,
61
87
  }),
62
88
  ),
63
89
  );
@@ -86,8 +112,13 @@ Choose the Effect client when you want the canonical typed error channel and Eff
86
112
 
87
113
  Effect is the canonical typed surface. The Promise client is an adapter for environments that want standard async functions.
88
114
 
115
+ - SDK creation does not require an access token
116
+ - Authenticated endpoints need a token through client config or the Effect layer config
89
117
  - Effect client: keeps errors in the Effect error channel with operation-specific typing
90
118
  - Promise client: throws tagged SDK error objects such as `PutioOperationError`, `PutioApiError`, and `PutioRateLimitError`
119
+ - Promise client: owns a managed Effect runtime and exposes `dispose()` for explicit teardown
120
+
121
+ If you create a long-lived Promise client in a script, test harness, or server integration, call `await sdk.dispose()` during teardown.
91
122
 
92
123
  ## Namespace Surface
93
124
 
@@ -110,6 +141,7 @@ Effect is the canonical typed surface. The Promise client is an adapter for envi
110
141
  | `transfers` | transfer list, add/retry/cancel/clean flows |
111
142
  | `trash` | trash listing, restore, delete, empty |
112
143
  | `tunnel` | route listing |
144
+ | `utilities` | file URLs, localized errors, and shared formatting helpers |
113
145
  | `zips` | zip creation and lookup |
114
146
 
115
147
  ## Design Rules
@@ -146,7 +178,7 @@ import {
146
178
  } from "@putdotio/sdk";
147
179
 
148
180
  const sdk = createPutioSdkPromiseClient({
149
- accessToken: process.env.PUTIO_TOKEN_FIRST_PARTY,
181
+ accessToken: process.env.PUTIO_TOKEN,
150
182
  });
151
183
 
152
184
  try {
@@ -190,7 +222,7 @@ const handled = sdk.files
190
222
  }),
191
223
  Effect.provide(
192
224
  makePutioSdkLayer({
193
- accessToken: process.env.PUTIO_TOKEN_FIRST_PARTY!,
225
+ accessToken: process.env.PUTIO_TOKEN!,
194
226
  }),
195
227
  ),
196
228
  );
@@ -252,7 +284,9 @@ export const useFiles = (parentId: number) =>
252
284
  });
253
285
  ```
254
286
 
255
- ## Verification
287
+ ## Repo Verification
288
+
289
+ If you are working on the SDK itself, repo-local verification uses `vp`:
256
290
 
257
291
  Local checks:
258
292
 
@@ -270,17 +304,12 @@ Live verification:
270
304
  vp run test:live
271
305
  ```
272
306
 
273
- Custom package scripts:
307
+ Repo scripts:
274
308
 
275
309
  ```bash
276
310
  vp run verify
277
311
  vp run bootstrap:tokens
278
312
  ```
279
313
 
280
- ## Release Flow
281
-
282
- Pushes to `main` verify the repo and then run `semantic-release`.
283
- Add `NPM_TOKEN` in GitHub secrets and use conventional commits to drive version bumps.
284
-
285
- Implementation and confidence notes live in `docs/READINESS.md`.
314
+ Implementation notes live in `docs/READINESS.md`.
286
315
  Target-by-target live verification guidance lives in `docs/TESTING.md`.
@@ -0,0 +1,178 @@
1
+ import { Headers, HttpClient, HttpClientRequest, HttpClientResponse } from "@effect/platform";
2
+ import { Context, Data, Effect, Layer, Option, Schema } from "effect";
3
+ //#region src/core/errors.ts
4
+ const PutioErrorEnvelopeSchema = Schema.Struct({
5
+ error_message: Schema.optional(Schema.String),
6
+ error_type: Schema.optional(Schema.String),
7
+ status_code: Schema.optional(Schema.Number.pipe(Schema.int())),
8
+ details: Schema.optional(Schema.Unknown)
9
+ });
10
+ const isKnownContractMatch = (contract, error) => {
11
+ if (contract.errorType !== void 0) return error.body.error_type === contract.errorType;
12
+ if (contract.statusCode !== void 0) return error.status === contract.statusCode;
13
+ return false;
14
+ };
15
+ const isMatchableApiError = (error) => error._tag === "PutioApiError" || error._tag === "PutioAuthError";
16
+ function toOperationReason(contract) {
17
+ if (contract.errorType !== void 0) return {
18
+ kind: "error_type",
19
+ errorType: contract.errorType
20
+ };
21
+ return {
22
+ kind: "status_code",
23
+ statusCode: contract.statusCode
24
+ };
25
+ }
26
+ var PutioTransportError = class extends Data.TaggedError("PutioTransportError") {};
27
+ var PutioConfigurationError = class extends Data.TaggedError("PutioConfigurationError") {};
28
+ var PutioValidationError = class extends Data.TaggedError("PutioValidationError") {};
29
+ var PutioApiError = class extends Data.TaggedError("PutioApiError") {};
30
+ var PutioAuthError = class extends Data.TaggedError("PutioAuthError") {};
31
+ var PutioRateLimitError = class extends Data.TaggedError("PutioRateLimitError") {};
32
+ var PutioOperationError = class extends Data.TaggedError("PutioOperationError") {};
33
+ const definePutioOperationErrorSpec = (spec) => spec;
34
+ const decodePutioErrorEnvelope = Schema.decodeUnknown(PutioErrorEnvelopeSchema);
35
+ const fallbackPutioErrorEnvelope = (status) => ({
36
+ error_message: `put.io API request failed with status ${status}`,
37
+ status_code: status
38
+ });
39
+ const responseRateLimitHeaders = (headers) => ({
40
+ action: Option.getOrUndefined(Headers.get(headers, "x-ratelimit-action")),
41
+ id: Option.getOrUndefined(Headers.get(headers, "x-ratelimit-id")),
42
+ limit: Option.getOrUndefined(Headers.get(headers, "x-ratelimit-limit")),
43
+ remaining: Option.getOrUndefined(Headers.get(headers, "x-ratelimit-remaining")),
44
+ retryAfter: Option.getOrUndefined(Headers.get(headers, "retry-after")),
45
+ reset: Option.getOrUndefined(Headers.get(headers, "x-ratelimit-reset"))
46
+ });
47
+ const mapDecodeErrorToValidationError = (cause) => new PutioValidationError({ cause });
48
+ const mapConfigurationError = (cause) => new PutioConfigurationError({ cause });
49
+ const mapTransportError = (cause) => new PutioTransportError({ cause });
50
+ const makeResponseError = (status, headers, body) => {
51
+ if (status === 429) return new PutioRateLimitError({
52
+ status,
53
+ body,
54
+ ...responseRateLimitHeaders(headers)
55
+ });
56
+ if (status === 401 || status === 403) return new PutioAuthError({
57
+ status,
58
+ body
59
+ });
60
+ return new PutioApiError({
61
+ status,
62
+ body
63
+ });
64
+ };
65
+ const parseErrorBody = (status, json) => decodePutioErrorEnvelope(json).pipe(Effect.orElseSucceed(() => fallbackPutioErrorEnvelope(status)));
66
+ function withOperationErrors(effectOrSpec, maybeSpec) {
67
+ if (maybeSpec === void 0) {
68
+ const spec = effectOrSpec;
69
+ return (effect) => withOperationErrors(effect, spec);
70
+ }
71
+ const effect = effectOrSpec;
72
+ const spec = maybeSpec;
73
+ return effect.pipe(Effect.mapError((error) => {
74
+ if (!isMatchableApiError(error)) return error;
75
+ const contract = spec.knownErrors.find((candidate) => isKnownContractMatch(candidate, error));
76
+ if (!contract) return error;
77
+ return new PutioOperationError({
78
+ body: error.body,
79
+ contract,
80
+ domain: spec.domain,
81
+ operation: spec.operation,
82
+ reason: toOperationReason(contract),
83
+ status: error.status
84
+ });
85
+ }));
86
+ }
87
+ //#endregion
88
+ //#region src/core/defaults.ts
89
+ const DEFAULT_PUTIO_API_BASE_URL = "https://api.put.io";
90
+ const DEFAULT_PUTIO_UPLOAD_BASE_URL = "https://upload.put.io";
91
+ const DEFAULT_PUTIO_WEB_APP_URL = "https://app.put.io";
92
+ //#endregion
93
+ //#region src/core/http.ts
94
+ var PutioSdkConfig = class extends Context.Tag("PutioSdkConfig")() {};
95
+ const makePutioSdkConfig = (config) => ({
96
+ accessToken: config.accessToken,
97
+ baseUrl: config.baseUrl ?? "https://api.put.io",
98
+ uploadBaseUrl: config.uploadBaseUrl ?? "https://upload.put.io",
99
+ webAppUrl: config.webAppUrl ?? "https://app.put.io"
100
+ });
101
+ const makePutioSdkLayer = (config) => Layer.succeed(PutioSdkConfig, makePutioSdkConfig(config));
102
+ const buildPutioUrl = (baseUrl, path, query) => {
103
+ const url = new URL(path, baseUrl);
104
+ if (query) {
105
+ for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) url.searchParams.set(key, String(value));
106
+ }
107
+ return url.toString();
108
+ };
109
+ const OkResponseSchema = Schema.Struct({ status: Schema.Literal("OK") });
110
+ const isSuccessStatus = (status) => status >= 200 && status < 300;
111
+ const decodeSuccessJson = (schema, response) => HttpClientResponse.schemaBodyJson(schema)(response).pipe(Effect.mapError(mapDecodeErrorToValidationError));
112
+ 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)));
113
+ const toBasicAuthorization = (username, password) => {
114
+ if (typeof globalThis.btoa === "function") return `Basic ${globalThis.btoa(`${username}:${password}`)}`;
115
+ throw mapConfigurationError("This runtime does not provide btoa(), so Basic auth cannot be encoded safely");
116
+ };
117
+ const resolveAuthorization = (config, auth) => {
118
+ const resolvedAuth = auth ?? { type: "config-token" };
119
+ switch (resolvedAuth.type) {
120
+ case "none": return Effect.succeed(void 0);
121
+ case "token": return Effect.succeed(`Token ${resolvedAuth.token}`);
122
+ case "basic": return Effect.try({
123
+ try: () => toBasicAuthorization(resolvedAuth.username, resolvedAuth.password),
124
+ catch: mapConfigurationError
125
+ });
126
+ case "config-token":
127
+ if (!config.accessToken) return Effect.fail(mapConfigurationError("This endpoint requires an access token, but PutioSdkConfig.accessToken is missing"));
128
+ return Effect.succeed(`Token ${config.accessToken}`);
129
+ }
130
+ };
131
+ const normalizeFormValue = (value) => {
132
+ if (value === null || value === void 0) return "";
133
+ if (typeof value === "string") return value;
134
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
135
+ return JSON.stringify(value);
136
+ };
137
+ const withBody = (request, body) => {
138
+ switch (body.type) {
139
+ case "none": return Effect.succeed(request);
140
+ case "json": return HttpClientRequest.bodyJson(request, body.value).pipe(Effect.mapError(mapDecodeErrorToValidationError));
141
+ case "form": return Effect.succeed(HttpClientRequest.bodyUrlParams(request, Object.fromEntries(Object.entries(body.value).flatMap(([key, value]) => value === void 0 ? [] : [[key, normalizeFormValue(value)]]))));
142
+ case "form-data": return Effect.succeed(HttpClientRequest.bodyFormData(request, body.value));
143
+ }
144
+ };
145
+ const makeRequest = (url, options, authorization) => Effect.gen(function* () {
146
+ const headers = authorization ? Headers.set(Headers.fromInput(options.headers), "authorization", authorization) : Headers.fromInput(options.headers);
147
+ const body = options.body ?? { type: "none" };
148
+ return yield* withBody(HttpClientRequest.make(options.method)(url, {
149
+ acceptJson: true,
150
+ headers
151
+ }), body);
152
+ });
153
+ const executeRequest = (options) => Effect.gen(function* () {
154
+ const config = yield* PutioSdkConfig;
155
+ const authorization = yield* resolveAuthorization(config, options.auth);
156
+ const request = yield* makeRequest(buildPutioUrl(options.baseUrl ?? config.baseUrl ?? "https://api.put.io", options.path, options.query), options, authorization);
157
+ return yield* HttpClient.execute(request).pipe(Effect.mapError(mapTransportError));
158
+ });
159
+ 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))));
160
+ const selectJsonField = (field) => (effect) => effect.pipe(Effect.map((value) => value[field]));
161
+ const selectJsonFields = (...fields) => (effect) => effect.pipe(Effect.map((value) => Object.fromEntries(fields.map((field) => [field, value[field]]))));
162
+ 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))));
163
+ const requestVoid = (options) => executeRequest(options).pipe(Effect.flatMap((response) => isSuccessStatus(response.status) ? Effect.void : decodeFailure(response, response.headers).pipe(Effect.flatMap(Effect.fail))));
164
+ //#endregion
165
+ //#region src/core/forms.ts
166
+ const joinCsv = (values) => values && values.length > 0 ? values.join(",") : void 0;
167
+ const toCursorSelectionForm = (selection, idsFieldName) => {
168
+ const resolvedIdsFieldName = idsFieldName ?? "file_ids";
169
+ return {
170
+ cursor: selection.cursor,
171
+ exclude_ids: joinCsv(selection.excludeIds),
172
+ [resolvedIdsFieldName]: joinCsv(selection.ids)
173
+ };
174
+ };
175
+ //#endregion
176
+ export { mapTransportError as A, PutioValidationError as C, makeResponseError as D, fallbackPutioErrorEnvelope as E, responseRateLimitHeaders as M, withOperationErrors as N, mapConfigurationError as O, PutioTransportError as S, definePutioOperationErrorSpec as T, PutioAuthError as _, buildPutioUrl as a, PutioOperationError as b, requestArrayBuffer as c, selectJsonField as d, selectJsonFields as f, PutioApiError as g, DEFAULT_PUTIO_WEB_APP_URL as h, PutioSdkConfig as i, parseErrorBody as j, mapDecodeErrorToValidationError as k, requestJson as l, DEFAULT_PUTIO_UPLOAD_BASE_URL as m, toCursorSelectionForm as n, makePutioSdkConfig as o, DEFAULT_PUTIO_API_BASE_URL as p, OkResponseSchema as r, makePutioSdkLayer as s, joinCsv as t, requestVoid as u, PutioConfigurationError as v, decodePutioErrorEnvelope as w, PutioRateLimitError as x, PutioErrorEnvelopeSchema as y };
177
+
178
+ //# sourceMappingURL=forms-DM_sjuyz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms-DM_sjuyz.js","names":[],"sources":["../src/core/errors.ts","../src/core/defaults.ts","../src/core/http.ts","../src/core/forms.ts"],"sourcesContent":["import { Headers } from \"@effect/platform\";\nimport { Data, Effect, Option, 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.Number.pipe(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;\n readonly statusCode?: TStatus;\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> = TSpec[\"knownErrors\"][number];\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\ntype PutioMatchableKnownErrorContract =\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, PutioMatchableKnownErrorContract> => {\n if (contract.errorType !== undefined) {\n return error.body.error_type === contract.errorType;\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\nfunction toOperationReason<TType extends string>(contract: {\n readonly errorType: TType;\n readonly statusCode?: number;\n}): {\n readonly kind: \"error_type\";\n readonly errorType: TType;\n};\nfunction toOperationReason<TStatus extends number>(contract: {\n readonly errorType?: undefined;\n readonly statusCode: TStatus;\n}): {\n readonly kind: \"status_code\";\n readonly statusCode: TStatus;\n};\nfunction toOperationReason(contract: PutioMatchableKnownErrorContract) {\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\nexport class PutioApiError extends Data.TaggedError(\"PutioApiError\")<{\n readonly status: number;\n readonly body: PutioErrorEnvelope;\n}> {}\n\nexport class PutioAuthError extends Data.TaggedError(\"PutioAuthError\")<{\n readonly status: number;\n readonly body: PutioErrorEnvelope;\n}> {}\n\nexport class PutioRateLimitError extends Data.TaggedError(\"PutioRateLimitError\")<{\n readonly status: number;\n readonly body: PutioErrorEnvelope;\n readonly action?: string;\n readonly id?: string;\n readonly limit?: string;\n readonly remaining?: string;\n readonly retryAfter?: string;\n readonly reset?: string;\n}> {}\n\nexport class PutioOperationError<\n TDomain extends string,\n TOperation extends string,\n TContract extends PutioKnownErrorContract,\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 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.decodeUnknown(PutioErrorEnvelopeSchema);\n\nexport const fallbackPutioErrorEnvelope = (status: number): PutioErrorEnvelope => ({\n error_message: `put.io API request failed with status ${status}`,\n status_code: status,\n});\n\nexport const responseRateLimitHeaders = (headers: Headers.Headers) => ({\n action: Option.getOrUndefined(Headers.get(headers, \"x-ratelimit-action\")),\n id: Option.getOrUndefined(Headers.get(headers, \"x-ratelimit-id\")),\n limit: Option.getOrUndefined(Headers.get(headers, \"x-ratelimit-limit\")),\n remaining: Option.getOrUndefined(Headers.get(headers, \"x-ratelimit-remaining\")),\n retryAfter: Option.getOrUndefined(Headers.get(headers, \"retry-after\")),\n reset: Option.getOrUndefined(Headers.get(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.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<A, E | PutioOperationError<TDomain, TOperation, TContracts[number]>, R>;\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<A, E | PutioOperationError<TDomain, TOperation, TContracts[number]>, R>;\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<A, E | PutioOperationError<TDomain, TOperation, TContracts[number]>, R>\n | (<A2, E2 extends PutioSdkError, R2>(\n effect: Effect.Effect<A2, E2, R2>,\n ) => Effect.Effect<A2, E2 | PutioOperationError<TDomain, TOperation, TContracts[number]>, R2>) {\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<TContracts[number]>,\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 { Headers, HttpClient, HttpClientRequest, HttpClientResponse } from \"@effect/platform\";\nimport { 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 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 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.Tag(\"PutioSdkConfig\")<\n PutioSdkConfig,\n PutioSdkConfigShape\n>() {}\n\nexport type PutioSdkContext = PutioSdkConfig | HttpClient.HttpClient;\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 buildPutioUrl = (baseUrl: string | URL, path: string, query?: PutioQuery): string => {\n const url = new URL(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\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 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: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n readonly path: string;\n readonly baseUrl?: string | URL;\n readonly query?: PutioQuery;\n readonly headers?: Headers.Input;\n readonly auth?: PutioAuth;\n readonly body?: PutioRequestBody;\n}\n\nconst isSuccessStatus = (status: number) => status >= 200 && status < 300;\n\nconst decodeSuccessJson = <A, I, R>(\n schema: Schema.Schema<A, I, R>,\n response: HttpClientResponse.HttpClientResponse,\n) =>\n HttpClientResponse.schemaBodyJson(schema)(response).pipe(\n Effect.mapError(mapDecodeErrorToValidationError),\n );\n\nconst decodeFailure = (response: HttpClientResponse.HttpClientResponse, headers: 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 = (\n request: HttpClientRequest.HttpClientRequest,\n body: PutioRequestBody,\n): Effect.Effect<HttpClientRequest.HttpClientRequest, PutioSdkError> => {\n switch (body.type) {\n case \"none\":\n return Effect.succeed(request);\n case \"json\":\n return HttpClientRequest.bodyJson(request, body.value).pipe(\n Effect.mapError(mapDecodeErrorToValidationError),\n );\n case \"form\":\n return Effect.succeed(\n HttpClientRequest.bodyUrlParams(\n request,\n Object.fromEntries(\n Object.entries(body.value).flatMap(([key, value]) =>\n value === undefined ? [] : [[key, normalizeFormValue(value)]],\n ),\n ),\n ),\n );\n case \"form-data\":\n return Effect.succeed(HttpClientRequest.bodyFormData(request, body.value));\n }\n};\n\nconst makeRequest = (url: string, options: PutioRequestOptions, authorization?: string) =>\n Effect.gen(function* () {\n const headers = authorization\n ? Headers.set(Headers.fromInput(options.headers), \"authorization\", authorization)\n : Headers.fromInput(options.headers);\n\n const body = options.body ?? { type: \"none\" as const };\n const request = HttpClientRequest.make(options.method)(url, {\n acceptJson: true,\n headers,\n });\n\n return yield* withBody(request, body);\n });\n\nconst executeRequest = (options: PutioRequestOptions) =>\n Effect.gen(function* () {\n const config = yield* PutioSdkConfig;\n const authorization = yield* resolveAuthorization(config, options.auth);\n const url = buildPutioUrl(\n options.baseUrl ?? config.baseUrl ?? DEFAULT_PUTIO_API_BASE_URL,\n options.path,\n options.query,\n );\n const request = yield* makeRequest(url, options, authorization);\n\n return yield* HttpClient.execute(request).pipe(Effect.mapError(mapTransportError));\n });\n\nexport const requestJson = <A, I, R>(\n schema: Schema.Schema<A, I, R>,\n options: PutioRequestOptions,\n): Effect.Effect<A, PutioSdkError, PutioSdkContext | R> =>\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 Record<K, unknown>, E, R>(effect: Effect.Effect<A, E, R>): 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 Record<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 Pick<A, K[number]>,\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":"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"}