@useairfoil/connector-kit 0.4.0 → 0.5.1
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/METRICS.md +78 -0
- package/README.md +450 -88
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +3 -0
- package/dist/auth-DvU_CZ7C.js +42 -0
- package/dist/auth-DvU_CZ7C.js.map +1 -0
- package/dist/chunk-Bp6m_JJh.js +13 -0
- package/dist/connector-app/index.d.ts +14 -0
- package/dist/connector-app/index.js +11 -0
- package/dist/connector-app-d7Z-SZLQ.js +64 -0
- package/dist/connector-app-d7Z-SZLQ.js.map +1 -0
- package/dist/constants-BRhIX_rz.js +27 -0
- package/dist/constants-BRhIX_rz.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors-DHWylqRZ.js +8 -0
- package/dist/errors-DHWylqRZ.js.map +1 -0
- package/dist/index-Byr0Lf0C.d.ts +25 -0
- package/dist/index-CBT-JX-T.d.ts +173 -0
- package/dist/index-CTHVudvQ.d.ts +41 -0
- package/dist/index-CTLYQ74P.d.ts +80 -0
- package/dist/index-Coh_SkBs.d.ts +95 -0
- package/dist/index-D54ySAKn.d.ts +14 -0
- package/dist/index-DtJX_tic.d.ts +153 -0
- package/dist/index-J42AZaXU.d.ts +38 -0
- package/dist/index-fIIBVAai.d.ts +25 -0
- package/dist/index-o1-Z3n7V.d.ts +55 -0
- package/dist/index.d.ts +14 -165
- package/dist/index.js +50 -228
- package/dist/index.js.map +1 -1
- package/dist/ingestion/index.d.ts +6 -0
- package/dist/ingestion/index.js +10 -0
- package/dist/ingestion-BQo4cbGw.js +200 -0
- package/dist/ingestion-BQo4cbGw.js.map +1 -0
- package/dist/manifest/index.d.ts +2 -0
- package/dist/manifest/index.js +4 -0
- package/dist/manifest-ByE6YPG0.js +221 -0
- package/dist/manifest-ByE6YPG0.js.map +1 -0
- package/dist/metrics-CVAk1ALR.d.ts +53 -0
- package/dist/metrics-CWPy2Aqc.js +96 -0
- package/dist/metrics-CWPy2Aqc.js.map +1 -0
- package/dist/metrics.d.ts +4 -0
- package/dist/metrics.js +3 -0
- package/dist/publisher/index.d.ts +5 -0
- package/dist/publisher/index.js +6 -0
- package/dist/publisher-BYT3RLVO.js +131 -0
- package/dist/publisher-BYT3RLVO.js.map +1 -0
- package/dist/runtime-config/index.d.ts +2 -0
- package/dist/runtime-config/index.js +4 -0
- package/dist/runtime-config-BpB-d_bF.js +51 -0
- package/dist/runtime-config-BpB-d_bF.js.map +1 -0
- package/dist/server-CXTQ7odl.js +183 -0
- package/dist/server-CXTQ7odl.js.map +1 -0
- package/dist/service-DuFiQwid.js +191 -0
- package/dist/service-DuFiQwid.js.map +1 -0
- package/dist/service-IE5qaf9x.d.ts +32 -0
- package/dist/state-store/index.d.ts +3 -0
- package/dist/state-store/index.js +5 -0
- package/dist/state-store-yl6LiTQ0.js +198 -0
- package/dist/state-store-yl6LiTQ0.js.map +1 -0
- package/dist/status/index.d.ts +5 -0
- package/dist/status/index.js +6 -0
- package/dist/status-B-oZBc33.js +84 -0
- package/dist/status-B-oZBc33.js.map +1 -0
- package/dist/types-B35J5YPu.d.ts +174 -0
- package/dist/webhook/index.d.ts +6 -0
- package/dist/webhook/index.js +8 -0
- package/dist/webhook-DI-Afxkg.js +13 -0
- package/dist/webhook-DI-Afxkg.js.map +1 -0
- package/package.json +66 -8
- package/src/auth/index.ts +1 -0
- package/src/auth/token-cache.ts +54 -0
- package/src/connector-app/check.ts +76 -0
- package/src/connector-app/index.ts +2 -0
- package/src/connector-app/start.ts +42 -0
- package/src/core/builder.ts +81 -9
- package/src/core/index.ts +22 -0
- package/src/core/types.ts +204 -76
- package/src/errors/index.ts +1 -0
- package/src/index.ts +13 -28
- package/src/ingestion/engine.ts +409 -174
- package/src/ingestion/index.ts +1 -0
- package/src/manifest/config.ts +232 -0
- package/src/manifest/index.ts +14 -0
- package/src/manifest/manifest.ts +31 -0
- package/src/manifest/number-schema.ts +17 -0
- package/src/manifest/schema.ts +160 -0
- package/src/metrics.ts +128 -0
- package/src/publisher/console.ts +18 -0
- package/src/publisher/index.ts +7 -0
- package/src/publisher/instrumented.ts +68 -0
- package/src/publisher/service.ts +30 -13
- package/src/publisher/wings.ts +159 -72
- package/src/runtime/context.ts +15 -0
- package/src/runtime-config/constants.ts +27 -0
- package/src/runtime-config/error.ts +13 -0
- package/src/runtime-config/index.ts +3 -0
- package/src/runtime-config/layer.ts +56 -0
- package/src/state-store/index.ts +3 -0
- package/src/state-store/keys.ts +22 -0
- package/src/state-store/layer-key-value-store.ts +132 -0
- package/src/state-store/layer-memory.ts +11 -0
- package/src/state-store/layer-sql.ts +50 -0
- package/src/state-store/schema.ts +57 -0
- package/src/state-store/service.ts +51 -0
- package/src/state-store/state.ts +17 -0
- package/src/status/index.ts +2 -0
- package/src/status/route.ts +77 -0
- package/src/status/types.ts +33 -0
- package/src/telemetry.ts +288 -0
- package/src/webhook/index.ts +8 -0
- package/src/webhook/server.ts +209 -39
- package/src/webhook/types.ts +6 -17
- package/src/ingestion/state-store.ts +0 -36
- package/src/streams/pull-stream.ts +0 -54
- package/src/streams/webhook-queue.ts +0 -14
- /package/src/{core/errors.ts → errors/connector-error.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useairfoil/connector-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"repository": "useairfoil/typescript-sdk",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src",
|
|
8
|
+
"METRICS.md",
|
|
8
9
|
"README.md"
|
|
9
10
|
],
|
|
10
11
|
"type": "module",
|
|
@@ -15,6 +16,61 @@
|
|
|
15
16
|
"types": "./dist/index.d.ts",
|
|
16
17
|
"import": "./dist/index.js",
|
|
17
18
|
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./auth": {
|
|
21
|
+
"types": "./dist/auth/index.d.ts",
|
|
22
|
+
"import": "./dist/auth/index.js",
|
|
23
|
+
"default": "./dist/auth/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./connector-app": {
|
|
26
|
+
"types": "./dist/connector-app/index.d.ts",
|
|
27
|
+
"import": "./dist/connector-app/index.js",
|
|
28
|
+
"default": "./dist/connector-app/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./ingestion": {
|
|
31
|
+
"types": "./dist/ingestion/index.d.ts",
|
|
32
|
+
"import": "./dist/ingestion/index.js",
|
|
33
|
+
"default": "./dist/ingestion/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./manifest": {
|
|
36
|
+
"types": "./dist/manifest/index.d.ts",
|
|
37
|
+
"import": "./dist/manifest/index.js",
|
|
38
|
+
"default": "./dist/manifest/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./metrics": {
|
|
41
|
+
"types": "./dist/metrics.d.ts",
|
|
42
|
+
"import": "./dist/metrics.js",
|
|
43
|
+
"default": "./dist/metrics.js"
|
|
44
|
+
},
|
|
45
|
+
"./publisher": {
|
|
46
|
+
"types": "./dist/publisher/index.d.ts",
|
|
47
|
+
"import": "./dist/publisher/index.js",
|
|
48
|
+
"default": "./dist/publisher/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./runtime-config": {
|
|
51
|
+
"types": "./dist/runtime-config/index.d.ts",
|
|
52
|
+
"import": "./dist/runtime-config/index.js",
|
|
53
|
+
"default": "./dist/runtime-config/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./state-store": {
|
|
56
|
+
"types": "./dist/state-store/index.d.ts",
|
|
57
|
+
"import": "./dist/state-store/index.js",
|
|
58
|
+
"default": "./dist/state-store/index.js"
|
|
59
|
+
},
|
|
60
|
+
"./status": {
|
|
61
|
+
"types": "./dist/status/index.d.ts",
|
|
62
|
+
"import": "./dist/status/index.js",
|
|
63
|
+
"default": "./dist/status/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./webhook": {
|
|
66
|
+
"types": "./dist/webhook/index.d.ts",
|
|
67
|
+
"import": "./dist/webhook/index.js",
|
|
68
|
+
"default": "./dist/webhook/index.js"
|
|
69
|
+
},
|
|
70
|
+
"./errors": {
|
|
71
|
+
"types": "./dist/errors/index.d.ts",
|
|
72
|
+
"import": "./dist/errors/index.js",
|
|
73
|
+
"default": "./dist/errors/index.js"
|
|
18
74
|
}
|
|
19
75
|
},
|
|
20
76
|
"scripts": {
|
|
@@ -24,19 +80,21 @@
|
|
|
24
80
|
"typecheck": "tsc --noEmit"
|
|
25
81
|
},
|
|
26
82
|
"dependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@useairfoil/
|
|
29
|
-
"
|
|
30
|
-
"json-stable-stringify": "^1.3.0"
|
|
83
|
+
"@effect/platform-node": "^4.0.0-rc.108",
|
|
84
|
+
"@useairfoil/flight": "0.4.4",
|
|
85
|
+
"@useairfoil/wings": "0.4.2"
|
|
31
86
|
},
|
|
32
87
|
"devDependencies": {
|
|
33
|
-
"@effect/
|
|
88
|
+
"@effect/sql-pg": "^4.0.0-rc.108",
|
|
89
|
+
"@effect/vitest": "^4.0.0-rc.108",
|
|
34
90
|
"@types/node": "^24.2.0",
|
|
91
|
+
"effect": "^4.0.0-rc.108",
|
|
92
|
+
"testcontainers": "^11.14.0",
|
|
35
93
|
"tsdown": "^0.15.6",
|
|
36
|
-
"vitest": "^
|
|
94
|
+
"vitest": "^4.1.0"
|
|
37
95
|
},
|
|
38
96
|
"peerDependencies": {
|
|
39
|
-
"effect": "4.0.0-
|
|
97
|
+
"effect": "^4.0.0-rc.108"
|
|
40
98
|
},
|
|
41
99
|
"peerDependenciesMeta": {
|
|
42
100
|
"effect": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./token-cache";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Cache, Duration, Effect, Exit, Number, Redacted } from "effect";
|
|
2
|
+
|
|
3
|
+
export interface ExpiringToken {
|
|
4
|
+
/** The credential kept in memory by the cache. */
|
|
5
|
+
readonly value: Redacted.Redacted<string>;
|
|
6
|
+
/** The lifetime reported by the provider. */
|
|
7
|
+
readonly expiresIn: Duration.Duration;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TokenCache<E> {
|
|
11
|
+
/** Returns the cached token or performs one shared acquisition. */
|
|
12
|
+
readonly get: Effect.Effect<Redacted.Redacted<string>, E>;
|
|
13
|
+
/** Removes the cached token so the next `get` reacquires it. */
|
|
14
|
+
readonly invalidate: Effect.Effect<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a lazy, in-memory token cache around an acquisition effect.
|
|
19
|
+
*
|
|
20
|
+
* `refreshFactor` controls how much of the provider lifetime is cached. It is
|
|
21
|
+
* clamped between `0` and `1`.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const cache = yield* makeTokenCache({
|
|
26
|
+
* acquire: exchangeCredentials,
|
|
27
|
+
* refreshFactor: 0.5,
|
|
28
|
+
* })
|
|
29
|
+
*
|
|
30
|
+
* const token = yield* cache.get
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const makeTokenCache = <E, R>(options: {
|
|
34
|
+
readonly acquire: Effect.Effect<ExpiringToken, E, R>;
|
|
35
|
+
readonly refreshFactor?: number;
|
|
36
|
+
}): Effect.Effect<TokenCache<E>, never, R> =>
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
const refreshFactor = Number.clamp(options.refreshFactor ?? 0.5, {
|
|
39
|
+
minimum: 0,
|
|
40
|
+
maximum: 1,
|
|
41
|
+
});
|
|
42
|
+
const cache = yield* Cache.makeWith((_: void) => options.acquire, {
|
|
43
|
+
capacity: 1,
|
|
44
|
+
timeToLive: (exit) =>
|
|
45
|
+
Exit.isSuccess(exit)
|
|
46
|
+
? Duration.millis(Duration.toMillis(exit.value.expiresIn) * refreshFactor)
|
|
47
|
+
: Duration.zero,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
get: Cache.get(cache, undefined).pipe(Effect.map((token) => token.value)),
|
|
52
|
+
invalidate: Cache.invalidate(cache, undefined),
|
|
53
|
+
};
|
|
54
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Tuple } from "effect";
|
|
2
|
+
|
|
3
|
+
import type { ConnectorDefinition, ResourceDefinition, ResourceName } from "../core/types";
|
|
4
|
+
|
|
5
|
+
export type ResourceCheckResult =
|
|
6
|
+
| { readonly _tag: "ok" }
|
|
7
|
+
| { readonly _tag: "error"; readonly message: string };
|
|
8
|
+
|
|
9
|
+
export type CheckOptions<Name extends string> = {
|
|
10
|
+
readonly resources: ReadonlyArray<Name>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ResourceCheckResults<Name extends PropertyKey> = {
|
|
14
|
+
readonly [Key in Name]: ResourceCheckResult;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type CheckResult<
|
|
18
|
+
Resources extends ReadonlyArray<ResourceDefinition>,
|
|
19
|
+
Name extends ResourceName<Resources> = ResourceName<Resources>,
|
|
20
|
+
> = ResourceCheckResults<Name>;
|
|
21
|
+
|
|
22
|
+
type CheckFailure = { readonly message: string };
|
|
23
|
+
|
|
24
|
+
const ok: ResourceCheckResult = { _tag: "ok" };
|
|
25
|
+
|
|
26
|
+
const error = (message: string): ResourceCheckResult => ({ _tag: "error", message });
|
|
27
|
+
|
|
28
|
+
const fromEntries = <Name extends string>(
|
|
29
|
+
entries: ReadonlyArray<readonly [Name, ResourceCheckResult]>,
|
|
30
|
+
): ResourceCheckResults<Name> => Object.fromEntries(entries) as ResourceCheckResults<Name>;
|
|
31
|
+
|
|
32
|
+
const resultsFor = <Name extends string>(names: ReadonlyArray<Name>, result: ResourceCheckResult) =>
|
|
33
|
+
fromEntries(names.map((name) => Tuple.make(name, result)));
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Builds the connector service from its layer and validates only the selected
|
|
37
|
+
* resources. The layer remains open until every check finishes.
|
|
38
|
+
*/
|
|
39
|
+
export function check<
|
|
40
|
+
Identifier,
|
|
41
|
+
const Resources extends ReadonlyArray<ResourceDefinition>,
|
|
42
|
+
E extends CheckFailure,
|
|
43
|
+
R,
|
|
44
|
+
const Name extends ResourceName<Resources>,
|
|
45
|
+
>(
|
|
46
|
+
service: Context.Key<Identifier, ConnectorDefinition<Resources>>,
|
|
47
|
+
layer: Layer.Layer<Identifier, E, R>,
|
|
48
|
+
options: CheckOptions<Name>,
|
|
49
|
+
): Effect.Effect<CheckResult<Resources, Name>, never, R> {
|
|
50
|
+
if (options.resources.length === 0) {
|
|
51
|
+
return Effect.succeed(fromEntries<Name>([]));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return service.pipe(
|
|
55
|
+
Effect.flatMap((connector) =>
|
|
56
|
+
Effect.forEach(options.resources, (name) => {
|
|
57
|
+
const resource = connector.resources.find((candidate) => candidate.name === name);
|
|
58
|
+
const result = resource
|
|
59
|
+
? resource.check.pipe(
|
|
60
|
+
Effect.match({
|
|
61
|
+
onFailure: (failure) => error(failure.message),
|
|
62
|
+
onSuccess: () => ok,
|
|
63
|
+
}),
|
|
64
|
+
)
|
|
65
|
+
: Effect.succeed(error(`Unknown connector resource: ${name}`));
|
|
66
|
+
|
|
67
|
+
return result.pipe(Effect.map((result) => Tuple.make(name, result)));
|
|
68
|
+
}).pipe(Effect.map(fromEntries)),
|
|
69
|
+
),
|
|
70
|
+
Effect.provide(layer),
|
|
71
|
+
Effect.match({
|
|
72
|
+
onFailure: (failure) => resultsFor(options.resources, error(failure.message)),
|
|
73
|
+
onSuccess: (results) => results,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NodeHttpServer } from "@effect/platform-node";
|
|
2
|
+
import { DateTime, Effect } from "effect";
|
|
3
|
+
import { HttpRouter } from "effect/unstable/http";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
|
|
6
|
+
import type { ConnectorDefinition } from "../core";
|
|
7
|
+
import type { Cursor } from "../core/types";
|
|
8
|
+
|
|
9
|
+
import { run as runIngestion } from "../ingestion";
|
|
10
|
+
|
|
11
|
+
export type App = ConnectorDefinition;
|
|
12
|
+
|
|
13
|
+
export type StartOptions = {
|
|
14
|
+
readonly port: number;
|
|
15
|
+
readonly initialCutoff?: Cursor.Value;
|
|
16
|
+
readonly healthPath?: HttpRouter.PathInput;
|
|
17
|
+
readonly metricsPath?: HttpRouter.PathInput | false;
|
|
18
|
+
readonly statusPath?: HttpRouter.PathInput | false;
|
|
19
|
+
readonly disableHttpLogger?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const start = (app: App, options: StartOptions) =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const initialCutoff =
|
|
25
|
+
options.initialCutoff ?? (yield* DateTime.now.pipe(Effect.map(DateTime.formatIso)));
|
|
26
|
+
const routes = app.webhooks?.map((route) => route.path) ?? [];
|
|
27
|
+
|
|
28
|
+
yield* Effect.logInfo("webhook server ready").pipe(
|
|
29
|
+
Effect.annotateLogs({ port: options.port, routes }),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return yield* runIngestion(app, {
|
|
33
|
+
initialCutoff,
|
|
34
|
+
webhook: {
|
|
35
|
+
routes: app.webhooks ?? [],
|
|
36
|
+
healthPath: options.healthPath ?? "/health",
|
|
37
|
+
metricsPath: options.metricsPath,
|
|
38
|
+
statusPath: options.statusPath,
|
|
39
|
+
disableHttpLogger: options.disableHttpLogger ?? true,
|
|
40
|
+
},
|
|
41
|
+
}).pipe(Effect.provide(NodeHttpServer.layer(createServer, { port: options.port })));
|
|
42
|
+
});
|
package/src/core/builder.ts
CHANGED
|
@@ -1,12 +1,84 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DateTime, Effect } from "effect";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import type {
|
|
4
|
+
ChangesFetch,
|
|
5
|
+
ConnectorDefinition,
|
|
6
|
+
Cursor as CursorType,
|
|
7
|
+
DeleteValue,
|
|
8
|
+
PageFetch,
|
|
9
|
+
ResourceDefinition,
|
|
10
|
+
ResourceMutation,
|
|
11
|
+
ResourceSchema,
|
|
12
|
+
WebhookHandler,
|
|
13
|
+
} from "./types";
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
import { ConnectorError } from "../errors";
|
|
11
16
|
|
|
12
|
-
export const
|
|
17
|
+
export const Connector = {
|
|
18
|
+
define: <const Resources extends ReadonlyArray<ResourceDefinition>>(
|
|
19
|
+
definition: ConnectorDefinition<Resources>,
|
|
20
|
+
) => definition,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Resource = {
|
|
24
|
+
entity: <
|
|
25
|
+
S extends ResourceSchema,
|
|
26
|
+
Payload = never,
|
|
27
|
+
R = never,
|
|
28
|
+
const Name extends string = string,
|
|
29
|
+
>(
|
|
30
|
+
definition: ResourceDefinition<S, Payload, R, Name>,
|
|
31
|
+
): ResourceDefinition<S, Payload, R, Name> => definition,
|
|
32
|
+
|
|
33
|
+
webhook: <Payload, Row extends object = never>(definition: WebhookHandler<Row, Payload>) =>
|
|
34
|
+
definition,
|
|
35
|
+
|
|
36
|
+
upsert: <Row extends object>(row: Row): ResourceMutation<Row> => ({ op: "upsert", row }),
|
|
37
|
+
|
|
38
|
+
delete: (options: {
|
|
39
|
+
readonly key: DeleteValue;
|
|
40
|
+
readonly version: DeleteValue;
|
|
41
|
+
}): ResourceMutation<never> => ({
|
|
42
|
+
op: "delete",
|
|
43
|
+
key: options.key,
|
|
44
|
+
version: options.version,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const Fetch = {
|
|
49
|
+
page: <Row extends object = never, R = never>(definition: PageFetch<Row, R>) => definition,
|
|
50
|
+
changes: <Row extends object = never, R = never>(definition: ChangesFetch<Row, R>) => definition,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const decodeFailure = (kind: string, value: unknown) =>
|
|
54
|
+
new ConnectorError({ message: `Invalid ${kind} cursor value: ${String(value)}` });
|
|
55
|
+
|
|
56
|
+
export const Cursor = {
|
|
57
|
+
string: (): CursorType.Definition<string> => ({
|
|
58
|
+
kind: "string",
|
|
59
|
+
decode: (value) =>
|
|
60
|
+
typeof value === "string"
|
|
61
|
+
? Effect.succeed(value)
|
|
62
|
+
: Effect.fail(decodeFailure("string", value)),
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
number: (): CursorType.Definition<number> => ({
|
|
66
|
+
kind: "number",
|
|
67
|
+
decode: (value) =>
|
|
68
|
+
typeof value === "number" && Number.isFinite(value)
|
|
69
|
+
? Effect.succeed(value)
|
|
70
|
+
: Effect.fail(decodeFailure("number", value)),
|
|
71
|
+
}),
|
|
72
|
+
|
|
73
|
+
isoDateTime: (): CursorType.Definition<string> => ({
|
|
74
|
+
kind: "isoDateTime",
|
|
75
|
+
decode: (value) => {
|
|
76
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
77
|
+
return Effect.fail(decodeFailure("ISO datetime", value));
|
|
78
|
+
}
|
|
79
|
+
return Effect.succeed(value);
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
|
|
83
|
+
nowIsoDateTime: Effect.map(DateTime.now, DateTime.formatIso),
|
|
84
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { Connector, Cursor, Fetch, Resource } from "./builder";
|
|
2
|
+
export type {
|
|
3
|
+
ChangesFetch,
|
|
4
|
+
ConnectorDefinition,
|
|
5
|
+
Cursor as CursorTypes,
|
|
6
|
+
FetchChangesResult,
|
|
7
|
+
FetchPageResult,
|
|
8
|
+
PageFetch,
|
|
9
|
+
ResourceBatch,
|
|
10
|
+
ResourceDefinition,
|
|
11
|
+
ResourceField,
|
|
12
|
+
ResourceMutation,
|
|
13
|
+
ResourcePayload,
|
|
14
|
+
ResourceRow,
|
|
15
|
+
ResourceRows,
|
|
16
|
+
ResourceSchema,
|
|
17
|
+
ResourceState,
|
|
18
|
+
WebhookAckMode,
|
|
19
|
+
WebhookHandler,
|
|
20
|
+
WebhookRoute,
|
|
21
|
+
WebhookRouteContext,
|
|
22
|
+
} from "./types";
|