@distilled.cloud/discord 0.0.0 → 1.0.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ import * as Context from "effect/Context";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Layer from "effect/Layer";
4
+ import * as Redacted from "effect/Redacted";
5
+ /**
6
+ * Discord HTTP API base URL. The trailing `/v10` is the API version the spec
7
+ * submodule describes — override via `DISCORD_API_URL` only to point at a
8
+ * proxy, not to change versions (the generated operations are v10-shaped).
9
+ */
10
+ export declare const DEFAULT_API_BASE_URL = "https://discord.com/api/v10";
11
+ /** Authorization header prefix — see the module doc. */
12
+ export type TokenType = "Bot" | "Bearer";
13
+ export interface Config {
14
+ readonly token: Redacted.Redacted<string>;
15
+ readonly tokenType: TokenType;
16
+ readonly apiBaseUrl: string;
17
+ }
18
+ declare const Credentials_base: Context.ServiceClass<Credentials, "DiscordCredentials", Effect.Effect<Config, never, never>>;
19
+ export declare class Credentials extends Credentials_base {
20
+ }
21
+ export declare const CredentialsFromEnv: Layer.Layer<Credentials, never, never>;
22
+ /** Convenience layer from a plain token + optional token type / base URL. */
23
+ export declare const credentials: (config: {
24
+ readonly token: string;
25
+ readonly tokenType?: TokenType;
26
+ readonly apiBaseUrl?: string;
27
+ }) => Layer.Layer<Credentials>;
28
+ export {};
29
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAG5C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAElE,wDAAwD;AACxD,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEzC,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;;AAED,qBAAa,WAAY,SAAQ,gBAGR;CAAG;AAgB5B,eAAO,MAAM,kBAAkB,wCAqB9B,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,WAAW,WAAY;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,KAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAQxB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Discord credentials — hand-written.
3
+ *
4
+ * The `Credentials` service resolves `{ token, tokenType, apiBaseUrl }` per
5
+ * request; the protocol layer formats the `Authorization: <tokenType> <token>`
6
+ * header from it.
7
+ *
8
+ * Discord authorizes HTTP API calls two ways, distinguished by the token
9
+ * prefix (https://discord.com/developers/docs/reference#authentication):
10
+ * • `Bot <token>` — a bot token from the application's Bot page (the
11
+ * default; what almost every server-side integration uses)
12
+ * • `Bearer <token>` — an OAuth2 access token, for calls made on behalf of
13
+ * a user (`/users/@me`, `/users/@me/guilds`, …)
14
+ */
15
+ import * as EffectConfig from "effect/Config";
16
+ import * as Context from "effect/Context";
17
+ import * as Effect from "effect/Effect";
18
+ import * as Layer from "effect/Layer";
19
+ import * as Redacted from "effect/Redacted";
20
+ import { ConfigError } from "@distilled.cloud/core/errors";
21
+ /**
22
+ * Discord HTTP API base URL. The trailing `/v10` is the API version the spec
23
+ * submodule describes — override via `DISCORD_API_URL` only to point at a
24
+ * proxy, not to change versions (the generated operations are v10-shaped).
25
+ */
26
+ export const DEFAULT_API_BASE_URL = "https://discord.com/api/v10";
27
+ export class Credentials extends Context.Service()("DiscordCredentials") {
28
+ }
29
+ const envConfig = EffectConfig.all({
30
+ // DISCORD_BOT_TOKEN is the spelling discord.js and most hosting platforms
31
+ // use; DISCORD_TOKEN is the fallback.
32
+ token: EffectConfig.string("DISCORD_BOT_TOKEN").pipe(EffectConfig.orElse(() => EffectConfig.string("DISCORD_TOKEN"))),
33
+ tokenType: EffectConfig.string("DISCORD_TOKEN_TYPE").pipe(EffectConfig.withDefault("Bot")),
34
+ apiBaseUrl: EffectConfig.string("DISCORD_API_URL").pipe(EffectConfig.withDefault(DEFAULT_API_BASE_URL)),
35
+ });
36
+ export const CredentialsFromEnv = Layer.succeed(Credentials, envConfig.pipe(Effect.mapError(() => new ConfigError({
37
+ message: "DISCORD_BOT_TOKEN (or DISCORD_TOKEN) environment variable is required",
38
+ })), Effect.map(({ token, tokenType, apiBaseUrl }) => ({
39
+ token: Redacted.make(token),
40
+ // Anything but an explicit `Bearer` means a bot token — the OAuth2
41
+ // flavor is the opt-in.
42
+ tokenType: (tokenType.toLowerCase() === "bearer"
43
+ ? "Bearer"
44
+ : "Bot"),
45
+ apiBaseUrl,
46
+ })), Effect.orDie));
47
+ /** Convenience layer from a plain token + optional token type / base URL. */
48
+ export const credentials = (config) => Layer.succeed(Credentials, Effect.succeed({
49
+ token: Redacted.make(config.token),
50
+ tokenType: config.tokenType ?? "Bot",
51
+ apiBaseUrl: config.apiBaseUrl ?? DEFAULT_API_BASE_URL,
52
+ }));
53
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,YAAY,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,6BAA6B,CAAC;AAWlE,MAAM,OAAO,WAAY,SAAQ,OAAO,CAAC,OAAO,EAG7C,CAAC,oBAAoB,CAAC;CAAG;AAE5B,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC;IACjC,0EAA0E;IAC1E,sCAAsC;IACtC,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAClD,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAChE;IACD,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CACvD,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAChC;IACD,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CACrD,YAAY,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAC/C;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAC7C,WAAW,EACX,SAAS,CAAC,IAAI,CACZ,MAAM,CAAC,QAAQ,CACb,GAAG,EAAE,CACH,IAAI,WAAW,CAAC;IACd,OAAO,EACL,uEAAuE;CAC1E,CAAC,CACL,EACD,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;IAChD,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;IAC3B,mEAAmE;IACnE,wBAAwB;IACxB,SAAS,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,QAAQ;QAC9C,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,KAAK,CAAc;IACvB,UAAU;CACX,CAAC,CAAC,EACH,MAAM,CAAC,KAAK,CACb,CACF,CAAC;AAEF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAI3B,EAA4B,EAAE,CAC7B,KAAK,CAAC,OAAO,CACX,WAAW,EACX,MAAM,CAAC,OAAO,CAAC;IACb,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,KAAK;IACpC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,oBAAoB;CACtD,CAAC,CACH,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Discord-specific error types.
3
+ *
4
+ * Re-exports the common HTTP errors from core and adds the Discord-specific
5
+ * unknown-error and parse-error wrappers.
6
+ */
7
+ export { BadGateway, BadRequest, Conflict, ConfigError, Forbidden, GatewayTimeout, InternalServerError, Locked, NotFound, ServiceUnavailable, TooManyRequests, Unauthorized, UnprocessableEntity, HTTP_STATUS_MAP, DEFAULT_ERRORS, API_ERRORS, } from "@distilled.cloud/core/errors";
8
+ import type { DefaultErrors as CoreDefaultErrors } from "@distilled.cloud/core/errors";
9
+ import * as Schema from "effect/Schema";
10
+ declare const UnknownDiscordError_base: Schema.Class<UnknownDiscordError, Schema.TaggedStruct<"UnknownDiscordError", {
11
+ readonly code: Schema.optional<Schema.Number>;
12
+ readonly message: Schema.optional<Schema.String>;
13
+ readonly errors: Schema.optional<Schema.Unknown>;
14
+ readonly body: Schema.Unknown;
15
+ }>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
16
+ "@distilled.cloud/error/categories": {
17
+ ServerError: true;
18
+ };
19
+ });
20
+ /**
21
+ * Unknown Discord error — returned when a failed response's HTTP status has
22
+ * no mapped error class. `code` is Discord's own JSON error code (e.g. 50001
23
+ * "Missing Access"), which is far more specific than the HTTP status and is
24
+ * the field worth branching on; `errors` carries the per-field validation
25
+ * detail Discord attaches to 400s. See
26
+ * https://discord.com/developers/docs/topics/opcodes-and-status-codes#json.
27
+ */
28
+ export declare class UnknownDiscordError extends UnknownDiscordError_base {
29
+ }
30
+ declare const DiscordParseError_base: Schema.Class<DiscordParseError, Schema.TaggedStruct<"DiscordParseError", {
31
+ readonly body: Schema.Unknown;
32
+ readonly cause: Schema.Unknown;
33
+ }>, import("effect/Cause").YieldableError> & (new (...args: any[]) => {
34
+ "@distilled.cloud/error/categories": {
35
+ ParseError: true;
36
+ };
37
+ });
38
+ /** Schema parse error wrapper. */
39
+ export declare class DiscordParseError extends DiscordParseError_base {
40
+ }
41
+ /**
42
+ * Errors any Discord operation may surface in addition to the shared HTTP
43
+ * status errors.
44
+ */
45
+ export type ClientErrors = UnknownDiscordError | DiscordParseError;
46
+ /**
47
+ * Default Discord operation errors: the shared HTTP status errors from core
48
+ * plus the client-level fallback/decode errors.
49
+ */
50
+ export type DefaultErrors = CoreDefaultErrors | ClientErrors;
51
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,MAAM,EACN,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEvF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;;;;;;;;;;;AAGxC;;;;;;;GAOG;AACH,qBAAa,mBAAoB,SAAQ,wBAQT;CAAG;;;;;;;;;AAEnC,kCAAkC;AAClC,qBAAa,iBAAkB,SAAQ,sBAMR;CAAG;AAElC;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,YAAY,CAAC"}
package/lib/errors.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Discord-specific error types.
3
+ *
4
+ * Re-exports the common HTTP errors from core and adds the Discord-specific
5
+ * unknown-error and parse-error wrappers.
6
+ */
7
+ export { BadGateway, BadRequest, Conflict, ConfigError, Forbidden, GatewayTimeout, InternalServerError, Locked, NotFound, ServiceUnavailable, TooManyRequests, Unauthorized, UnprocessableEntity, HTTP_STATUS_MAP, DEFAULT_ERRORS, API_ERRORS, } from "@distilled.cloud/core/errors";
8
+ import * as Schema from "effect/Schema";
9
+ import * as Category from "@distilled.cloud/core/category";
10
+ /**
11
+ * Unknown Discord error — returned when a failed response's HTTP status has
12
+ * no mapped error class. `code` is Discord's own JSON error code (e.g. 50001
13
+ * "Missing Access"), which is far more specific than the HTTP status and is
14
+ * the field worth branching on; `errors` carries the per-field validation
15
+ * detail Discord attaches to 400s. See
16
+ * https://discord.com/developers/docs/topics/opcodes-and-status-codes#json.
17
+ */
18
+ export class UnknownDiscordError extends Schema.TaggedError()("UnknownDiscordError", {
19
+ code: Schema.optional(Schema.Number),
20
+ message: Schema.optional(Schema.String),
21
+ errors: Schema.optional(Schema.Unknown),
22
+ body: Schema.Unknown,
23
+ }).pipe(Category.withServerError) {
24
+ }
25
+ /** Schema parse error wrapper. */
26
+ export class DiscordParseError extends Schema.TaggedError()("DiscordParseError", {
27
+ body: Schema.Unknown,
28
+ cause: Schema.Unknown,
29
+ }).pipe(Category.withParseError) {
30
+ }
31
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,UAAU,EACV,UAAU,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,MAAM,EACN,QAAQ,EACR,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,QAAQ,MAAM,gCAAgC,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,OAAO,mBAAoB,SAAQ,MAAM,CAAC,WAAW,EAAuB,CAChF,qBAAqB,EACrB;IACE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC,OAAO;CACrB,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC;CAAG;AAEnC,kCAAkC;AAClC,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAC5E,mBAAmB,EACnB;IACE,IAAI,EAAE,MAAM,CAAC,OAAO;IACpB,KAAK,EAAE,MAAM,CAAC,OAAO;CACtB,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;CAAG"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @distilled.cloud/discord — Discord HTTP API (v10) SDK for Effect.
3
+ *
4
+ * `./services` is generated by `scripts/generate.ts` from the Smithy model in
5
+ * `.generated-specs` (written by `scripts/convert.ts` from the Discord
6
+ * OpenAPI spec submodule). Everything else in this folder is hand-written.
7
+ */
8
+ export * from "./credentials.ts";
9
+ export * from "./errors.ts";
10
+ export * as T from "./traits.ts";
11
+ export { DiscordProtocol, type DiscordOpError, type DiscordOpContext, } from "./protocol.ts";
12
+ export * as Retry from "./retry.ts";
13
+ export * as Services from "./services/index.ts";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AACjC,OAAO,EACL,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @distilled.cloud/discord — Discord HTTP API (v10) SDK for Effect.
3
+ *
4
+ * `./services` is generated by `scripts/generate.ts` from the Smithy model in
5
+ * `.generated-specs` (written by `scripts/convert.ts` from the Discord
6
+ * OpenAPI spec submodule). Everything else in this folder is hand-written.
7
+ */
8
+ export * from "./credentials.js";
9
+ export * from "./errors.js";
10
+ export * as T from "./traits.js";
11
+ export { DiscordProtocol, } from "./protocol.js";
12
+ export * as Retry from "./retry.js";
13
+ export * as Services from "./services/index.js";
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AACjC,OAAO,EACL,eAAe,GAGhB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type * as Layer from "effect/Layer";
2
+ import type * as HttpClient from "effect/unstable/http/HttpClient";
3
+ import type * as HttpClientError from "effect/unstable/http/HttpClientError";
4
+ import type * as API from "@distilled.cloud/core/api";
5
+ import type { ConfigError } from "@distilled.cloud/core/errors";
6
+ import { Credentials } from "./credentials.ts";
7
+ import { type DefaultErrors } from "./errors.ts";
8
+ /**
9
+ * Error channel shared by every generated Discord operation. Generated
10
+ * service files annotate operations with `API.OperationMethod<I, O,
11
+ * DiscordOpError, DiscordOpContext>` explicitly so the compiler never infers
12
+ * these back out of the schema generics.
13
+ */
14
+ export type DiscordOpError = DefaultErrors | ConfigError | HttpClientError.HttpClientError;
15
+ /** Context (requirements) shared by every generated Discord operation. */
16
+ export type DiscordOpContext = Credentials | HttpClient.HttpClient;
17
+ export declare const DiscordProtocol: Layer.Layer<API.Protocol>;
18
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,KAAK,eAAe,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,KAAK,GAAG,MAAM,2BAA2B,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAKhE,OAAO,EAAE,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB,aAAa,GACb,WAAW,GACX,eAAe,CAAC,eAAe,CAAC;AAEpC,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC;AA4CnE,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAqBlD,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * DiscordProtocol — the shared bearer-REST protocol instantiated for Discord.
3
+ *
4
+ * Discord speaks plain JSON with no response envelope: successful responses
5
+ * are the resource (or a bare array) verbatim. Failures carry
6
+ * `{ code, message, errors? }` where `code` is Discord's own numeric JSON
7
+ * error code — the shared HTTP status map turns the status into the error
8
+ * class, and anything unmapped becomes {@link UnknownDiscordError} with the
9
+ * code and per-field `errors` detail preserved.
10
+ *
11
+ * Rate limits (429) arrive as `TooManyRequests` with `retryAfter` read from
12
+ * the `Retry-After` header, so the default retry policy honors Discord's
13
+ * bucket hints without extra configuration.
14
+ */
15
+ import * as Effect from "effect/Effect";
16
+ import * as Redacted from "effect/Redacted";
17
+ import { makeRestProtocol, } from "@distilled.cloud/core/protocol-rest";
18
+ import { Credentials } from "./credentials.js";
19
+ import { UnknownDiscordError } from "./errors.js";
20
+ /**
21
+ * Discord's error body is `{ code: <numeric JSON error code>, message }`.
22
+ * The OAuth2 token endpoints answer in the OAuth style instead
23
+ * (`{ error, error_description }`), so both spellings are read here.
24
+ */
25
+ const errorEnvelope = (body) => {
26
+ if (body === null || typeof body !== "object")
27
+ return undefined;
28
+ const b = body;
29
+ const message = typeof b.message === "string"
30
+ ? b.message
31
+ : typeof b.error_description === "string"
32
+ ? b.error_description
33
+ : typeof b.error === "string"
34
+ ? b.error
35
+ : undefined;
36
+ const code = typeof b.code === "number" || typeof b.code === "string"
37
+ ? b.code
38
+ : undefined;
39
+ return { code, message };
40
+ };
41
+ /** Discord's `errors` object: per-field validation detail on 400s. */
42
+ const errorDetails = (body) => {
43
+ if (body === null || typeof body !== "object")
44
+ return undefined;
45
+ return body.errors;
46
+ };
47
+ /**
48
+ * Discord's JSON error code as a number. The OAuth2 endpoints answer with a
49
+ * string `error` slug instead of a numeric `code` — those carry no numeric
50
+ * code at all, so anything unparseable is dropped rather than surfaced as
51
+ * NaN.
52
+ */
53
+ const numericCode = (code) => {
54
+ if (typeof code === "number")
55
+ return Number.isFinite(code) ? code : undefined;
56
+ if (typeof code !== "string" || code.trim() === "")
57
+ return undefined;
58
+ const n = Number(code);
59
+ return Number.isFinite(n) ? n : undefined;
60
+ };
61
+ export const DiscordProtocol = makeRestProtocol({
62
+ // Resolved on the CALLING fiber per request (the layer is memoized per
63
+ // process); the Credentials service holds an effect so rotating tokens
64
+ // Just Work.
65
+ credentials: Effect.gen(function* () {
66
+ const resolve = yield* Credentials;
67
+ return yield* resolve;
68
+ }),
69
+ baseUrl: (creds) => creds.apiBaseUrl,
70
+ headers: (creds) => ({
71
+ Authorization: `${creds.tokenType} ${Redacted.value(creds.token)}`,
72
+ }),
73
+ errorEnvelope,
74
+ unknownError: ({ code, message, body }) => new UnknownDiscordError({
75
+ code: numericCode(code),
76
+ message,
77
+ errors: errorDetails(body),
78
+ body,
79
+ }),
80
+ });
81
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/lib/retry.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Discord retry surface — a veneer over `@distilled.cloud/core/retry`.
3
+ *
4
+ * The `Retry` service tag is threaded into every generated operation via
5
+ * `API.make({ retry: Retry })`, so a caller-installed policy applies to all
6
+ * Discord calls below it and core's `makeDefault` is the fallback when none
7
+ * is provided. Discord rate limits aggressively per-bucket and answers 429s
8
+ * with a `Retry-After` header, which the default policy honors with
9
+ * precedence over its own backoff.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import * as Discord from "@distilled.cloud/discord";
14
+ *
15
+ * myEffect.pipe(Discord.Retry.throttling);
16
+ * ```
17
+ */
18
+ import * as Context from "effect/Context";
19
+ import * as Effect from "effect/Effect";
20
+ import * as Retries from "@distilled.cloud/core/retry";
21
+ export type Options = Retries.Options;
22
+ export type Factory = Retries.Factory;
23
+ export type Policy = Retries.Policy;
24
+ declare const Retry_base: Context.ServiceClass<Retry, "DiscordRetry", Retries.Policy>;
25
+ /** Context tag for configuring retry behavior of Discord API calls. */
26
+ export declare class Retry extends Retry_base {
27
+ }
28
+ /** Provides a custom retry policy to every Discord API call below it. */
29
+ export declare const policy: {
30
+ (options: Options): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
31
+ (factory: Factory): <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
32
+ };
33
+ /** Disables all automatic retries. */
34
+ export declare const none: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
35
+ /**
36
+ * The default retry policy (core's): transient/throttling/retryable errors,
37
+ * capped exponential backoff with jitter, server `retryAfter` hints honored
38
+ * with precedence.
39
+ */
40
+ export declare const makeDefault: Factory;
41
+ export declare const jittered: <Error, Env>(self: import("effect/Schedule").Schedule<unknown, unknown, Error, Env>) => import("effect/Schedule").Schedule<unknown, unknown, Error, Env>;
42
+ export declare const capped: (max: import("effect/Duration").Duration) => <Error, Env>(self: import("effect/Schedule").Schedule<unknown, unknown, Error, Env>) => import("effect/Schedule").Schedule<unknown, unknown, Error, Env>;
43
+ /** Retry options that retry all throttling errors indefinitely. */
44
+ export declare const throttlingOptions: Options;
45
+ /** Retries all throttling errors indefinitely (honoring server hints). */
46
+ export declare const throttling: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
47
+ /** Retry options that retry all transient errors indefinitely. */
48
+ export declare const transientOptions: Options;
49
+ /** Retries all transient errors indefinitely (honoring server hints). */
50
+ export declare const transient: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, Retry>>;
51
+ export {};
52
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAEvD,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;AACtC,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;AACtC,MAAM,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;;AAEpC,uEAAuE;AACvE,qBAAa,KAAM,SAAQ,UAAgD;CAAG;AAE9E,yEAAyE;AACzE,eAAO,MAAM,MAAM,EAAE;IACnB,CACE,OAAO,EAAE,OAAO,GACf,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACT,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5C,CACE,OAAO,EAAE,OAAO,GACf,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACT,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;CAEU,CAAC;AAEzD,sCAAsC;AACtC,eAAO,MAAM,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACzB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAEzC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,OAA6B,CAAC;AAExD,eAAO,MAAM,QAAQ,0JAAmB,CAAC;AACzC,eAAO,MAAM,MAAM,uMAAiB,CAAC;AAErC,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,EAAE,OAAmC,CAAC;AAEpE,0EAA0E;AAC1E,eAAO,MAAM,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAqC,CAAC;AAEhF,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,OAAkC,CAAC;AAElE,yEAAyE;AACzE,eAAO,MAAM,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAoC,CAAC"}
package/lib/retry.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Discord retry surface — a veneer over `@distilled.cloud/core/retry`.
3
+ *
4
+ * The `Retry` service tag is threaded into every generated operation via
5
+ * `API.make({ retry: Retry })`, so a caller-installed policy applies to all
6
+ * Discord calls below it and core's `makeDefault` is the fallback when none
7
+ * is provided. Discord rate limits aggressively per-bucket and answers 429s
8
+ * with a `Retry-After` header, which the default policy honors with
9
+ * precedence over its own backoff.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import * as Discord from "@distilled.cloud/discord";
14
+ *
15
+ * myEffect.pipe(Discord.Retry.throttling);
16
+ * ```
17
+ */
18
+ import * as Context from "effect/Context";
19
+ import * as Effect from "effect/Effect";
20
+ import * as Layer from "effect/Layer";
21
+ import * as Retries from "@distilled.cloud/core/retry";
22
+ /** Context tag for configuring retry behavior of Discord API calls. */
23
+ export class Retry extends Context.Service()("DiscordRetry") {
24
+ }
25
+ /** Provides a custom retry policy to every Discord API call below it. */
26
+ export const policy = (optionsOrFactory) => Effect.provide(Layer.succeed(Retry, optionsOrFactory));
27
+ /** Disables all automatic retries. */
28
+ export const none = Effect.provide(Layer.succeed(Retry, { while: () => false }));
29
+ /**
30
+ * The default retry policy (core's): transient/throttling/retryable errors,
31
+ * capped exponential backoff with jitter, server `retryAfter` hints honored
32
+ * with precedence.
33
+ */
34
+ export const makeDefault = Retries.makeDefault;
35
+ export const jittered = Retries.jittered;
36
+ export const capped = Retries.capped;
37
+ /** Retry options that retry all throttling errors indefinitely. */
38
+ export const throttlingOptions = Retries.throttlingOptions;
39
+ /** Retries all throttling errors indefinitely (honoring server hints). */
40
+ export const throttling = policy(Retries.throttlingFactory);
41
+ /** Retry options that retry all transient errors indefinitely. */
42
+ export const transientOptions = Retries.transientOptions;
43
+ /** Retries all transient errors indefinitely (honoring server hints). */
44
+ export const transient = policy(Retries.transientFactory);
45
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,6BAA6B,CAAC;AAMvD,uEAAuE;AACvE,MAAM,OAAO,KAAM,SAAQ,OAAO,CAAC,OAAO,EAAiB,CAAC,cAAc,CAAC;CAAG;AAE9E,yEAAyE;AACzE,MAAM,CAAC,MAAM,MAAM,GAWf,CAAC,gBAAmC,EAAE,EAAE,CAC1C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEzD,sCAAsC;AACtC,MAAM,CAAC,MAAM,IAAI,GAE6B,MAAM,CAAC,OAAO,CAC1D,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAC7C,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAY,OAAO,CAAC,WAAW,CAAC;AAExD,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;AACzC,MAAM,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;AAErC,mEAAmE;AACnE,MAAM,CAAC,MAAM,iBAAiB,GAAY,OAAO,CAAC,iBAAiB,CAAC;AAEpE,0EAA0E;AAC1E,MAAM,CAAC,MAAM,UAAU,GAEuB,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAEhF,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAY,OAAO,CAAC,gBAAgB,CAAC;AAElE,yEAAyE;AACzE,MAAM,CAAC,MAAM,SAAS,GAEwB,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC"}