@distilled.cloud/core 0.0.0-john
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 +30 -0
- package/lib/category.d.ts +260 -0
- package/lib/category.d.ts.map +1 -0
- package/lib/category.js +264 -0
- package/lib/category.js.map +1 -0
- package/lib/client.d.ts +149 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.js +342 -0
- package/lib/client.js.map +1 -0
- package/lib/errors.d.ts +211 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +138 -0
- package/lib/errors.js.map +1 -0
- package/lib/json-patch.d.ts +44 -0
- package/lib/json-patch.d.ts.map +1 -0
- package/lib/json-patch.js +208 -0
- package/lib/json-patch.js.map +1 -0
- package/lib/pagination.d.ts +85 -0
- package/lib/pagination.d.ts.map +1 -0
- package/lib/pagination.js +177 -0
- package/lib/pagination.js.map +1 -0
- package/lib/retry.d.ts +99 -0
- package/lib/retry.d.ts.map +1 -0
- package/lib/retry.js +106 -0
- package/lib/retry.js.map +1 -0
- package/lib/sensitive.d.ts +50 -0
- package/lib/sensitive.d.ts.map +1 -0
- package/lib/sensitive.js +64 -0
- package/lib/sensitive.js.map +1 -0
- package/lib/traits.d.ts +274 -0
- package/lib/traits.d.ts.map +1 -0
- package/lib/traits.js +479 -0
- package/lib/traits.js.map +1 -0
- package/package.json +80 -0
- package/src/category.ts +406 -0
- package/src/client.ts +631 -0
- package/src/errors.ts +178 -0
- package/src/json-patch.ts +261 -0
- package/src/pagination.ts +303 -0
- package/src/retry.ts +177 -0
- package/src/sensitive.ts +74 -0
- package/src/traits.ts +641 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pagination utilities for streaming through paginated API responses.
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple pagination styles:
|
|
5
|
+
* - Page-based (e.g., PlanetScale): page/per_page with next_page number
|
|
6
|
+
* - Cursor-based (e.g., Neon): cursor/limit with next cursor string
|
|
7
|
+
* - Token-based (e.g., AWS): NextToken/MaxResults with continuation tokens
|
|
8
|
+
*
|
|
9
|
+
* Each SDK defines its own pagination trait configuration, and these
|
|
10
|
+
* shared utilities handle the streaming logic.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import * as Pagination from "@distilled.cloud/core/pagination";
|
|
15
|
+
*
|
|
16
|
+
* // Page-based pagination
|
|
17
|
+
* const allPages = Pagination.paginatePages(listDatabases, { organization: "my-org" }, {
|
|
18
|
+
* inputToken: "page",
|
|
19
|
+
* outputToken: "next_page",
|
|
20
|
+
* items: "data",
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import * as Effect from "effect/Effect";
|
|
25
|
+
import * as Stream from "effect/Stream";
|
|
26
|
+
/**
|
|
27
|
+
* Pagination trait describing how to navigate between pages.
|
|
28
|
+
*/
|
|
29
|
+
export interface PaginatedTrait {
|
|
30
|
+
/** Pagination strategy */
|
|
31
|
+
mode?: "token" | "page" | "cursor" | "single";
|
|
32
|
+
/** The name of the input member containing the page/cursor token */
|
|
33
|
+
inputToken?: string;
|
|
34
|
+
/** The path to the output member containing the next page/cursor token */
|
|
35
|
+
outputToken?: string;
|
|
36
|
+
/** The path to the output member containing the paginated items */
|
|
37
|
+
items?: string;
|
|
38
|
+
/** The name of the input member that limits page size */
|
|
39
|
+
pageSize?: string;
|
|
40
|
+
}
|
|
41
|
+
export type PaginationStrategy = <Input extends Record<string, unknown>, Output, E, R>(operation: (input: Input) => Effect.Effect<Output, E, R>, input: Input, pagination: PaginatedTrait) => Stream.Stream<Output, E, R>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a stream for single-shot list endpoints that still expose the paginated API surface.
|
|
44
|
+
*/
|
|
45
|
+
export declare const paginateSingle: PaginationStrategy;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a stream of pages using page-number pagination.
|
|
48
|
+
*
|
|
49
|
+
* @param operation - The paginated operation to call
|
|
50
|
+
* @param input - The initial input (without page parameter)
|
|
51
|
+
* @param pagination - The pagination trait configuration
|
|
52
|
+
* @returns A Stream of full page responses
|
|
53
|
+
*/
|
|
54
|
+
export declare const paginatePageNumber: <Input extends Record<string, unknown>, Output, E, R>(operation: (input: Input) => Effect.Effect<Output, E, R>, input: Omit<Input, string>, pagination: PaginatedTrait) => Stream.Stream<Output, E, R>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a stream of pages using cursor-based pagination.
|
|
57
|
+
*
|
|
58
|
+
* @param operation - The paginated operation to call
|
|
59
|
+
* @param input - The initial input (without cursor parameter)
|
|
60
|
+
* @param pagination - The pagination trait configuration
|
|
61
|
+
* @returns A Stream of full page responses
|
|
62
|
+
*/
|
|
63
|
+
export declare const paginateCursor: <Input extends Record<string, unknown>, Output, E, R>(operation: (input: Input) => Effect.Effect<Output, E, R>, input: Omit<Input, string>, pagination: PaginatedTrait) => Stream.Stream<Output, E, R>;
|
|
64
|
+
/**
|
|
65
|
+
* Creates a stream of pages using token-based pagination.
|
|
66
|
+
*
|
|
67
|
+
* @param operation - The paginated operation to call
|
|
68
|
+
* @param input - The initial input
|
|
69
|
+
* @param pagination - The pagination trait configuration
|
|
70
|
+
* @returns A Stream of full page responses
|
|
71
|
+
*/
|
|
72
|
+
export declare const paginateToken: <Input extends Record<string, unknown>, Output, E, R>(operation: (input: Input) => Effect.Effect<Output, E, R>, input: Input, pagination: PaginatedTrait) => Stream.Stream<Output, E, R>;
|
|
73
|
+
/**
|
|
74
|
+
* Shared default pagination dispatcher for SDKs that use generic token/cursor/page traversal.
|
|
75
|
+
*/
|
|
76
|
+
export declare const paginateWithDefaults: PaginationStrategy;
|
|
77
|
+
/**
|
|
78
|
+
* Extracts individual items from a page stream.
|
|
79
|
+
*
|
|
80
|
+
* @param pages - A stream of page responses
|
|
81
|
+
* @param itemsPath - Dot-separated path to the items array in the page response
|
|
82
|
+
* @returns A Stream of individual items
|
|
83
|
+
*/
|
|
84
|
+
export declare const extractItems: <Output, Item, E, R>(pages: Stream.Stream<Output, E, R>, itemsPath: string) => Stream.Stream<Item, E, R>;
|
|
85
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAOxC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC9C,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,MAAM,EACN,CAAC,EACD,CAAC,EAED,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EACxD,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,cAAc,KACvB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAIjC;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,kBAG1B,CAAC;AAMJ;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC7B,KAAK,kCACL,MAAM,EACN,CAAC,EACD,CAAC,kJA+CF,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,KAAK,kCACL,MAAM,EACN,CAAC,EACD,CAAC,kJA+CF,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,kCACL,MAAM,EACN,CAAC,EACD,CAAC,oIAyCF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,kBAoBlC,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,qFAS5C,CAAC"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pagination utilities for streaming through paginated API responses.
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple pagination styles:
|
|
5
|
+
* - Page-based (e.g., PlanetScale): page/per_page with next_page number
|
|
6
|
+
* - Cursor-based (e.g., Neon): cursor/limit with next cursor string
|
|
7
|
+
* - Token-based (e.g., AWS): NextToken/MaxResults with continuation tokens
|
|
8
|
+
*
|
|
9
|
+
* Each SDK defines its own pagination trait configuration, and these
|
|
10
|
+
* shared utilities handle the streaming logic.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import * as Pagination from "@distilled.cloud/core/pagination";
|
|
15
|
+
*
|
|
16
|
+
* // Page-based pagination
|
|
17
|
+
* const allPages = Pagination.paginatePages(listDatabases, { organization: "my-org" }, {
|
|
18
|
+
* inputToken: "page",
|
|
19
|
+
* outputToken: "next_page",
|
|
20
|
+
* items: "data",
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import * as Effect from "effect/Effect";
|
|
25
|
+
import * as Stream from "effect/Stream";
|
|
26
|
+
import { getPath } from "./traits.js";
|
|
27
|
+
const missingPaginationConfig = (kind) => Stream.die(new Error(kind));
|
|
28
|
+
/**
|
|
29
|
+
* Creates a stream for single-shot list endpoints that still expose the paginated API surface.
|
|
30
|
+
*/
|
|
31
|
+
export const paginateSingle = (operation, input) => Stream.make(input).pipe(Stream.mapEffect((requestPayload) => operation(requestPayload)));
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// Page-based Pagination (PlanetScale style)
|
|
34
|
+
// ============================================================================
|
|
35
|
+
/**
|
|
36
|
+
* Creates a stream of pages using page-number pagination.
|
|
37
|
+
*
|
|
38
|
+
* @param operation - The paginated operation to call
|
|
39
|
+
* @param input - The initial input (without page parameter)
|
|
40
|
+
* @param pagination - The pagination trait configuration
|
|
41
|
+
* @returns A Stream of full page responses
|
|
42
|
+
*/
|
|
43
|
+
export const paginatePageNumber = (operation, input, pagination) => {
|
|
44
|
+
const inputToken = pagination.inputToken;
|
|
45
|
+
const outputToken = pagination.outputToken;
|
|
46
|
+
const inputRecord = input;
|
|
47
|
+
if (!inputToken || !outputToken) {
|
|
48
|
+
return missingPaginationConfig("Page-number pagination requires inputToken and outputToken");
|
|
49
|
+
}
|
|
50
|
+
const startPage = typeof inputRecord[inputToken] === "number"
|
|
51
|
+
? inputRecord[inputToken]
|
|
52
|
+
: 1;
|
|
53
|
+
const unfoldFn = (state) => Effect.gen(function* () {
|
|
54
|
+
if (state.done) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const requestPayload = {
|
|
58
|
+
...input,
|
|
59
|
+
[inputToken]: state.page,
|
|
60
|
+
};
|
|
61
|
+
const response = yield* operation(requestPayload);
|
|
62
|
+
const nextPage = getPath(response, outputToken);
|
|
63
|
+
const nextState = {
|
|
64
|
+
page: nextPage ?? state.page + 1,
|
|
65
|
+
done: nextPage === null || nextPage === undefined,
|
|
66
|
+
};
|
|
67
|
+
return [response, nextState];
|
|
68
|
+
});
|
|
69
|
+
return Stream.unfold({ page: startPage, done: false }, unfoldFn);
|
|
70
|
+
};
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// Cursor-based Pagination (Neon style)
|
|
73
|
+
// ============================================================================
|
|
74
|
+
/**
|
|
75
|
+
* Creates a stream of pages using cursor-based pagination.
|
|
76
|
+
*
|
|
77
|
+
* @param operation - The paginated operation to call
|
|
78
|
+
* @param input - The initial input (without cursor parameter)
|
|
79
|
+
* @param pagination - The pagination trait configuration
|
|
80
|
+
* @returns A Stream of full page responses
|
|
81
|
+
*/
|
|
82
|
+
export const paginateCursor = (operation, input, pagination) => {
|
|
83
|
+
const inputToken = pagination.inputToken;
|
|
84
|
+
const outputToken = pagination.outputToken;
|
|
85
|
+
const inputRecord = input;
|
|
86
|
+
if (!inputToken || !outputToken) {
|
|
87
|
+
return missingPaginationConfig("Cursor pagination requires inputToken and outputToken");
|
|
88
|
+
}
|
|
89
|
+
const startCursor = typeof inputRecord[inputToken] === "string"
|
|
90
|
+
? inputRecord[inputToken]
|
|
91
|
+
: undefined;
|
|
92
|
+
const unfoldFn = (state) => Effect.gen(function* () {
|
|
93
|
+
if (state.done) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const requestPayload = {
|
|
97
|
+
...input,
|
|
98
|
+
...(state.cursor ? { [inputToken]: state.cursor } : {}),
|
|
99
|
+
};
|
|
100
|
+
const response = yield* operation(requestPayload);
|
|
101
|
+
const nextCursor = getPath(response, outputToken);
|
|
102
|
+
const nextState = {
|
|
103
|
+
cursor: nextCursor ?? undefined,
|
|
104
|
+
done: nextCursor === null || nextCursor === undefined,
|
|
105
|
+
};
|
|
106
|
+
return [response, nextState];
|
|
107
|
+
});
|
|
108
|
+
return Stream.unfold({ cursor: startCursor, done: false }, unfoldFn);
|
|
109
|
+
};
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Token-based Pagination (AWS style)
|
|
112
|
+
// ============================================================================
|
|
113
|
+
/**
|
|
114
|
+
* Creates a stream of pages using token-based pagination.
|
|
115
|
+
*
|
|
116
|
+
* @param operation - The paginated operation to call
|
|
117
|
+
* @param input - The initial input
|
|
118
|
+
* @param pagination - The pagination trait configuration
|
|
119
|
+
* @returns A Stream of full page responses
|
|
120
|
+
*/
|
|
121
|
+
export const paginateToken = (operation, input, pagination) => {
|
|
122
|
+
const inputToken = pagination.inputToken;
|
|
123
|
+
const outputToken = pagination.outputToken;
|
|
124
|
+
const inputRecord = input;
|
|
125
|
+
if (!inputToken || !outputToken) {
|
|
126
|
+
return missingPaginationConfig("Token pagination requires inputToken and outputToken");
|
|
127
|
+
}
|
|
128
|
+
const startToken = inputRecord[inputToken];
|
|
129
|
+
const unfoldFn = (state) => Effect.gen(function* () {
|
|
130
|
+
if (state.done) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const requestPayload = state.token !== undefined
|
|
134
|
+
? { ...input, [inputToken]: state.token }
|
|
135
|
+
: input;
|
|
136
|
+
const response = yield* operation(requestPayload);
|
|
137
|
+
const nextToken = getPath(response, outputToken);
|
|
138
|
+
const nextState = {
|
|
139
|
+
token: nextToken,
|
|
140
|
+
done: nextToken === undefined || nextToken === null,
|
|
141
|
+
};
|
|
142
|
+
return [response, nextState];
|
|
143
|
+
});
|
|
144
|
+
return Stream.unfold({ token: startToken, done: false }, unfoldFn);
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Shared default pagination dispatcher for SDKs that use generic token/cursor/page traversal.
|
|
148
|
+
*/
|
|
149
|
+
export const paginateWithDefaults = (operation, input, pagination) => {
|
|
150
|
+
const mode = pagination.mode ?? "token";
|
|
151
|
+
switch (mode) {
|
|
152
|
+
case "page":
|
|
153
|
+
return paginatePageNumber(operation, input, pagination);
|
|
154
|
+
case "cursor":
|
|
155
|
+
return paginateCursor(operation, input, pagination);
|
|
156
|
+
case "single":
|
|
157
|
+
return missingPaginationConfig("Single-page pagination requires a provider-specific pagination strategy");
|
|
158
|
+
case "token":
|
|
159
|
+
default:
|
|
160
|
+
return paginateToken(operation, input, pagination);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
// ============================================================================
|
|
164
|
+
// Item extraction
|
|
165
|
+
// ============================================================================
|
|
166
|
+
/**
|
|
167
|
+
* Extracts individual items from a page stream.
|
|
168
|
+
*
|
|
169
|
+
* @param pages - A stream of page responses
|
|
170
|
+
* @param itemsPath - Dot-separated path to the items array in the page response
|
|
171
|
+
* @returns A Stream of individual items
|
|
172
|
+
*/
|
|
173
|
+
export const extractItems = (pages, itemsPath) => pages.pipe(Stream.flatMap((page) => {
|
|
174
|
+
const items = getPath(page, itemsPath);
|
|
175
|
+
return Stream.fromIterable(items ?? []);
|
|
176
|
+
}));
|
|
177
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"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"}
|
package/lib/retry.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Policy System
|
|
3
|
+
*
|
|
4
|
+
* Provides configurable retry policies for API operations.
|
|
5
|
+
* Each SDK creates its own Retry service tag but uses these shared utilities
|
|
6
|
+
* for building retry schedules and policies.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import * as Retry from "@distilled.cloud/core/retry";
|
|
11
|
+
*
|
|
12
|
+
* // Use the default retry policy
|
|
13
|
+
* myEffect.pipe(Retry.policy(myRetryService, Retry.makeDefault()))
|
|
14
|
+
*
|
|
15
|
+
* // Disable retries
|
|
16
|
+
* myEffect.pipe(Retry.none(myRetryService))
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import * as Duration from "effect/Duration";
|
|
20
|
+
import * as Effect from "effect/Effect";
|
|
21
|
+
import * as Ref from "effect/Ref";
|
|
22
|
+
import * as Schedule from "effect/Schedule";
|
|
23
|
+
import * as ServiceMap from "effect/ServiceMap";
|
|
24
|
+
/**
|
|
25
|
+
* Retry policy options that match the Effect.retry contract.
|
|
26
|
+
*/
|
|
27
|
+
export interface Options {
|
|
28
|
+
/**
|
|
29
|
+
* Predicate to determine if an error should trigger a retry.
|
|
30
|
+
*/
|
|
31
|
+
readonly while?: (error: unknown) => boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The schedule to use for retrying.
|
|
34
|
+
*/
|
|
35
|
+
readonly schedule?: Schedule.Schedule<unknown>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A factory function that creates retry policy options with access to the last error ref.
|
|
39
|
+
* This allows dynamic policies that can inspect the last error for retry-after headers, etc.
|
|
40
|
+
*/
|
|
41
|
+
export type Factory = (lastError: Ref.Ref<unknown>) => Options;
|
|
42
|
+
/**
|
|
43
|
+
* A retry policy can be either static options or a factory that receives the last error ref.
|
|
44
|
+
*/
|
|
45
|
+
export type Policy = Options | Factory;
|
|
46
|
+
/**
|
|
47
|
+
* Create a typed Retry service class for an SDK.
|
|
48
|
+
* Each SDK should create its own Retry service using this factory.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* // In planetscale-sdk/src/retry.ts
|
|
53
|
+
* export class Retry extends makeRetryService("PlanetScaleRetry") {}
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const makeRetryService: (name: string) => ServiceMap.ServiceClass<any, string, Policy>;
|
|
57
|
+
/**
|
|
58
|
+
* Provides a custom retry policy for API calls.
|
|
59
|
+
*/
|
|
60
|
+
export declare const policy: (Service: any, optionsOrFactory: Policy) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, unknown, unknown>;
|
|
61
|
+
/**
|
|
62
|
+
* Disables all automatic retries.
|
|
63
|
+
*/
|
|
64
|
+
export declare const none: (Service: any) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, unknown, unknown>;
|
|
65
|
+
/**
|
|
66
|
+
* Custom jittered schedule helper.
|
|
67
|
+
* Adds random jitter between 0-50ms to avoid thundering herd.
|
|
68
|
+
*/
|
|
69
|
+
export declare const jittered: <Input, Error, Env>(self: Schedule.Schedule<unknown, Input, Error, Env>) => Schedule.Schedule<unknown, Input, Error, Env>;
|
|
70
|
+
/**
|
|
71
|
+
* Cap delay at a maximum duration.
|
|
72
|
+
*/
|
|
73
|
+
export declare const capped: (max: Duration.Duration) => <Input, Error, Env>(self: Schedule.Schedule<Duration.Duration, Input, Error, Env>) => Schedule.Schedule<Duration.Duration, Input, Error, Env>;
|
|
74
|
+
/**
|
|
75
|
+
* Creates the default retry policy.
|
|
76
|
+
*
|
|
77
|
+
* This policy:
|
|
78
|
+
* - Retries transient errors (throttling, server, network, locked errors)
|
|
79
|
+
* - Uses exponential backoff starting at 100ms with a factor of 2
|
|
80
|
+
* - Ensures at least 500ms delay for throttling errors
|
|
81
|
+
* - Limits to 5 retry attempts
|
|
82
|
+
* - Applies jitter to avoid thundering herd
|
|
83
|
+
*/
|
|
84
|
+
export declare const makeDefault: Factory;
|
|
85
|
+
/**
|
|
86
|
+
* Retry options that retries all throttling errors indefinitely.
|
|
87
|
+
*/
|
|
88
|
+
export declare const throttlingOptions: Options;
|
|
89
|
+
/**
|
|
90
|
+
* Retry options that retries all transient errors indefinitely.
|
|
91
|
+
*
|
|
92
|
+
* This includes:
|
|
93
|
+
* 1. Throttling errors
|
|
94
|
+
* 2. Server errors
|
|
95
|
+
* 3. Network errors
|
|
96
|
+
* 4. Locked errors (423)
|
|
97
|
+
*/
|
|
98
|
+
export declare const transientOptions: Options;
|
|
99
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAC;AAOhD;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IAC7C;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAChD;AAED;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAMvC;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,gEACY,CAAC;AAE1C;;GAEG;AACH,eAAO,MAAM,MAAM,+CAEhB,CAAC,EAAE,CAAC,EAAE,CAAC,uEACiE,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,IAAI,qBAEd,CAAC,EAAE,CAAC,EAAE,CAAC,uEAIL,CAAC;AAMN;;;GAGG;AACH,eAAO,MAAM,QAAQ,2HAEpB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,MAAM,2KAKhB,CAAC;AAMJ;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,EAAE,OAkBxB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAO/B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAO9B,CAAC"}
|
package/lib/retry.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry Policy System
|
|
3
|
+
*
|
|
4
|
+
* Provides configurable retry policies for API operations.
|
|
5
|
+
* Each SDK creates its own Retry service tag but uses these shared utilities
|
|
6
|
+
* for building retry schedules and policies.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import * as Retry from "@distilled.cloud/core/retry";
|
|
11
|
+
*
|
|
12
|
+
* // Use the default retry policy
|
|
13
|
+
* myEffect.pipe(Retry.policy(myRetryService, Retry.makeDefault()))
|
|
14
|
+
*
|
|
15
|
+
* // Disable retries
|
|
16
|
+
* myEffect.pipe(Retry.none(myRetryService))
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import * as Duration from "effect/Duration";
|
|
20
|
+
import * as Effect from "effect/Effect";
|
|
21
|
+
import { pipe } from "effect/Function";
|
|
22
|
+
import * as Layer from "effect/Layer";
|
|
23
|
+
import * as Ref from "effect/Ref";
|
|
24
|
+
import * as Schedule from "effect/Schedule";
|
|
25
|
+
import * as ServiceMap from "effect/ServiceMap";
|
|
26
|
+
import { isThrottling, isTransientError } from "./category.js";
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Retry Service Factory
|
|
29
|
+
// ============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Create a typed Retry service class for an SDK.
|
|
32
|
+
* Each SDK should create its own Retry service using this factory.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // In planetscale-sdk/src/retry.ts
|
|
37
|
+
* export class Retry extends makeRetryService("PlanetScaleRetry") {}
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const makeRetryService = (name) => ServiceMap.Service()(name);
|
|
41
|
+
/**
|
|
42
|
+
* Provides a custom retry policy for API calls.
|
|
43
|
+
*/
|
|
44
|
+
export const policy = (Service, optionsOrFactory) => (effect) => Effect.provide(effect, Layer.succeed(Service, optionsOrFactory));
|
|
45
|
+
/**
|
|
46
|
+
* Disables all automatic retries.
|
|
47
|
+
*/
|
|
48
|
+
export const none = (Service) => (effect) => Effect.provide(effect, Layer.succeed(Service, { while: () => false }));
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// Retry Schedule Utilities
|
|
51
|
+
// ============================================================================
|
|
52
|
+
/**
|
|
53
|
+
* Custom jittered schedule helper.
|
|
54
|
+
* Adds random jitter between 0-50ms to avoid thundering herd.
|
|
55
|
+
*/
|
|
56
|
+
export const jittered = Schedule.addDelay(() => Effect.succeed(Duration.millis(Math.random() * 50)));
|
|
57
|
+
/**
|
|
58
|
+
* Cap delay at a maximum duration.
|
|
59
|
+
*/
|
|
60
|
+
export const capped = (max) => Schedule.modifyDelay((duration) => Effect.succeed(Duration.isGreaterThan(duration, max) ? Duration.millis(5000) : duration));
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Default Retry Policies
|
|
63
|
+
// ============================================================================
|
|
64
|
+
/**
|
|
65
|
+
* Creates the default retry policy.
|
|
66
|
+
*
|
|
67
|
+
* This policy:
|
|
68
|
+
* - Retries transient errors (throttling, server, network, locked errors)
|
|
69
|
+
* - Uses exponential backoff starting at 100ms with a factor of 2
|
|
70
|
+
* - Ensures at least 500ms delay for throttling errors
|
|
71
|
+
* - Limits to 5 retry attempts
|
|
72
|
+
* - Applies jitter to avoid thundering herd
|
|
73
|
+
*/
|
|
74
|
+
export const makeDefault = (lastError) => ({
|
|
75
|
+
while: (error) => isTransientError(error),
|
|
76
|
+
schedule: pipe(Schedule.exponential(100, 2), Schedule.modifyDelay(Effect.fnUntraced(function* (duration) {
|
|
77
|
+
const error = yield* Ref.get(lastError);
|
|
78
|
+
if (isThrottling(error)) {
|
|
79
|
+
if (Duration.toMillis(duration) < 500) {
|
|
80
|
+
return Duration.toMillis(Duration.millis(500));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return Duration.toMillis(duration);
|
|
84
|
+
})), Schedule.both(Schedule.recurs(5)), jittered),
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Retry options that retries all throttling errors indefinitely.
|
|
88
|
+
*/
|
|
89
|
+
export const throttlingOptions = {
|
|
90
|
+
while: (error) => isThrottling(error),
|
|
91
|
+
schedule: pipe(Schedule.exponential(1000, 2), capped(Duration.seconds(5)), jittered),
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Retry options that retries all transient errors indefinitely.
|
|
95
|
+
*
|
|
96
|
+
* This includes:
|
|
97
|
+
* 1. Throttling errors
|
|
98
|
+
* 2. Server errors
|
|
99
|
+
* 3. Network errors
|
|
100
|
+
* 4. Locked errors (423)
|
|
101
|
+
*/
|
|
102
|
+
export const transientOptions = {
|
|
103
|
+
while: isTransientError,
|
|
104
|
+
schedule: pipe(Schedule.exponential(1000, 2), capped(Duration.seconds(5)), jittered),
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=retry.js.map
|
package/lib/retry.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitive data schemas for handling credentials and secrets.
|
|
3
|
+
*
|
|
4
|
+
* This module provides schemas that wrap sensitive data in Effect's Redacted type,
|
|
5
|
+
* preventing accidental logging of secrets like passwords and tokens.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { SensitiveString } from "@distilled.cloud/core/sensitive";
|
|
10
|
+
*
|
|
11
|
+
* const Password = Schema.Struct({ plain_text: SensitiveString });
|
|
12
|
+
*
|
|
13
|
+
* // Users can pass raw strings (convenient):
|
|
14
|
+
* API.createPassword({ plain_text: "my-secret" })
|
|
15
|
+
*
|
|
16
|
+
* // Or Redacted values (explicit):
|
|
17
|
+
* API.createPassword({ plain_text: Redacted.make("my-secret") })
|
|
18
|
+
*
|
|
19
|
+
* // Response values are always Redacted (safe):
|
|
20
|
+
* console.log(result.plain_text); // logs "<redacted>"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import * as Redacted from "effect/Redacted";
|
|
24
|
+
import * as S from "effect/Schema";
|
|
25
|
+
/**
|
|
26
|
+
* Sensitive - Marks data as sensitive, wrapping in Effect's Redacted type.
|
|
27
|
+
*
|
|
28
|
+
* This schema provides a convenient way to handle sensitive data:
|
|
29
|
+
* - TypeScript type: `A | Redacted.Redacted<A>` (accepts both for inputs)
|
|
30
|
+
* - Decode (responses): Always wraps wire value in Redacted
|
|
31
|
+
* - Encode (requests): Accepts BOTH raw values and Redacted, extracts the raw value
|
|
32
|
+
*
|
|
33
|
+
* The union type allows users to conveniently pass plain values for inputs while
|
|
34
|
+
* still getting proper Redacted types for outputs. Response values will always
|
|
35
|
+
* be Redacted, which prevents accidental logging.
|
|
36
|
+
*/
|
|
37
|
+
export declare const Sensitive: <A>(schema: S.Schema<A>) => S.Schema<A | Redacted.Redacted<A>>;
|
|
38
|
+
/**
|
|
39
|
+
* Sensitive string - a string marked as sensitive.
|
|
40
|
+
* Wire format is plain string, TypeScript type is string | Redacted<string>.
|
|
41
|
+
* At runtime, decoded values are always Redacted<string>.
|
|
42
|
+
*/
|
|
43
|
+
export declare const SensitiveString: S.Schema<string | Redacted.Redacted<string>>;
|
|
44
|
+
/**
|
|
45
|
+
* Sensitive nullable string - a nullable string marked as sensitive.
|
|
46
|
+
* Wire format is plain string | null, TypeScript type is string | null | Redacted<string>.
|
|
47
|
+
* At runtime, decoded non-null values are always Redacted<string>.
|
|
48
|
+
*/
|
|
49
|
+
export declare const SensitiveNullableString: S.NullOr<S.Schema<string | Redacted.Redacted<string>>>;
|
|
50
|
+
//# sourceMappingURL=sensitive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitive.d.ts","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,CAAC,MAAM,eAAe,CAAC;AAGnC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,4DAiBrB,CAAC;AAEP;;;;GAIG;AACH,eAAO,MAAM,eAAe,8CAE1B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,wDAElC,CAAC"}
|
package/lib/sensitive.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitive data schemas for handling credentials and secrets.
|
|
3
|
+
*
|
|
4
|
+
* This module provides schemas that wrap sensitive data in Effect's Redacted type,
|
|
5
|
+
* preventing accidental logging of secrets like passwords and tokens.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { SensitiveString } from "@distilled.cloud/core/sensitive";
|
|
10
|
+
*
|
|
11
|
+
* const Password = Schema.Struct({ plain_text: SensitiveString });
|
|
12
|
+
*
|
|
13
|
+
* // Users can pass raw strings (convenient):
|
|
14
|
+
* API.createPassword({ plain_text: "my-secret" })
|
|
15
|
+
*
|
|
16
|
+
* // Or Redacted values (explicit):
|
|
17
|
+
* API.createPassword({ plain_text: Redacted.make("my-secret") })
|
|
18
|
+
*
|
|
19
|
+
* // Response values are always Redacted (safe):
|
|
20
|
+
* console.log(result.plain_text); // logs "<redacted>"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import * as Redacted from "effect/Redacted";
|
|
24
|
+
import * as S from "effect/Schema";
|
|
25
|
+
import * as SchemaTransformation from "effect/SchemaTransformation";
|
|
26
|
+
/**
|
|
27
|
+
* Sensitive - Marks data as sensitive, wrapping in Effect's Redacted type.
|
|
28
|
+
*
|
|
29
|
+
* This schema provides a convenient way to handle sensitive data:
|
|
30
|
+
* - TypeScript type: `A | Redacted.Redacted<A>` (accepts both for inputs)
|
|
31
|
+
* - Decode (responses): Always wraps wire value in Redacted
|
|
32
|
+
* - Encode (requests): Accepts BOTH raw values and Redacted, extracts the raw value
|
|
33
|
+
*
|
|
34
|
+
* The union type allows users to conveniently pass plain values for inputs while
|
|
35
|
+
* still getting proper Redacted types for outputs. Response values will always
|
|
36
|
+
* be Redacted, which prevents accidental logging.
|
|
37
|
+
*/
|
|
38
|
+
export const Sensitive = (schema) => schema
|
|
39
|
+
.pipe(S.decodeTo(S.Union([S.toType(schema), S.Redacted(S.toType(schema))]), SchemaTransformation.transform({
|
|
40
|
+
// Decode: wire format -> always wrap in Redacted
|
|
41
|
+
decode: (a) => Redacted.make(a),
|
|
42
|
+
// Encode: accept both raw and Redacted -> extract raw value
|
|
43
|
+
encode: (v) => (Redacted.isRedacted(v) ? Redacted.value(v) : v),
|
|
44
|
+
})))
|
|
45
|
+
.annotate({
|
|
46
|
+
identifier: `Sensitive<${schema.ast.annotations?.identifier ?? "unknown"}>`,
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Sensitive string - a string marked as sensitive.
|
|
50
|
+
* Wire format is plain string, TypeScript type is string | Redacted<string>.
|
|
51
|
+
* At runtime, decoded values are always Redacted<string>.
|
|
52
|
+
*/
|
|
53
|
+
export const SensitiveString = Sensitive(S.String).annotate({
|
|
54
|
+
identifier: "SensitiveString",
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Sensitive nullable string - a nullable string marked as sensitive.
|
|
58
|
+
* Wire format is plain string | null, TypeScript type is string | null | Redacted<string>.
|
|
59
|
+
* At runtime, decoded non-null values are always Redacted<string>.
|
|
60
|
+
*/
|
|
61
|
+
export const SensitiveNullableString = S.NullOr(SensitiveString).annotate({
|
|
62
|
+
identifier: "SensitiveNullableString",
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=sensitive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitive.js","sourceRoot":"","sources":["../src/sensitive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,CAAC,MAAM,eAAe,CAAC;AACnC,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,MAAmB,EACiB,EAAE,CACtC,MAAM;KACH,IAAI,CACH,CAAC,CAAC,QAAQ,CACR,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EACzD,oBAAoB,CAAC,SAAS,CAAC;IAC7B,iDAAiD;IACjD,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAQ;IACtC,4DAA4D;IAC5D,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAChE,CAAC,CACH,CACF;KACA,QAAQ,CAAC;IACR,UAAU,EAAE,aAAa,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,IAAI,SAAS,GAAG;CAC5E,CAAC,CAAC;AAEP;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC;IAC1D,UAAU,EAAE,iBAAiB;CAC9B,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC;IACxE,UAAU,EAAE,yBAAyB;CACtC,CAAC,CAAC"}
|