@databricks/sdk-core 0.0.0-dev → 0.1.0-dev.2

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.
Files changed (164) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +11 -1
  3. package/dist/api/execute.d.ts +12 -0
  4. package/dist/api/execute.d.ts.map +1 -0
  5. package/dist/api/execute.js +77 -0
  6. package/dist/api/execute.js.map +1 -0
  7. package/dist/api/index.d.ts +12 -0
  8. package/dist/api/index.d.ts.map +1 -0
  9. package/dist/api/index.js +8 -0
  10. package/dist/api/index.js.map +1 -0
  11. package/dist/api/limiter.d.ts +9 -0
  12. package/dist/api/limiter.d.ts.map +1 -0
  13. package/dist/api/limiter.js +2 -0
  14. package/dist/api/limiter.js.map +1 -0
  15. package/dist/api/options.d.ts +22 -0
  16. package/dist/api/options.d.ts.map +1 -0
  17. package/dist/api/options.js +2 -0
  18. package/dist/api/options.js.map +1 -0
  19. package/dist/api/retrier.d.ts +58 -0
  20. package/dist/api/retrier.d.ts.map +1 -0
  21. package/dist/api/retrier.js +70 -0
  22. package/dist/api/retrier.js.map +1 -0
  23. package/dist/apierror/apierror.d.ts +53 -0
  24. package/dist/apierror/apierror.d.ts.map +1 -0
  25. package/dist/apierror/apierror.js +217 -0
  26. package/dist/apierror/apierror.js.map +1 -0
  27. package/dist/apierror/codes/codes.d.ts +140 -0
  28. package/dist/apierror/codes/codes.d.ts.map +1 -0
  29. package/dist/apierror/codes/codes.js +167 -0
  30. package/dist/apierror/codes/codes.js.map +1 -0
  31. package/dist/apierror/codes/index.d.ts +7 -0
  32. package/dist/apierror/codes/index.d.ts.map +1 -0
  33. package/dist/apierror/codes/index.js +7 -0
  34. package/dist/apierror/codes/index.js.map +1 -0
  35. package/dist/apierror/details.d.ts +177 -0
  36. package/dist/apierror/details.d.ts.map +1 -0
  37. package/dist/apierror/details.js +250 -0
  38. package/dist/apierror/details.js.map +1 -0
  39. package/dist/apierror/index.d.ts +8 -0
  40. package/dist/apierror/index.d.ts.map +1 -0
  41. package/dist/apierror/index.js +7 -0
  42. package/dist/apierror/index.js.map +1 -0
  43. package/dist/clientinfo/agent.d.ts +56 -0
  44. package/dist/clientinfo/agent.d.ts.map +1 -0
  45. package/dist/clientinfo/agent.js +114 -0
  46. package/dist/clientinfo/agent.js.map +1 -0
  47. package/dist/clientinfo/base.d.ts +39 -0
  48. package/dist/clientinfo/base.d.ts.map +1 -0
  49. package/dist/clientinfo/base.js +62 -0
  50. package/dist/clientinfo/base.js.map +1 -0
  51. package/dist/clientinfo/clientinfo.d.ts +61 -0
  52. package/dist/clientinfo/clientinfo.d.ts.map +1 -0
  53. package/dist/clientinfo/clientinfo.js +96 -0
  54. package/dist/clientinfo/clientinfo.js.map +1 -0
  55. package/dist/clientinfo/default.browser.d.ts +17 -0
  56. package/dist/clientinfo/default.browser.d.ts.map +1 -0
  57. package/dist/clientinfo/default.browser.js +20 -0
  58. package/dist/clientinfo/default.browser.js.map +1 -0
  59. package/dist/clientinfo/default.d.ts +14 -0
  60. package/dist/clientinfo/default.d.ts.map +1 -0
  61. package/dist/clientinfo/default.js +104 -0
  62. package/dist/clientinfo/default.js.map +1 -0
  63. package/dist/clientinfo/index.browser.d.ts +5 -0
  64. package/dist/clientinfo/index.browser.d.ts.map +1 -0
  65. package/dist/clientinfo/index.browser.js +4 -0
  66. package/dist/clientinfo/index.browser.js.map +1 -0
  67. package/dist/clientinfo/index.d.ts +5 -0
  68. package/dist/clientinfo/index.d.ts.map +1 -0
  69. package/dist/clientinfo/index.js +4 -0
  70. package/dist/clientinfo/index.js.map +1 -0
  71. package/dist/http/http.d.ts +40 -0
  72. package/dist/http/http.d.ts.map +1 -0
  73. package/dist/http/http.js +37 -0
  74. package/dist/http/http.js.map +1 -0
  75. package/dist/http/index.d.ts +8 -0
  76. package/dist/http/index.d.ts.map +1 -0
  77. package/dist/http/index.js +7 -0
  78. package/dist/http/index.js.map +1 -0
  79. package/dist/index.d.ts +6 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +7 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/logger/index.d.ts +8 -0
  84. package/dist/logger/index.d.ts.map +1 -0
  85. package/dist/logger/index.js +7 -0
  86. package/dist/logger/index.js.map +1 -0
  87. package/dist/logger/logger.d.ts +49 -0
  88. package/dist/logger/logger.d.ts.map +1 -0
  89. package/dist/logger/logger.js +65 -0
  90. package/dist/logger/logger.js.map +1 -0
  91. package/dist/profiles/errors.d.ts +17 -0
  92. package/dist/profiles/errors.d.ts.map +1 -0
  93. package/dist/profiles/errors.js +19 -0
  94. package/dist/profiles/errors.js.map +1 -0
  95. package/dist/profiles/index.browser.d.ts +10 -0
  96. package/dist/profiles/index.browser.d.ts.map +1 -0
  97. package/dist/profiles/index.browser.js +8 -0
  98. package/dist/profiles/index.browser.js.map +1 -0
  99. package/dist/profiles/index.d.ts +15 -0
  100. package/dist/profiles/index.d.ts.map +1 -0
  101. package/dist/profiles/index.js +13 -0
  102. package/dist/profiles/index.js.map +1 -0
  103. package/dist/profiles/ini.d.ts +36 -0
  104. package/dist/profiles/ini.d.ts.map +1 -0
  105. package/dist/profiles/ini.js +113 -0
  106. package/dist/profiles/ini.js.map +1 -0
  107. package/dist/profiles/profile.d.ts +131 -0
  108. package/dist/profiles/profile.d.ts.map +1 -0
  109. package/dist/profiles/profile.js +307 -0
  110. package/dist/profiles/profile.js.map +1 -0
  111. package/dist/profiles/resolve.d.ts +29 -0
  112. package/dist/profiles/resolve.d.ts.map +1 -0
  113. package/dist/profiles/resolve.js +206 -0
  114. package/dist/profiles/resolve.js.map +1 -0
  115. package/dist/profiles/secret.d.ts +25 -0
  116. package/dist/profiles/secret.d.ts.map +1 -0
  117. package/dist/profiles/secret.js +38 -0
  118. package/dist/profiles/secret.js.map +1 -0
  119. package/dist/wkt/fieldmask.d.ts +32 -0
  120. package/dist/wkt/fieldmask.d.ts.map +1 -0
  121. package/dist/wkt/fieldmask.js +68 -0
  122. package/dist/wkt/fieldmask.js.map +1 -0
  123. package/dist/wkt/index.d.ts +4 -0
  124. package/dist/wkt/index.d.ts.map +1 -0
  125. package/dist/wkt/index.js +2 -0
  126. package/dist/wkt/index.js.map +1 -0
  127. package/dist/wkt/value.d.ts +13 -0
  128. package/dist/wkt/value.d.ts.map +1 -0
  129. package/dist/wkt/value.js +2 -0
  130. package/dist/wkt/value.js.map +1 -0
  131. package/package.json +82 -4
  132. package/src/api/execute.ts +102 -0
  133. package/src/api/index.ts +12 -0
  134. package/src/api/limiter.ts +8 -0
  135. package/src/api/options.ts +22 -0
  136. package/src/api/retrier.ts +108 -0
  137. package/src/apierror/apierror.ts +253 -0
  138. package/src/apierror/codes/codes.ts +189 -0
  139. package/src/apierror/codes/index.ts +7 -0
  140. package/src/apierror/details.ts +459 -0
  141. package/src/apierror/index.ts +24 -0
  142. package/src/clientinfo/agent.ts +125 -0
  143. package/src/clientinfo/base.ts +73 -0
  144. package/src/clientinfo/clientinfo.ts +129 -0
  145. package/src/clientinfo/default.browser.ts +24 -0
  146. package/src/clientinfo/default.ts +128 -0
  147. package/src/clientinfo/index.browser.ts +4 -0
  148. package/src/clientinfo/index.ts +4 -0
  149. package/src/http/http.ts +75 -0
  150. package/src/http/index.ts +8 -0
  151. package/src/index.ts +5 -0
  152. package/src/logger/index.ts +8 -0
  153. package/src/logger/logger.ts +99 -0
  154. package/src/profiles/errors.ts +28 -0
  155. package/src/profiles/index.browser.ts +10 -0
  156. package/src/profiles/index.ts +15 -0
  157. package/src/profiles/ini.ts +126 -0
  158. package/src/profiles/profile.ts +467 -0
  159. package/src/profiles/resolve.ts +251 -0
  160. package/src/profiles/secret.ts +40 -0
  161. package/src/wkt/fieldmask.ts +89 -0
  162. package/src/wkt/index.ts +3 -0
  163. package/src/wkt/value.ts +19 -0
  164. package/index.js +0 -1
@@ -0,0 +1,68 @@
1
+ // Remove duplicates and paths subsumed by a parent (e.g. "config" subsumes "config.numWorkers").
2
+ function normalize(paths) {
3
+ const unique = [...new Set(paths)].sort();
4
+ const result = [];
5
+ for (const path of unique) {
6
+ const isSubsumed = result.some(existing => path.startsWith(existing + '.'));
7
+ if (!isSubsumed) {
8
+ result.push(path);
9
+ }
10
+ }
11
+ return result;
12
+ }
13
+ // Walk a dot-separated typescript field name path against a schema, returning the equivalent wire-format path. Returns `undefined` when any segment fails: a name that isn't a field of the current message, or a non-terminal segment that doesn't reference another message.
14
+ function walkFieldMaskPath(schema, path) {
15
+ const segments = path.split('.');
16
+ const wireSegments = [];
17
+ let current = schema;
18
+ for (let i = 0; i < segments.length; i++) {
19
+ const seg = segments[i];
20
+ // Existence check before lookup: `current[seg]` is typed as FieldMaskSchemaField without noUncheckedIndexedAccess, so an undefined check downstream would be flagged "unnecessary".
21
+ if (!(seg in current))
22
+ return undefined;
23
+ const field = current[seg];
24
+ wireSegments.push(field.wire);
25
+ if (i < segments.length - 1) {
26
+ if (field.children === undefined)
27
+ return undefined;
28
+ current = field.children();
29
+ }
30
+ }
31
+ return wireSegments.join('.');
32
+ }
33
+ /**
34
+ * A field mask implementing google.protobuf.FieldMask semantics.
35
+ */
36
+ export class FieldMask {
37
+ // Stored post-translation, normalized wire-format paths.
38
+ paths;
39
+ constructor(paths) {
40
+ this.paths = paths;
41
+ }
42
+ /**
43
+ * Build a FieldMask from typescript field name paths against the target message's schema. Validates every path by walking each segment through the schema and throws Error when any segment fails.
44
+ *
45
+ * Reserved for generated per-message factories; user code should call the factory (e.g. `alertFieldMask(...)`), which supplies the schema before delegating here.
46
+ *
47
+ * @internal
48
+ */
49
+ static build(paths, schema) {
50
+ const normalized = normalize(paths);
51
+ const wire = [];
52
+ for (const p of normalized) {
53
+ const w = walkFieldMaskPath(schema, p);
54
+ if (w === undefined) {
55
+ throw new Error(`Unknown field path "${p}"`);
56
+ }
57
+ wire.push(w);
58
+ }
59
+ return new FieldMask(wire);
60
+ }
61
+ /**
62
+ * Serialize the mask to the wire-format string.
63
+ */
64
+ toString() {
65
+ return this.paths.join(',');
66
+ }
67
+ }
68
+ //# sourceMappingURL=fieldmask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldmask.js","sourceRoot":"","sources":["../../src/wkt/fieldmask.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,SAAS,SAAS,CAAC,KAAe;IAChC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAeD,+QAA+Q;AAC/Q,SAAS,iBAAiB,CACxB,MAAuB,EACvB,IAAY;IAEZ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,OAAO,GAAoB,MAAM,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxB,oLAAoL;QACpL,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YACnD,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IACD,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,SAAS;IAIpB,yDAAyD;IACxC,KAAK,CAAW;IAEjC,YAAoB,KAAe;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAI,KAAe,EAAE,MAAuB;QACtD,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC;YAC/C,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACf,CAAC;QACD,OAAO,IAAI,SAAS,CAAI,IAAI,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ export { FieldMask } from './fieldmask';
2
+ export type { FieldMaskSchema, FieldMaskSchemaField } from './fieldmask';
3
+ export type { JsonValue, JsonObject } from './value';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wkt/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,YAAY,EAAC,eAAe,EAAE,oBAAoB,EAAC,MAAM,aAAa,CAAC;AACvE,YAAY,EAAC,SAAS,EAAE,UAAU,EAAC,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { FieldMask } from './fieldmask';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wkt/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Represents any valid JSON value. Matches the JSON value space used by
3
+ * google.protobuf.Value.
4
+ */
5
+ export type JsonValue = null | number | string | boolean | JsonObject | JsonValue[];
6
+ /**
7
+ * Represents a JSON object with string keys and JSON values. Matches the
8
+ * structure used by google.protobuf.Struct.
9
+ */
10
+ export interface JsonObject {
11
+ [key: string]: JsonValue;
12
+ }
13
+ //# sourceMappingURL=value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value.d.ts","sourceRoot":"","sources":["../../src/wkt/value.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,IAAI,GACJ,MAAM,GACN,MAAM,GACN,OAAO,GACP,UAAU,GACV,SAAS,EAAE,CAAC;AAEhB;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value.js","sourceRoot":"","sources":["../../src/wkt/value.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,7 +1,85 @@
1
1
  {
2
2
  "name": "@databricks/sdk-core",
3
- "version": "0.0.0-dev",
4
- "description": "Bootstrap placeholder; real contents in a later release.",
5
- "main": "index.js",
6
- "license": "Apache-2.0"
3
+ "version": "0.1.0-dev.2",
4
+ "description": "Databricks core library for JavaScript/TypeScript",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./profiles": {
14
+ "types": "./dist/profiles/index.d.ts",
15
+ "import": "./dist/profiles/index.js"
16
+ },
17
+ "./profiles/browser": {
18
+ "types": "./dist/profiles/index.browser.d.ts",
19
+ "import": "./dist/profiles/index.browser.js"
20
+ },
21
+ "./wkt": {
22
+ "types": "./dist/wkt/index.d.ts",
23
+ "import": "./dist/wkt/index.js"
24
+ },
25
+ "./clientinfo": {
26
+ "browser": {
27
+ "types": "./dist/clientinfo/index.browser.d.ts",
28
+ "import": "./dist/clientinfo/index.browser.js"
29
+ },
30
+ "default": {
31
+ "types": "./dist/clientinfo/index.d.ts",
32
+ "import": "./dist/clientinfo/index.js"
33
+ }
34
+ },
35
+ "./clientinfo/browser": {
36
+ "types": "./dist/clientinfo/index.browser.d.ts",
37
+ "import": "./dist/clientinfo/index.browser.js"
38
+ },
39
+ "./http": {
40
+ "types": "./dist/http/index.d.ts",
41
+ "import": "./dist/http/index.js"
42
+ },
43
+ "./logger": {
44
+ "types": "./dist/logger/index.d.ts",
45
+ "import": "./dist/logger/index.js"
46
+ },
47
+ "./api": {
48
+ "types": "./dist/api/index.d.ts",
49
+ "import": "./dist/api/index.js"
50
+ },
51
+ "./apierror": {
52
+ "types": "./dist/apierror/index.d.ts",
53
+ "import": "./dist/apierror/index.js"
54
+ },
55
+ "./apierror/codes": {
56
+ "types": "./dist/apierror/codes/index.d.ts",
57
+ "import": "./dist/apierror/codes/index.js"
58
+ }
59
+ },
60
+ "files": [
61
+ "dist",
62
+ "src",
63
+ "LICENSE"
64
+ ],
65
+ "scripts": {
66
+ "build": "tsc -b",
67
+ "lint": "eslint src tests --ext .ts",
68
+ "lint:fix": "eslint src tests --ext .ts --fix",
69
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
70
+ "format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
71
+ "test": "vitest run",
72
+ "test:browser": "vitest run --config vitest.config.browser.ts",
73
+ "typecheck": "tsc --noEmit",
74
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
75
+ },
76
+ "author": "Databricks",
77
+ "license": "Apache-2.0",
78
+ "engines": {
79
+ "node": ">=22.0.0"
80
+ },
81
+ "dependencies": {
82
+ "json-bigint": "^1.0.0",
83
+ "zod": "^4.3.6"
84
+ }
7
85
  }
@@ -0,0 +1,102 @@
1
+ import type {Options} from './options';
2
+ import type {Retrier} from './retrier';
3
+
4
+ /** Call represents a call to a Databricks API. */
5
+ export type Call = (signal?: AbortSignal) => Promise<void>;
6
+
7
+ // Coerces an unknown value to an Error instance.
8
+ function toError(value: unknown): Error {
9
+ return value instanceof Error ? value : new Error(String(value));
10
+ }
11
+
12
+ /**
13
+ * Sleeps for the given duration. It is mostly equivalent to setTimeout, but
14
+ * can be interrupted by the AbortSignal if the signal aborts before the
15
+ * duration elapses.
16
+ */
17
+ export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
18
+ return new Promise<void>((resolve, reject) => {
19
+ if (signal?.aborted === true) {
20
+ reject(toError(signal.reason));
21
+ return;
22
+ }
23
+ if (signal === undefined) {
24
+ setTimeout(resolve, ms);
25
+ return;
26
+ }
27
+ const onAbort = (): void => {
28
+ clearTimeout(timer);
29
+ reject(toError(signal.reason));
30
+ };
31
+ const timer = setTimeout(() => {
32
+ signal.removeEventListener('abort', onAbort);
33
+ resolve();
34
+ }, ms);
35
+ signal.addEventListener('abort', onAbort, {once: true});
36
+ });
37
+ }
38
+
39
+ // Sleeper is a convenience type for readability.
40
+ type Sleeper = (ms: number, signal?: AbortSignal) => Promise<void>;
41
+
42
+ /** Makes a call to a Databricks API using the given options. */
43
+ export async function execute(
44
+ signal: AbortSignal | undefined,
45
+ call: Call,
46
+ options?: Options
47
+ ): Promise<void> {
48
+ const opts: Options = {...options};
49
+ return executeImpl(signal, call, opts, sleep);
50
+ }
51
+
52
+ /**
53
+ * The actual implementation of execute. Its purpose is to ease testing by
54
+ * providing a convenient way to mock the sleeping logic.
55
+ */
56
+ async function executeImpl(
57
+ signal: AbortSignal | undefined,
58
+ apiCall: Call,
59
+ opts: Options,
60
+ sleep: Sleeper
61
+ ): Promise<void> {
62
+ // Optionally combine the signal with a timeout signal. If the signal
63
+ // already has a deadline, that deadline is updated to the minimum of the
64
+ // signal's deadline and the timeout.
65
+ if (opts.timeout !== undefined && opts.timeout > 0) {
66
+ const timeoutSignal = AbortSignal.timeout(opts.timeout);
67
+ signal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
68
+ }
69
+
70
+ // Get a new retrier for this specific execution. This is instantiated
71
+ // lazily if and when the first call execution returns an error.
72
+ let retrier: Retrier | undefined;
73
+
74
+ for (;;) {
75
+ if (opts.rateLimiter) {
76
+ await opts.rateLimiter.wait(signal);
77
+ }
78
+
79
+ try {
80
+ await apiCall(signal);
81
+ return; // Nothing to retry.
82
+ } catch (err: unknown) {
83
+ const error = toError(err);
84
+
85
+ if (retrier === undefined) {
86
+ if (opts.retrier) {
87
+ retrier = opts.retrier(); // Lazily instantiate the retrier.
88
+ }
89
+ if (retrier === undefined) {
90
+ throw error; // No retrier == no retry.
91
+ }
92
+ }
93
+
94
+ const delay = retrier.isRetriable(error);
95
+ if (delay === undefined) {
96
+ throw error; // Not retriable.
97
+ }
98
+
99
+ await sleep(delay, signal);
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Databricks API client utilities.
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ export {execute} from './execute';
8
+ export type {Call} from './execute';
9
+ export type {Limiter} from './limiter';
10
+ export type {Options} from './options';
11
+ export {BackoffPolicy, retryOn} from './retrier';
12
+ export type {BackoffPolicyOptions, Retrier} from './retrier';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Limiter is anything that can wait. It is typically used to implement
3
+ * client-side rate limiting. Implementations of this interface must be
4
+ * safe to call concurrently.
5
+ */
6
+ export interface Limiter {
7
+ wait(signal?: AbortSignal): Promise<void>;
8
+ }
@@ -0,0 +1,22 @@
1
+ import type {Limiter} from './limiter';
2
+ import type {Retrier} from './retrier';
3
+
4
+ /** Options to control the behavior of an API call. */
5
+ export interface Options {
6
+ /**
7
+ * Provides a new Retrier to be used to execute a Call. The function is
8
+ * called for each Call and must be safe to call concurrently. The retrier
9
+ * must be fresh within the context of an execute call (e.g. no need to
10
+ * reset a BackoffPolicy).
11
+ */
12
+ retrier?: (() => Retrier) | undefined;
13
+ /** The rate limiter used to potentially rate limit the API call. */
14
+ rateLimiter?: Limiter | undefined;
15
+ /**
16
+ * Timeout duration in milliseconds. If the signal already has a deadline,
17
+ * that deadline is updated to the minimum of the signal's deadline and the
18
+ * timeout. The timeout covers the whole Call execution; it is not a timeout
19
+ * for each intermediary API call.
20
+ */
21
+ timeout?: number | undefined;
22
+ }
@@ -0,0 +1,108 @@
1
+ /** Options for configuring a {@link BackoffPolicy}. */
2
+ export interface BackoffPolicyOptions {
3
+ /** Initial delay in milliseconds; defaults to 1000. */
4
+ initial?: number;
5
+
6
+ /** Maximum delay in milliseconds; defaults to 60000. */
7
+ maximum?: number;
8
+
9
+ /**
10
+ * Factor by which the delay is multiplied after each retry. The value must
11
+ * be greater or equal to 1. If not, it defaults to 2.
12
+ */
13
+ factor?: number;
14
+ }
15
+
16
+ // Random number generation, wrapped in an object for testability.
17
+ export const rand = {
18
+ // Returns a random integer in [0, n).
19
+ int(n: number): number {
20
+ return Math.floor(Math.random() * n);
21
+ },
22
+ };
23
+
24
+ /**
25
+ * BackoffPolicy implements an exponential backoff policy. The delay between
26
+ * retries is randomly computed between 0 and the "exponential delay" as
27
+ * recommended in [Exponential Backoff And Jitter]. The retry delay starts from
28
+ * initial and grows exponentially by factor at every retry. The maximum retry
29
+ * delay is capped by maximum.
30
+ *
31
+ * There is no parameter to limit the number of retries. This is intended as
32
+ * such logic should be implemented upstream (e.g. in a Retrier).
33
+ *
34
+ * [Exponential Backoff And Jitter]: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
35
+ */
36
+ export class BackoffPolicy {
37
+ /** Initial delay in milliseconds. */
38
+ readonly initial: number;
39
+
40
+ /** Maximum delay in milliseconds. */
41
+ readonly maximum: number;
42
+
43
+ /** Factor by which the delay is multiplied after each retry. */
44
+ readonly factor: number;
45
+
46
+ // Current delay before the next retry.
47
+ private current: number;
48
+
49
+ constructor(options?: BackoffPolicyOptions) {
50
+ let initial = options?.initial ?? 1000; // Default initial delay of 1 second.
51
+ const maximum = options?.maximum ?? 60000; // Default maximum delay of 60 seconds.
52
+
53
+ if (initial > maximum) {
54
+ // Initial cannot be greater than maximum.
55
+ initial = maximum;
56
+ }
57
+
58
+ this.initial = initial;
59
+ this.maximum = maximum;
60
+ this.factor =
61
+ options?.factor !== undefined && options.factor >= 1 ? options.factor : 2;
62
+ this.current = this.initial;
63
+ }
64
+
65
+ /** Returns a random delay in [0, current] and grows the current delay. */
66
+ delay(): number {
67
+ // Random duration in the range [0, this.current].
68
+ const d = rand.int(this.current + 1);
69
+
70
+ // Grow delay for the next call.
71
+ this.current = Math.min(this.current * this.factor, this.maximum);
72
+
73
+ return d;
74
+ }
75
+ }
76
+
77
+ /** Retrier defines a retry behavior. */
78
+ export interface Retrier {
79
+ /**
80
+ * Returns the delay in milliseconds before the next retry, or undefined if
81
+ * the error is not retriable. Implementations should assume that the given
82
+ * error is never undefined.
83
+ */
84
+ isRetriable(err: Error): number | undefined;
85
+ }
86
+
87
+ /**
88
+ * Returns a Retrier that retries based on the isRetriable predicate and relies
89
+ * on an internal backoff policy to decide how long to wait between retries.
90
+ *
91
+ * Important: the retrier has its own backoff policy which cannot be trivially
92
+ * reset by design. Users who need to reset the backoff policy should rather
93
+ * create a new retrier.
94
+ */
95
+ export function retryOn(
96
+ options: BackoffPolicyOptions,
97
+ isRetriable: (err: Error) => boolean
98
+ ): Retrier {
99
+ const bp = new BackoffPolicy(options);
100
+ return {
101
+ isRetriable(err: Error): number | undefined {
102
+ if (!isRetriable(err)) {
103
+ return undefined;
104
+ }
105
+ return bp.delay();
106
+ },
107
+ };
108
+ }