@useairfoil/connector-kit 0.5.3 → 0.6.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 +20 -19
- package/README.md +127 -430
- package/dist/annotations-BE74YmAO.d.mts +39 -0
- package/dist/auth/index.d.mts +2 -0
- package/dist/{auth-DvU_CZ7C.js → auth/index.mjs} +6 -8
- package/dist/auth/index.mjs.map +1 -0
- package/dist/connector-app/index.d.mts +2 -0
- package/dist/connector-app/index.mjs +2 -0
- package/dist/connector-app-C-L4QqG6.mjs +123 -0
- package/dist/connector-app-C-L4QqG6.mjs.map +1 -0
- package/dist/{constants-BRhIX_rz.js → constants-D-GQzpHZ.mjs} +10 -6
- package/dist/constants-D-GQzpHZ.mjs.map +1 -0
- package/dist/demo/index.d.mts +2 -0
- package/dist/demo/index.mjs +2 -0
- package/dist/demo-B30Vlkk2.mjs +191 -0
- package/dist/demo-B30Vlkk2.mjs.map +1 -0
- package/dist/errors/index.d.mts +2 -0
- package/dist/errors/index.mjs +2 -0
- package/dist/{errors-DHWylqRZ.js → errors-pT0YVJU5.mjs} +2 -3
- package/dist/errors-pT0YVJU5.mjs.map +1 -0
- package/dist/iceberg/index.d.mts +3 -0
- package/dist/iceberg/index.mjs +3 -0
- package/dist/iceberg-D6L8I6vA.mjs +39 -0
- package/dist/iceberg-D6L8I6vA.mjs.map +1 -0
- package/dist/{index-Cq2IzY7T.d.ts → index-BUHSGm9Q.d.mts} +11 -13
- package/dist/{index-CTHVudvQ.d.ts → index-BX8G7d41.d.mts} +1 -2
- package/dist/{index-J42AZaXU.d.ts → index-BfXpgxk9.d.mts} +9 -10
- package/dist/{index-DKWIh6M1.d.ts → index-CRVAwJ5-.d.mts} +10 -8
- package/dist/index-CUPP2A_m.d.mts +27 -0
- package/dist/{index-Coh_SkBs.d.ts → index-CgvFomO6.d.mts} +6 -7
- package/dist/index-DJhDp4Xc.d.mts +58 -0
- package/dist/index-Dk7urvpF.d.mts +76 -0
- package/dist/{index-D54ySAKn.d.ts → index-DkVNO6ks.d.mts} +2 -5
- package/dist/{index-DtJX_tic.d.ts → index-NnCutIqM.d.mts} +77 -38
- package/dist/{index-CBT-JX-T.d.ts → index-eFuoMZZ3.d.mts} +18 -20
- package/dist/index-ygpml2kC.d.mts +73 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +45 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ingestion/index.d.mts +2 -0
- package/dist/ingestion/index.mjs +2 -0
- package/dist/ingestion-q0WwqUSt.mjs +275 -0
- package/dist/ingestion-q0WwqUSt.mjs.map +1 -0
- package/dist/ingestor/index.d.mts +3 -0
- package/dist/ingestor/index.mjs +4 -0
- package/dist/ingestor-D4L-HPkg.mjs +26 -0
- package/dist/ingestor-D4L-HPkg.mjs.map +1 -0
- package/dist/instrumented-Bhp7fyvh.mjs +29 -0
- package/dist/instrumented-Bhp7fyvh.mjs.map +1 -0
- package/dist/manifest/index.d.mts +2 -0
- package/dist/manifest/{index.js → index.mjs} +2 -4
- package/dist/{manifest-ByE6YPG0.js → manifest-BGKxmKLy.mjs} +14 -19
- package/dist/manifest-BGKxmKLy.mjs.map +1 -0
- package/dist/metrics-BaEX__MN.mjs +352 -0
- package/dist/metrics-BaEX__MN.mjs.map +1 -0
- package/dist/metrics-CVXFL7YT.d.mts +64 -0
- package/dist/metrics.d.mts +2 -0
- package/dist/metrics.mjs +2 -0
- package/dist/{chunk-Bp6m_JJh.js → rolldown-runtime-D7D4PA-g.mjs} +4 -4
- package/dist/runtime-config/index.d.mts +2 -0
- package/dist/runtime-config/index.mjs +3 -0
- package/dist/runtime-config-Oa55gAew.mjs +97 -0
- package/dist/runtime-config-Oa55gAew.mjs.map +1 -0
- package/dist/{server-CXTQ7odl.js → server-CMnxz3h0.mjs} +21 -60
- package/dist/server-CMnxz3h0.mjs.map +1 -0
- package/dist/service-DLkhuxYl.d.mts +27 -0
- package/dist/service-jWxxfEht.mjs +7 -0
- package/dist/service-jWxxfEht.mjs.map +1 -0
- package/dist/state-store/index.d.mts +2 -0
- package/dist/state-store/index.mjs +2 -0
- package/dist/{state-store-yl6LiTQ0.js → state-store-uFvHY7Ax.mjs} +15 -22
- package/dist/state-store-uFvHY7Ax.mjs.map +1 -0
- package/dist/status/{index.d.ts → index.d.mts} +1 -4
- package/dist/status/{index.js → index.mjs} +2 -6
- package/dist/{status-B-oZBc33.js → status-CKb9IhQ9.mjs} +14 -16
- package/dist/status-CKb9IhQ9.mjs.map +1 -0
- package/dist/table-V0tgUC5i.mjs +370 -0
- package/dist/table-V0tgUC5i.mjs.map +1 -0
- package/dist/types-xZtSmrGA.d.mts +220 -0
- package/dist/webhook/index.d.mts +3 -0
- package/dist/webhook/index.mjs +12 -0
- package/dist/webhook/index.mjs.map +1 -0
- package/dist/wings-I56hGtNv.mjs +325 -0
- package/dist/wings-I56hGtNv.mjs.map +1 -0
- package/package.json +64 -51
- package/src/catalog/table.ts +201 -0
- package/src/connector-app/create-table.ts +47 -0
- package/src/connector-app/demo.ts +42 -0
- package/src/connector-app/index.ts +2 -0
- package/src/connector-app/start.ts +1 -1
- package/src/core/builder.ts +15 -23
- package/src/core/index.ts +11 -1
- package/src/core/types.ts +114 -39
- package/src/demo/definition.ts +68 -0
- package/src/demo/generate.ts +167 -0
- package/src/demo/index.ts +3 -0
- package/src/demo/run.ts +142 -0
- package/src/iceberg/annotations.ts +62 -0
- package/src/iceberg/error.ts +9 -0
- package/src/iceberg/index.ts +3 -0
- package/src/iceberg/table.ts +511 -0
- package/src/index.ts +3 -1
- package/src/ingestion/engine.ts +240 -60
- package/src/ingestor/arrow.ts +248 -0
- package/src/ingestor/console.ts +13 -0
- package/src/ingestor/index.ts +9 -0
- package/src/ingestor/instrumented.ts +61 -0
- package/src/ingestor/service.ts +30 -0
- package/src/ingestor/wings.ts +143 -0
- package/src/manifest/config.ts +3 -3
- package/src/metrics.ts +125 -33
- package/src/runtime-config/config.ts +14 -0
- package/src/runtime-config/constants.ts +5 -2
- package/src/runtime-config/error.ts +4 -1
- package/src/runtime-config/index.ts +2 -0
- package/src/runtime-config/layer.ts +1 -1
- package/src/runtime-config/table-bindings.ts +92 -0
- package/src/state-store/layer-key-value-store.ts +8 -3
- package/src/state-store/layer-memory.ts +1 -1
- package/src/state-store/layer-sql.ts +4 -4
- package/src/state-store/schema.ts +2 -2
- package/src/state-store/state.ts +14 -2
- package/src/status/route.ts +2 -2
- package/src/telemetry.ts +25 -10
- package/src/webhook/server.ts +39 -40
- package/dist/auth/index.d.ts +0 -2
- package/dist/auth/index.js +0 -3
- package/dist/auth-DvU_CZ7C.js.map +0 -1
- package/dist/connector-app/index.d.ts +0 -14
- package/dist/connector-app/index.js +0 -11
- package/dist/connector-app-d7Z-SZLQ.js +0 -64
- package/dist/connector-app-d7Z-SZLQ.js.map +0 -1
- package/dist/constants-BRhIX_rz.js.map +0 -1
- package/dist/errors/index.d.ts +0 -2
- package/dist/errors/index.js +0 -3
- package/dist/errors-DHWylqRZ.js.map +0 -1
- package/dist/index-Byr0Lf0C.d.ts +0 -25
- package/dist/index-o1-Z3n7V.d.ts +0 -55
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -58
- package/dist/index.js.map +0 -1
- package/dist/ingestion/index.d.ts +0 -6
- package/dist/ingestion/index.js +0 -10
- package/dist/ingestion-BQo4cbGw.js +0 -200
- package/dist/ingestion-BQo4cbGw.js.map +0 -1
- package/dist/manifest/index.d.ts +0 -2
- package/dist/manifest-ByE6YPG0.js.map +0 -1
- package/dist/metrics-CVAk1ALR.d.ts +0 -53
- package/dist/metrics-CWPy2Aqc.js +0 -96
- package/dist/metrics-CWPy2Aqc.js.map +0 -1
- package/dist/metrics.d.ts +0 -4
- package/dist/metrics.js +0 -3
- package/dist/publisher/index.d.ts +0 -5
- package/dist/publisher/index.js +0 -6
- package/dist/publisher-BYT3RLVO.js +0 -131
- package/dist/publisher-BYT3RLVO.js.map +0 -1
- package/dist/runtime-config/index.d.ts +0 -2
- package/dist/runtime-config/index.js +0 -4
- package/dist/runtime-config-BpB-d_bF.js +0 -51
- package/dist/runtime-config-BpB-d_bF.js.map +0 -1
- package/dist/server-CXTQ7odl.js.map +0 -1
- package/dist/service-DuFiQwid.js +0 -191
- package/dist/service-DuFiQwid.js.map +0 -1
- package/dist/service-IE5qaf9x.d.ts +0 -32
- package/dist/state-store/index.d.ts +0 -3
- package/dist/state-store/index.js +0 -5
- package/dist/state-store-yl6LiTQ0.js.map +0 -1
- package/dist/status-B-oZBc33.js.map +0 -1
- package/dist/types-B35J5YPu.d.ts +0 -174
- package/dist/webhook/index.d.ts +0 -6
- package/dist/webhook/index.js +0 -8
- package/dist/webhook-DI-Afxkg.js +0 -13
- package/dist/webhook-DI-Afxkg.js.map +0 -1
- package/src/publisher/console.ts +0 -18
- package/src/publisher/index.ts +0 -7
- package/src/publisher/instrumented.ts +0 -68
- package/src/publisher/service.ts +0 -37
- package/src/publisher/wings.ts +0 -204
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { Cache, Duration, Effect, Exit, Number
|
|
3
|
-
|
|
1
|
+
import { t as __exportAll } from "../rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Cache, Duration, Effect, Exit, Number } from "effect";
|
|
4
3
|
//#region src/auth/token-cache.ts
|
|
5
4
|
/**
|
|
6
5
|
* Creates a lazy, in-memory token cache around an acquisition effect.
|
|
@@ -32,11 +31,10 @@ const makeTokenCache = (options) => Effect.gen(function* () {
|
|
|
32
31
|
invalidate: Cache.invalidate(cache, void 0)
|
|
33
32
|
};
|
|
34
33
|
});
|
|
35
|
-
|
|
36
34
|
//#endregion
|
|
37
35
|
//#region src/auth/index.ts
|
|
38
|
-
var auth_exports = /* @__PURE__ */
|
|
39
|
-
|
|
36
|
+
var auth_exports = /* @__PURE__ */ __exportAll({ makeTokenCache: () => makeTokenCache });
|
|
40
37
|
//#endregion
|
|
41
|
-
export { makeTokenCache
|
|
42
|
-
|
|
38
|
+
export { makeTokenCache, auth_exports as t };
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/auth/token-cache.ts","../../src/auth/index.ts"],"sourcesContent":["import { Cache, Duration, Effect, Exit, Number, Redacted } from \"effect\";\n\nexport interface ExpiringToken {\n /** The credential kept in memory by the cache. */\n readonly value: Redacted.Redacted<string>;\n /** The lifetime reported by the provider. */\n readonly expiresIn: Duration.Duration;\n}\n\nexport interface TokenCache<E> {\n /** Returns the cached token or performs one shared acquisition. */\n readonly get: Effect.Effect<Redacted.Redacted<string>, E>;\n /** Removes the cached token so the next `get` reacquires it. */\n readonly invalidate: Effect.Effect<void>;\n}\n\n/**\n * Creates a lazy, in-memory token cache around an acquisition effect.\n *\n * `refreshFactor` controls how much of the provider lifetime is cached. It is\n * clamped between `0` and `1`.\n *\n * @example\n * ```ts\n * const cache = yield* makeTokenCache({\n * acquire: exchangeCredentials,\n * refreshFactor: 0.5,\n * })\n *\n * const token = yield* cache.get\n * ```\n */\nexport const makeTokenCache = <E, R>(options: {\n readonly acquire: Effect.Effect<ExpiringToken, E, R>;\n readonly refreshFactor?: number;\n}): Effect.Effect<TokenCache<E>, never, R> =>\n Effect.gen(function* () {\n const refreshFactor = Number.clamp(options.refreshFactor ?? 0.5, {\n minimum: 0,\n maximum: 1,\n });\n const cache = yield* Cache.makeWith((_: void) => options.acquire, {\n capacity: 1,\n timeToLive: (exit) =>\n Exit.isSuccess(exit)\n ? Duration.millis(Duration.toMillis(exit.value.expiresIn) * refreshFactor)\n : Duration.zero,\n });\n\n return {\n get: Cache.get(cache, undefined).pipe(Effect.map((token) => token.value)),\n invalidate: Cache.invalidate(cache, undefined),\n };\n });\n","export * from \"./token-cache\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBAAwB,YAInC,OAAO,IAAI,aAAa;CACtB,MAAM,gBAAgB,OAAO,MAAM,QAAQ,iBAAiB,IAAK;EAC/D,SAAS;EACT,SAAS;CACX,CAAC;CACD,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAY,QAAQ,SAAS;EAChE,UAAU;EACV,aAAa,SACX,KAAK,UAAU,IAAI,IACf,SAAS,OAAO,SAAS,SAAS,KAAK,MAAM,SAAS,IAAI,aAAa,IACvE,SAAS;CACjB,CAAC;CAED,OAAO;EACL,KAAK,MAAM,IAAI,OAAO,KAAA,CAAS,CAAC,CAAC,KAAK,OAAO,KAAK,UAAU,MAAM,KAAK,CAAC;EACxE,YAAY,MAAM,WAAW,OAAO,KAAA,CAAS;CAC/C;AACF,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as makeDemoCommand, g as check, h as ResourceCheckResult, i as start, m as CheckResult, n as App, o as parseSize, p as CheckOptions, r as StartOptions, s as makeCreateTableCommand } from "../index-NnCutIqM.mjs";
|
|
2
|
+
export { type App, type CheckOptions, type CheckResult, type ResourceCheckResult, type StartOptions, check, makeCreateTableCommand, makeDemoCommand, parseSize, start };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { n as layerWingsConfig, r as createTableFromWings } from "./wings-I56hGtNv.mjs";
|
|
3
|
+
import { s as wingsUri } from "./runtime-config-Oa55gAew.mjs";
|
|
4
|
+
import { n as run } from "./demo-B30Vlkk2.mjs";
|
|
5
|
+
import { n as run$1 } from "./ingestion-q0WwqUSt.mjs";
|
|
6
|
+
import { ByteSize, DateTime, Effect, Option, Tuple } from "effect";
|
|
7
|
+
import { Argument, CliError, Command, Flag } from "effect/cli";
|
|
8
|
+
import "effect/http";
|
|
9
|
+
import { NodeHttpServer } from "@effect/platform-node";
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
//#region src/connector-app/check.ts
|
|
12
|
+
const ok = { _tag: "ok" };
|
|
13
|
+
const error = (message) => ({
|
|
14
|
+
_tag: "error",
|
|
15
|
+
message
|
|
16
|
+
});
|
|
17
|
+
const fromEntries = (entries) => Object.fromEntries(entries);
|
|
18
|
+
const resultsFor = (names, result) => fromEntries(names.map((name) => Tuple.make(name, result)));
|
|
19
|
+
/**
|
|
20
|
+
* Builds the connector service from its layer and validates only the selected
|
|
21
|
+
* resources. The layer remains open until every check finishes.
|
|
22
|
+
*/
|
|
23
|
+
function check(service, layer, options) {
|
|
24
|
+
if (options.resources.length === 0) return Effect.succeed(fromEntries([]));
|
|
25
|
+
return service.pipe(Effect.flatMap((connector) => Effect.forEach(options.resources, (name) => {
|
|
26
|
+
const resource = connector.resources.find((candidate) => candidate.name === name);
|
|
27
|
+
return (resource ? resource.check.pipe(Effect.match({
|
|
28
|
+
onFailure: (failure) => error(failure.message),
|
|
29
|
+
onSuccess: () => ok
|
|
30
|
+
})) : Effect.succeed(error(`Unknown connector resource: ${name}`))).pipe(Effect.map((result) => Tuple.make(name, result)));
|
|
31
|
+
}).pipe(Effect.map(fromEntries))), Effect.provide(layer), Effect.match({
|
|
32
|
+
onFailure: (failure) => resultsFor(options.resources, error(failure.message)),
|
|
33
|
+
onSuccess: (results) => results
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/connector-app/create-table.ts
|
|
38
|
+
/** Creates the table command for a connector's row schemas. */
|
|
39
|
+
const makeCreateTableCommand = (schemas) => Command.make("create-table", {
|
|
40
|
+
table: Argument.String("table"),
|
|
41
|
+
catalog: Flag.String("catalog"),
|
|
42
|
+
location: Flag.String("location").pipe(Flag.optional),
|
|
43
|
+
resource: Flag.String("resource").pipe(Flag.optional)
|
|
44
|
+
}, ({ table, catalog, location, resource }) => Effect.gen(function* () {
|
|
45
|
+
const namespace = table.split(".");
|
|
46
|
+
const name = namespace.pop();
|
|
47
|
+
if (!name || namespace.length === 0 || namespace.some((part) => part.length === 0)) return yield* new CliError.UserError({
|
|
48
|
+
cause: "Invalid table name",
|
|
49
|
+
userMessage: "Use a table name like my.namespace.table"
|
|
50
|
+
});
|
|
51
|
+
const resourceName = Option.getOrElse(resource, () => name);
|
|
52
|
+
const schema = Object.hasOwn(schemas, resourceName) ? schemas[resourceName] : void 0;
|
|
53
|
+
if (!schema) return yield* new CliError.UserError({
|
|
54
|
+
cause: "Unknown resource",
|
|
55
|
+
userMessage: `Unknown resource: ${resourceName}`
|
|
56
|
+
});
|
|
57
|
+
const uri = yield* wingsUri;
|
|
58
|
+
yield* createTableFromWings(schema, {
|
|
59
|
+
wingsUri: uri.href,
|
|
60
|
+
catalogId: catalog,
|
|
61
|
+
identifier: {
|
|
62
|
+
namespace,
|
|
63
|
+
name
|
|
64
|
+
},
|
|
65
|
+
location: Option.getOrUndefined(location)
|
|
66
|
+
});
|
|
67
|
+
yield* Effect.log(`Created ${table}`);
|
|
68
|
+
})).pipe(Command.withDescription("Create an Iceberg table for a connector resource"));
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/connector-app/demo.ts
|
|
71
|
+
/** Reads sizes such as `512KiB`, `128MiB` or `1GiB`. */
|
|
72
|
+
const parseSize = (input) => {
|
|
73
|
+
if (!/^\d+(KiB|MiB|GiB)$/.test(input)) return Option.none();
|
|
74
|
+
return ByteSize.fromString(input).pipe(Option.flatMap(ByteSize.toNumber), Option.filter((bytes) => bytes > 0));
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Creates the command that writes the demo data to Wings, then exits.
|
|
78
|
+
* It reads Wings and table bindings from Config, so provide `RuntimeConfig.layerHosted()`.
|
|
79
|
+
*/
|
|
80
|
+
const makeDemoCommand = (demo) => Command.make("demo", {
|
|
81
|
+
size: Flag.String("size").pipe(Flag.filterMap(parseSize, () => "a size like 512KiB, 128MiB or 1GiB")),
|
|
82
|
+
seed: Flag.Int("seed").pipe(Flag.withDefault(1))
|
|
83
|
+
}, ({ size, seed }) => Effect.gen(function* () {
|
|
84
|
+
const now = yield* DateTime.nowAsDate;
|
|
85
|
+
yield* run(demo, {
|
|
86
|
+
bytes: size,
|
|
87
|
+
seed,
|
|
88
|
+
now
|
|
89
|
+
}).pipe(Effect.provide(layerWingsConfig({ resources: [...demo.setup.tables, ...demo.group.tables] })));
|
|
90
|
+
})).pipe(Command.withDescription("Write demo data for the bound tables, then exit"));
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/connector-app/start.ts
|
|
93
|
+
const start = (app, options) => Effect.gen(function* () {
|
|
94
|
+
const initialCutoff = options.initialCutoff ?? (yield* DateTime.now.pipe(Effect.map(DateTime.formatIso)));
|
|
95
|
+
const routes = app.webhooks?.map((route) => route.path) ?? [];
|
|
96
|
+
yield* Effect.logInfo("webhook server ready").pipe(Effect.annotateLogs({
|
|
97
|
+
port: options.port,
|
|
98
|
+
routes
|
|
99
|
+
}));
|
|
100
|
+
return yield* run$1(app, {
|
|
101
|
+
initialCutoff,
|
|
102
|
+
webhook: {
|
|
103
|
+
routes: app.webhooks ?? [],
|
|
104
|
+
healthPath: options.healthPath ?? "/health",
|
|
105
|
+
metricsPath: options.metricsPath,
|
|
106
|
+
statusPath: options.statusPath,
|
|
107
|
+
disableHttpLogger: options.disableHttpLogger ?? true
|
|
108
|
+
}
|
|
109
|
+
}).pipe(Effect.provide(NodeHttpServer.layer(createServer, { port: options.port })));
|
|
110
|
+
});
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/connector-app/index.ts
|
|
113
|
+
var connector_app_exports = /* @__PURE__ */ __exportAll({
|
|
114
|
+
check: () => check,
|
|
115
|
+
makeCreateTableCommand: () => makeCreateTableCommand,
|
|
116
|
+
makeDemoCommand: () => makeDemoCommand,
|
|
117
|
+
parseSize: () => parseSize,
|
|
118
|
+
start: () => start
|
|
119
|
+
});
|
|
120
|
+
//#endregion
|
|
121
|
+
export { makeCreateTableCommand as a, parseSize as i, start as n, check as o, makeDemoCommand as r, connector_app_exports as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=connector-app-C-L4QqG6.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-app-C-L4QqG6.mjs","names":["runIngestion"],"sources":["../src/connector-app/check.ts","../src/connector-app/create-table.ts","../src/connector-app/demo.ts","../src/connector-app/start.ts","../src/connector-app/index.ts"],"sourcesContent":["import { Context, Effect, Layer, Tuple } from \"effect\";\n\nimport type { ConnectorDefinition, ResourceDefinition, ResourceName } from \"../core/types\";\n\nexport type ResourceCheckResult =\n | { readonly _tag: \"ok\" }\n | { readonly _tag: \"error\"; readonly message: string };\n\nexport type CheckOptions<Name extends string> = {\n readonly resources: ReadonlyArray<Name>;\n};\n\ntype ResourceCheckResults<Name extends PropertyKey> = {\n readonly [Key in Name]: ResourceCheckResult;\n};\n\nexport type CheckResult<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Name extends ResourceName<Resources> = ResourceName<Resources>,\n> = ResourceCheckResults<Name>;\n\ntype CheckFailure = { readonly message: string };\n\nconst ok: ResourceCheckResult = { _tag: \"ok\" };\n\nconst error = (message: string): ResourceCheckResult => ({ _tag: \"error\", message });\n\nconst fromEntries = <Name extends string>(\n entries: ReadonlyArray<readonly [Name, ResourceCheckResult]>,\n): ResourceCheckResults<Name> => Object.fromEntries(entries) as ResourceCheckResults<Name>;\n\nconst resultsFor = <Name extends string>(names: ReadonlyArray<Name>, result: ResourceCheckResult) =>\n fromEntries(names.map((name) => Tuple.make(name, result)));\n\n/**\n * Builds the connector service from its layer and validates only the selected\n * resources. The layer remains open until every check finishes.\n */\nexport function check<\n Identifier,\n const Resources extends ReadonlyArray<ResourceDefinition>,\n E extends CheckFailure,\n R,\n const Name extends ResourceName<Resources>,\n>(\n service: Context.Key<Identifier, ConnectorDefinition<Resources>>,\n layer: Layer.Layer<Identifier, E, R>,\n options: CheckOptions<Name>,\n): Effect.Effect<CheckResult<Resources, Name>, never, R> {\n if (options.resources.length === 0) {\n return Effect.succeed(fromEntries<Name>([]));\n }\n\n return service.pipe(\n Effect.flatMap((connector) =>\n Effect.forEach(options.resources, (name) => {\n const resource = connector.resources.find((candidate) => candidate.name === name);\n const result = resource\n ? resource.check.pipe(\n Effect.match({\n onFailure: (failure) => error(failure.message),\n onSuccess: () => ok,\n }),\n )\n : Effect.succeed(error(`Unknown connector resource: ${name}`));\n\n return result.pipe(Effect.map((result) => Tuple.make(name, result)));\n }).pipe(Effect.map(fromEntries)),\n ),\n Effect.provide(layer),\n Effect.match({\n onFailure: (failure) => resultsFor(options.resources, error(failure.message)),\n onSuccess: (results) => results,\n }),\n );\n}\n","import { Effect, Option, type Schema } from \"effect\";\nimport { Argument, CliError, Command, Flag } from \"effect/cli\";\n\nimport { createTableFromWings } from \"../catalog/table\";\nimport { wingsUri } from \"../runtime-config/config\";\n\n/** Creates the table command for a connector's row schemas. */\nexport const makeCreateTableCommand = (schemas: Readonly<Record<string, Schema.Top>>) =>\n Command.make(\n \"create-table\",\n {\n table: Argument.String(\"table\"),\n catalog: Flag.String(\"catalog\"),\n location: Flag.String(\"location\").pipe(Flag.optional),\n resource: Flag.String(\"resource\").pipe(Flag.optional),\n },\n ({ table, catalog, location, resource }) =>\n Effect.gen(function* () {\n const namespace = table.split(\".\");\n const name = namespace.pop();\n\n if (!name || namespace.length === 0 || namespace.some((part) => part.length === 0)) {\n return yield* new CliError.UserError({\n cause: \"Invalid table name\",\n userMessage: \"Use a table name like my.namespace.table\",\n });\n }\n\n const resourceName = Option.getOrElse(resource, () => name);\n const schema = Object.hasOwn(schemas, resourceName) ? schemas[resourceName] : undefined;\n if (!schema) {\n return yield* new CliError.UserError({\n cause: \"Unknown resource\",\n userMessage: `Unknown resource: ${resourceName}`,\n });\n }\n\n const uri = yield* wingsUri;\n yield* createTableFromWings(schema, {\n wingsUri: uri.href,\n catalogId: catalog,\n identifier: { namespace, name },\n location: Option.getOrUndefined(location),\n });\n yield* Effect.log(`Created ${table}`);\n }),\n ).pipe(Command.withDescription(\"Create an Iceberg table for a connector resource\"));\n","import { ByteSize, DateTime, Effect, Option } from \"effect\";\nimport { Command, Flag } from \"effect/cli\";\n\nimport { run, type DemoDefinition } from \"../demo\";\nimport { layerWingsConfig } from \"../ingestor/wings\";\n\n/** Reads sizes such as `512KiB`, `128MiB` or `1GiB`. */\nexport const parseSize = (input: string): Option.Option<number> => {\n if (!/^\\d+(KiB|MiB|GiB)$/.test(input)) return Option.none();\n\n return ByteSize.fromString(input).pipe(\n Option.flatMap(ByteSize.toNumber),\n Option.filter((bytes) => bytes > 0),\n );\n};\n\n/**\n * Creates the command that writes the demo data to Wings, then exits.\n * It reads Wings and table bindings from Config, so provide `RuntimeConfig.layerHosted()`.\n */\nexport const makeDemoCommand = (demo: DemoDefinition) =>\n Command.make(\n \"demo\",\n {\n size: Flag.String(\"size\").pipe(\n Flag.filterMap(parseSize, () => \"a size like 512KiB, 128MiB or 1GiB\"),\n ),\n seed: Flag.Int(\"seed\").pipe(Flag.withDefault(1)),\n },\n ({ size, seed }) =>\n Effect.gen(function* () {\n const now = yield* DateTime.nowAsDate;\n\n yield* run(demo, { bytes: size, seed, now }).pipe(\n Effect.provide(\n layerWingsConfig({\n resources: [...demo.setup.tables, ...demo.group.tables],\n }),\n ),\n );\n }),\n ).pipe(Command.withDescription(\"Write demo data for the bound tables, then exit\"));\n","import { NodeHttpServer } from \"@effect/platform-node\";\nimport { DateTime, Effect } from \"effect\";\nimport { HttpRouter } from \"effect/http\";\nimport { createServer } from \"node:http\";\n\nimport type { ConnectorDefinition } from \"../core\";\nimport type { Cursor } from \"../core/types\";\n\nimport { run as runIngestion } from \"../ingestion\";\n\nexport type App = ConnectorDefinition;\n\nexport type StartOptions = {\n readonly port: number;\n readonly initialCutoff?: Cursor.Value;\n readonly healthPath?: HttpRouter.PathInput;\n readonly metricsPath?: HttpRouter.PathInput | false;\n readonly statusPath?: HttpRouter.PathInput | false;\n readonly disableHttpLogger?: boolean;\n};\n\nexport const start = (app: App, options: StartOptions) =>\n Effect.gen(function* () {\n const initialCutoff =\n options.initialCutoff ?? (yield* DateTime.now.pipe(Effect.map(DateTime.formatIso)));\n const routes = app.webhooks?.map((route) => route.path) ?? [];\n\n yield* Effect.logInfo(\"webhook server ready\").pipe(\n Effect.annotateLogs({ port: options.port, routes }),\n );\n\n return yield* runIngestion(app, {\n initialCutoff,\n webhook: {\n routes: app.webhooks ?? [],\n healthPath: options.healthPath ?? \"/health\",\n metricsPath: options.metricsPath,\n statusPath: options.statusPath,\n disableHttpLogger: options.disableHttpLogger ?? true,\n },\n }).pipe(Effect.provide(NodeHttpServer.layer(createServer, { port: options.port })));\n });\n","export { check, type CheckOptions, type CheckResult, type ResourceCheckResult } from \"./check\";\nexport { makeCreateTableCommand } from \"./create-table\";\nexport { makeDemoCommand, parseSize } from \"./demo\";\nexport { start, type App, type StartOptions } from \"./start\";\n"],"mappings":"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"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { HashSet } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/runtime-config/constants.ts
|
|
4
3
|
/** Shared runtime keys owned by Airfoil rather than an individual connector. */
|
|
5
4
|
const PlatformRuntimeKey = {
|
|
6
5
|
configPath: "AIRFOIL_CONFIG_PATH",
|
|
6
|
+
httpPort: "AIRFOIL_HTTP_PORT",
|
|
7
|
+
tableBindings: "AIRFOIL_TABLE_BINDINGS",
|
|
7
8
|
connectorInstanceId: "AIRFOIL_CONNECTOR_INSTANCE_ID",
|
|
8
9
|
stateTable: "AIRFOIL_STATE_TABLE",
|
|
9
10
|
postgresConnectionString: "POSTGRES_CONNECTION_STRING",
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
wingsUri: "WINGS_URI",
|
|
12
|
+
catalog: "AIRFOIL_CATALOG",
|
|
12
13
|
otelEnabled: "OTEL_ENABLED",
|
|
13
14
|
otelExporterOtlpEndpoint: "OTEL_EXPORTER_OTLP_ENDPOINT",
|
|
14
15
|
otelExporterOtlpHeaders: "OTEL_EXPORTER_OTLP_HEADERS",
|
|
@@ -17,11 +18,14 @@ const PlatformRuntimeKey = {
|
|
|
17
18
|
otelResourceAttributes: "OTEL_RESOURCE_ATTRIBUTES"
|
|
18
19
|
};
|
|
19
20
|
/** Defaults for optional platform-owned runtime configuration. */
|
|
20
|
-
const PlatformRuntimeDefault = {
|
|
21
|
+
const PlatformRuntimeDefault = {
|
|
22
|
+
httpPort: 8080,
|
|
23
|
+
stateTable: "_airfoil_connectors_state"
|
|
24
|
+
};
|
|
21
25
|
const platformRuntimeKeys = HashSet.fromIterable(Object.values(PlatformRuntimeKey));
|
|
22
26
|
/** @internal */
|
|
23
27
|
const isPlatformRuntimeKey = (key) => HashSet.has(platformRuntimeKeys, key);
|
|
24
|
-
|
|
25
28
|
//#endregion
|
|
26
29
|
export { PlatformRuntimeKey as n, isPlatformRuntimeKey as r, PlatformRuntimeDefault as t };
|
|
27
|
-
|
|
30
|
+
|
|
31
|
+
//# sourceMappingURL=constants-D-GQzpHZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants-D-GQzpHZ.mjs","names":[],"sources":["../src/runtime-config/constants.ts"],"sourcesContent":["import { HashSet } from \"effect\";\n\n/** Shared runtime keys owned by Airfoil rather than an individual connector. */\nexport const PlatformRuntimeKey = {\n configPath: \"AIRFOIL_CONFIG_PATH\",\n httpPort: \"AIRFOIL_HTTP_PORT\",\n tableBindings: \"AIRFOIL_TABLE_BINDINGS\",\n connectorInstanceId: \"AIRFOIL_CONNECTOR_INSTANCE_ID\",\n stateTable: \"AIRFOIL_STATE_TABLE\",\n postgresConnectionString: \"POSTGRES_CONNECTION_STRING\",\n wingsUri: \"WINGS_URI\",\n catalog: \"AIRFOIL_CATALOG\",\n otelEnabled: \"OTEL_ENABLED\",\n otelExporterOtlpEndpoint: \"OTEL_EXPORTER_OTLP_ENDPOINT\",\n otelExporterOtlpHeaders: \"OTEL_EXPORTER_OTLP_HEADERS\",\n otelServiceName: \"OTEL_SERVICE_NAME\",\n otelServiceVersion: \"OTEL_SERVICE_VERSION\",\n otelResourceAttributes: \"OTEL_RESOURCE_ATTRIBUTES\",\n} as const;\n\n/** Defaults for optional platform-owned runtime configuration. */\nexport const PlatformRuntimeDefault = {\n httpPort: 8080,\n stateTable: \"_airfoil_connectors_state\",\n} as const;\n\nconst platformRuntimeKeys = HashSet.fromIterable(Object.values(PlatformRuntimeKey));\n\n/** @internal */\nexport const isPlatformRuntimeKey = (key: string): boolean => HashSet.has(platformRuntimeKeys, key);\n"],"mappings":";;;AAGA,MAAa,qBAAqB;CAChC,YAAY;CACZ,UAAU;CACV,eAAe;CACf,qBAAqB;CACrB,YAAY;CACZ,0BAA0B;CAC1B,UAAU;CACV,SAAS;CACT,aAAa;CACb,0BAA0B;CAC1B,yBAAyB;CACzB,iBAAiB;CACjB,oBAAoB;CACpB,wBAAwB;AAC1B;;AAGA,MAAa,yBAAyB;CACpC,UAAU;CACV,YAAY;AACd;AAEA,MAAM,sBAAsB,QAAQ,aAAa,OAAO,OAAO,kBAAkB,CAAC;;AAGlF,MAAa,wBAAwB,QAAyB,QAAQ,IAAI,qBAAqB,GAAG"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as DemoDefinition, c as define, i as run, l as table, n as DemoTotals, o as DemoRows, r as RunOptions, s as DemoTable, u as DemoContext } from "../index-Dk7urvpF.mjs";
|
|
2
|
+
export { type DemoContext, type DemoDefinition, type DemoRows, type DemoTable, type DemoTotals, type RunOptions, define, run, table };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { t as ConnectorError } from "./errors-pT0YVJU5.mjs";
|
|
3
|
+
import { t as checkHasRepresentation } from "./table-V0tgUC5i.mjs";
|
|
4
|
+
import { t as Ingestor } from "./service-jWxxfEht.mjs";
|
|
5
|
+
import { t as ingestBatch } from "./instrumented-Bhp7fyvh.mjs";
|
|
6
|
+
import { Array as Array$1, Duration, Effect, Option, Schema, Stream } from "effect";
|
|
7
|
+
import { Faker, base, en } from "@faker-js/faker";
|
|
8
|
+
//#region src/demo/definition.ts
|
|
9
|
+
const table = (definition) => definition;
|
|
10
|
+
const define = (definition) => definition;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/demo/generate.ts
|
|
13
|
+
const twoYears = Duration.toMillis(Duration.days(730));
|
|
14
|
+
var Unsupported = class extends Error {};
|
|
15
|
+
const unsupported = (path, what) => {
|
|
16
|
+
throw new Unsupported(`${path}: ${what} is not supported in demo data`);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Compiles a row schema into a filler for demo rows. It reads the same
|
|
20
|
+
* representation as `compileTable`, so values fit the Iceberg types. It fills
|
|
21
|
+
* only required fields the row lacks, so optional ones such as `_deleted` stay
|
|
22
|
+
* out.
|
|
23
|
+
*/
|
|
24
|
+
const compileRow = (schema) => Effect.try({
|
|
25
|
+
try: () => {
|
|
26
|
+
const { representation, references } = Schema.toRepresentation(Schema.toType(schema));
|
|
27
|
+
const resolve = (node, path) => {
|
|
28
|
+
if (node._tag !== "Reference") return node;
|
|
29
|
+
const target = references[node.$ref];
|
|
30
|
+
return target === void 0 ? unsupported(path, `reference ${node.$ref}`) : target;
|
|
31
|
+
};
|
|
32
|
+
const requiredFields = (node, path) => {
|
|
33
|
+
const resolved = resolve(node, path);
|
|
34
|
+
if (resolved._tag !== "Objects" || resolved.indexSignatures.length > 0) return unsupported(path, resolved._tag);
|
|
35
|
+
return resolved.propertySignatures.filter((property) => !property.isOptional).map((property) => {
|
|
36
|
+
const name = String(property.name);
|
|
37
|
+
return [name, value(property.type, `${path}.${name}`)];
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const object = (node, path) => {
|
|
41
|
+
const fields = requiredFields(node, path);
|
|
42
|
+
return (context) => Object.fromEntries(fields.map(([name, make]) => [name, make(context)]));
|
|
43
|
+
};
|
|
44
|
+
const value = (node, path) => {
|
|
45
|
+
const resolved = resolve(node, path);
|
|
46
|
+
switch (resolved._tag) {
|
|
47
|
+
case "String": return ({ faker }) => faker.word.words({ count: {
|
|
48
|
+
min: 1,
|
|
49
|
+
max: 3
|
|
50
|
+
} });
|
|
51
|
+
case "Boolean": return ({ faker }) => faker.datatype.boolean();
|
|
52
|
+
case "BigInt": return ({ faker }) => BigInt(faker.number.int({ max: 1e5 }));
|
|
53
|
+
case "Number": return checkHasRepresentation(resolved.checks, "effect/schema/isInt") ? ({ faker }) => faker.number.int({ max: 1e3 }) : ({ faker }) => faker.number.float({
|
|
54
|
+
max: 1e3,
|
|
55
|
+
fractionDigits: 2
|
|
56
|
+
});
|
|
57
|
+
case "Literal": {
|
|
58
|
+
const literal = resolved.literal;
|
|
59
|
+
return () => literal;
|
|
60
|
+
}
|
|
61
|
+
case "Union": {
|
|
62
|
+
const members = resolved.types.filter((member) => member._tag !== "Null" && member._tag !== "Undefined");
|
|
63
|
+
const literals = members.flatMap((member) => member._tag === "Literal" ? [member.literal] : []);
|
|
64
|
+
if (literals.length > 0 && literals.length === members.length) return ({ faker }) => faker.helpers.arrayElement(literals);
|
|
65
|
+
const [only] = members;
|
|
66
|
+
return only !== void 0 && members.length === 1 ? value(only, path) : unsupported(path, "a union of several types");
|
|
67
|
+
}
|
|
68
|
+
case "Objects": return object(resolved, path);
|
|
69
|
+
case "Arrays": {
|
|
70
|
+
const [element] = resolved.rest;
|
|
71
|
+
if (resolved.elements.length > 0 || resolved.rest.length !== 1 || !element) return unsupported(path, "a tuple");
|
|
72
|
+
const item = value(element, `${path}[]`);
|
|
73
|
+
return (context) => Array.from({ length: context.faker.number.int({ max: 3 }) }, () => item(context));
|
|
74
|
+
}
|
|
75
|
+
case "Declaration": return declaration(resolved, path);
|
|
76
|
+
case "Suspend": return value(resolved.thunk, path);
|
|
77
|
+
default: return unsupported(path, resolved._tag);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const declaration = (node, path) => {
|
|
81
|
+
switch (node.representation?.id) {
|
|
82
|
+
case "effect/schema/Date": return ({ faker, now }) => faker.date.between({
|
|
83
|
+
from: now.getTime() - twoYears,
|
|
84
|
+
to: now
|
|
85
|
+
});
|
|
86
|
+
case "effect/schema/Uint8Array": return ({ faker }) => Uint8Array.from({ length: 8 }, () => faker.number.int(255));
|
|
87
|
+
case "effect/schema/ReadonlyMap": {
|
|
88
|
+
const [keyNode, valueNode] = node.typeParameters;
|
|
89
|
+
if (!keyNode || !valueNode) return unsupported(path, "a map without key or value");
|
|
90
|
+
const key = value(keyNode, `${path}.key`);
|
|
91
|
+
const item = value(valueNode, `${path}.value`);
|
|
92
|
+
return (context) => new Map(Array.from({ length: context.faker.number.int({ max: 3 }) }, () => [key(context), item(context)]));
|
|
93
|
+
}
|
|
94
|
+
default: return unsupported(path, node.representation?.id ?? "an unnamed declaration");
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const fields = requiredFields(representation, "$");
|
|
98
|
+
return (context, row) => ({
|
|
99
|
+
...Object.fromEntries(fields.filter(([name]) => !(name in row)).map(([name, make]) => [name, make(context)])),
|
|
100
|
+
...row
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
catch: (cause) => new ConnectorError({
|
|
104
|
+
message: cause instanceof Unsupported ? cause.message : "Failed to compile demo rows",
|
|
105
|
+
cause
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/demo/run.ts
|
|
110
|
+
const empty = {
|
|
111
|
+
rows: 0,
|
|
112
|
+
bytes: 0,
|
|
113
|
+
tables: {}
|
|
114
|
+
};
|
|
115
|
+
const batchRows = 500;
|
|
116
|
+
const sum = (results) => ({
|
|
117
|
+
rows: results.reduce((total, result) => total + result.rows, 0),
|
|
118
|
+
bytes: results.reduce((total, result) => total + result.bytes, 0)
|
|
119
|
+
});
|
|
120
|
+
const add = (totals, written) => written.reduce((current, [name, result]) => ({
|
|
121
|
+
rows: current.rows + result.rows,
|
|
122
|
+
bytes: current.bytes + result.bytes,
|
|
123
|
+
tables: {
|
|
124
|
+
...current.tables,
|
|
125
|
+
[name]: {
|
|
126
|
+
rows: (current.tables[name]?.rows ?? 0) + result.rows,
|
|
127
|
+
bytes: (current.tables[name]?.bytes ?? 0) + result.bytes
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}), totals);
|
|
131
|
+
/**
|
|
132
|
+
* Writes the setup rows, then groups, until it reaches the size or the demo's
|
|
133
|
+
* count. It can go over the size by one chunk. Only bound tables are
|
|
134
|
+
* written; keys still point to the others.
|
|
135
|
+
*/
|
|
136
|
+
const run = Effect.fnUntraced(function* (demo, options) {
|
|
137
|
+
const ingestor = yield* Ingestor;
|
|
138
|
+
const bound = (table) => ingestor.resourceNames === void 0 || ingestor.resourceNames.includes(table.name);
|
|
139
|
+
const faker = new Faker({ locale: [en, base] });
|
|
140
|
+
faker.seed(options.seed);
|
|
141
|
+
const context = {
|
|
142
|
+
faker,
|
|
143
|
+
now: options.now
|
|
144
|
+
};
|
|
145
|
+
const prepare = (tables) => Effect.forEach(tables.filter(bound), (table) => compileRow(table.rowSchema).pipe(Effect.map((fill) => ({
|
|
146
|
+
table,
|
|
147
|
+
fill,
|
|
148
|
+
decode: Schema.decodeUnknownEffect(Schema.toType(table.rowSchema))
|
|
149
|
+
}))));
|
|
150
|
+
const write = (tables, rowsOf) => Effect.forEach(tables, ({ table, fill, decode }) => Effect.forEach(rowsOf(table.name), (row) => decode(fill(context, row)).pipe(Effect.mapError((cause) => new ConnectorError({
|
|
151
|
+
message: `Invalid demo row for ${table.name}`,
|
|
152
|
+
cause
|
|
153
|
+
})))).pipe(Effect.flatMap((rows) => Effect.forEach(Array$1.chunksOf(rows, batchRows), (batch) => ingestBatch({
|
|
154
|
+
connector: demo.name,
|
|
155
|
+
resource: table.name,
|
|
156
|
+
source: "demo",
|
|
157
|
+
batch: { rows: batch }
|
|
158
|
+
}))), Effect.map((results) => [table.name, sum(results)])));
|
|
159
|
+
const setupTables = yield* prepare(demo.setup.tables);
|
|
160
|
+
const groupTables = yield* prepare(demo.group.tables);
|
|
161
|
+
const setup = demo.setup.rows(context);
|
|
162
|
+
const afterSetup = add(empty, yield* write(setupTables, (name) => setup[name] ?? []));
|
|
163
|
+
const totals = afterSetup.bytes >= options.bytes || groupTables.length === 0 ? afterSetup : yield* Stream.range(0, (demo.group.count ?? Infinity) - 1).pipe(Stream.grouped(options.groupsPerChunk ?? demo.group.groupsPerChunk ?? 100), Stream.mapEffect((indexes) => {
|
|
164
|
+
const groups = indexes.map((index) => demo.group.rows(index, context));
|
|
165
|
+
return write(groupTables, (name) => groups.flatMap((group) => group[name] ?? []));
|
|
166
|
+
}), Stream.scan(() => afterSetup, add), Stream.takeUntil((current) => current.bytes >= options.bytes), Stream.tap((current) => Effect.logInfo("demo progress").pipe(Effect.annotateLogs({
|
|
167
|
+
rows: current.rows,
|
|
168
|
+
bytes: current.bytes
|
|
169
|
+
}))), Stream.runLast, Effect.map(Option.getOrElse(() => afterSetup)));
|
|
170
|
+
if (totals.bytes < options.bytes) yield* Effect.logWarning("The selected tables ran out of rows, so the run wrote less than the size asked for").pipe(Effect.annotateLogs({
|
|
171
|
+
bytes: totals.bytes,
|
|
172
|
+
target: options.bytes
|
|
173
|
+
}));
|
|
174
|
+
yield* Effect.logInfo("demo done").pipe(Effect.annotateLogs({
|
|
175
|
+
rows: totals.rows,
|
|
176
|
+
bytes: totals.bytes,
|
|
177
|
+
tables: totals.tables
|
|
178
|
+
}));
|
|
179
|
+
return totals;
|
|
180
|
+
});
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/demo/index.ts
|
|
183
|
+
var demo_exports = /* @__PURE__ */ __exportAll({
|
|
184
|
+
define: () => define,
|
|
185
|
+
run: () => run,
|
|
186
|
+
table: () => table
|
|
187
|
+
});
|
|
188
|
+
//#endregion
|
|
189
|
+
export { table as i, run as n, define as r, demo_exports as t };
|
|
190
|
+
|
|
191
|
+
//# sourceMappingURL=demo-B30Vlkk2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo-B30Vlkk2.mjs","names":["Arr"],"sources":["../src/demo/definition.ts","../src/demo/generate.ts","../src/demo/run.ts","../src/demo/index.ts"],"sourcesContent":["import type { Schema } from \"effect\";\n\nimport type { ResourceRequiredField, ResourceSchema } from \"../core/types\";\nimport type { DemoContext } from \"./generate\";\n\n/** A table a demo writes: the same name, row schema and version as its resource. */\nexport type DemoTable<\n Name extends string = string,\n S extends ResourceSchema = ResourceSchema,\n Version extends string = string,\n> = {\n readonly name: Name;\n readonly rowSchema: S;\n readonly version: Version;\n};\n\nexport const table = <\n const Name extends string,\n S extends ResourceSchema,\n const Version extends ResourceRequiredField<S>,\n>(\n definition: DemoTable<Name, S, Version>,\n): DemoTable<Name, S, Version> => definition;\n\n/** Rows by table. Required fields a row leaves out get placeholder values. */\nexport type DemoRows<Tables extends ReadonlyArray<DemoTable>> = {\n readonly [Table in Tables[number] as Table[\"name\"]]?: ReadonlyArray<\n Partial<Schema.Schema.Type<Table[\"rowSchema\"]>>\n >;\n};\n\nexport type DemoDefinition<\n Setup extends ReadonlyArray<DemoTable> = ReadonlyArray<DemoTable>,\n Group extends ReadonlyArray<DemoTable> = ReadonlyArray<DemoTable>,\n> = {\n readonly name: string;\n /** Tables written once, before any group, such as a product catalog. */\n readonly setup: {\n readonly tables: Setup;\n readonly rows: (context: DemoContext) => DemoRows<Setup>;\n };\n /**\n * Tables for one related unit, such as a customer and their orders. The run\n * adds groups until it reaches the size. Build keys from the index, so they\n * are unique and other groups can point to them.\n */\n readonly group: {\n readonly tables: Group;\n readonly rows: (index: number, context: DemoContext) => DemoRows<Group>;\n /**\n * Groups written per chunk, 100 by default. A run can go over the size by\n * one chunk, so lower it when a group is big.\n */\n readonly groupsPerChunk?: number;\n /**\n * The number of groups there are, when the provider only keeps so much\n * history. The run stops there, even below the size.\n */\n readonly count?: number;\n };\n};\n\nexport const define = <\n const Setup extends ReadonlyArray<DemoTable>,\n const Group extends ReadonlyArray<DemoTable>,\n>(\n definition: DemoDefinition<Setup, Group>,\n): DemoDefinition<Setup, Group> => definition;\n","import type { Faker } from \"@faker-js/faker\";\n\nimport { Duration, Effect, Schema, type SchemaRepresentation } from \"effect\";\n\nimport { ConnectorError } from \"../errors\";\nimport { checkHasRepresentation } from \"../iceberg/table\";\n\n/** What one run shares: the seeded Faker and the time the run started. */\nexport type DemoContext = {\n readonly faker: Faker;\n readonly now: Date;\n};\n\n/** Completes a row: keeps what it has, and fills the required fields it lacks. */\nexport type RowFiller = (context: DemoContext, row: object) => Record<string, unknown>;\n\ntype Representation = SchemaRepresentation.Representation;\ntype Value = (context: DemoContext) => unknown;\n\nconst twoYears = Duration.toMillis(Duration.days(730));\n\nclass Unsupported extends Error {}\n\nconst unsupported = (path: string, what: string): never => {\n throw new Unsupported(`${path}: ${what} is not supported in demo data`);\n};\n\n/**\n * Compiles a row schema into a filler for demo rows. It reads the same\n * representation as `compileTable`, so values fit the Iceberg types. It fills\n * only required fields the row lacks, so optional ones such as `_deleted` stay\n * out.\n */\nexport const compileRow = (schema: Schema.Top): Effect.Effect<RowFiller, ConnectorError> =>\n Effect.try({\n try: () => {\n const { representation, references } = Schema.toRepresentation(Schema.toType(schema));\n\n const resolve = (node: Representation, path: string): Representation => {\n if (node._tag !== \"Reference\") return node;\n const target = references[node.$ref];\n\n return target === undefined ? unsupported(path, `reference ${node.$ref}`) : target;\n };\n\n const requiredFields = (node: Representation, path: string) => {\n const resolved = resolve(node, path);\n\n if (resolved._tag !== \"Objects\" || resolved.indexSignatures.length > 0) {\n return unsupported(path, resolved._tag);\n }\n\n return resolved.propertySignatures\n .filter((property) => !property.isOptional)\n .map((property) => {\n const name = String(property.name);\n return [name, value(property.type, `${path}.${name}`)] as const;\n });\n };\n\n const object = (node: Representation, path: string): Value => {\n const fields = requiredFields(node, path);\n return (context) => Object.fromEntries(fields.map(([name, make]) => [name, make(context)]));\n };\n\n const value = (node: Representation, path: string): Value => {\n const resolved = resolve(node, path);\n\n switch (resolved._tag) {\n case \"String\":\n return ({ faker }) => faker.word.words({ count: { min: 1, max: 3 } });\n case \"Boolean\":\n return ({ faker }) => faker.datatype.boolean();\n case \"BigInt\":\n return ({ faker }) => BigInt(faker.number.int({ max: 100_000 }));\n case \"Number\":\n return checkHasRepresentation(resolved.checks, \"effect/schema/isInt\")\n ? ({ faker }) => faker.number.int({ max: 1000 })\n : ({ faker }) => faker.number.float({ max: 1000, fractionDigits: 2 });\n case \"Literal\": {\n const literal = resolved.literal;\n return () => literal;\n }\n case \"Union\": {\n // Fill every field, so nullable unions get their value type.\n const members = resolved.types.filter(\n (member) => member._tag !== \"Null\" && member._tag !== \"Undefined\",\n );\n\n const literals = members.flatMap((member) =>\n member._tag === \"Literal\" ? [member.literal] : [],\n );\n\n if (literals.length > 0 && literals.length === members.length) {\n return ({ faker }) => faker.helpers.arrayElement(literals);\n }\n\n const [only] = members;\n\n return only !== undefined && members.length === 1\n ? value(only, path)\n : unsupported(path, \"a union of several types\");\n }\n case \"Objects\":\n return object(resolved, path);\n case \"Arrays\": {\n const [element] = resolved.rest;\n\n if (resolved.elements.length > 0 || resolved.rest.length !== 1 || !element) {\n return unsupported(path, \"a tuple\");\n }\n\n const item = value(element, `${path}[]`);\n\n return (context) =>\n Array.from({ length: context.faker.number.int({ max: 3 }) }, () => item(context));\n }\n case \"Declaration\":\n return declaration(resolved, path);\n case \"Suspend\":\n return value(resolved.thunk, path);\n default:\n return unsupported(path, resolved._tag);\n }\n };\n\n const declaration = (node: SchemaRepresentation.Declaration, path: string): Value => {\n switch (node.representation?.id) {\n case \"effect/schema/Date\":\n return ({ faker, now }) =>\n faker.date.between({ from: now.getTime() - twoYears, to: now });\n case \"effect/schema/Uint8Array\":\n return ({ faker }) => Uint8Array.from({ length: 8 }, () => faker.number.int(255));\n case \"effect/schema/ReadonlyMap\": {\n const [keyNode, valueNode] = node.typeParameters;\n if (!keyNode || !valueNode) return unsupported(path, \"a map without key or value\");\n const key = value(keyNode, `${path}.key`);\n const item = value(valueNode, `${path}.value`);\n\n return (context) =>\n new Map(\n Array.from({ length: context.faker.number.int({ max: 3 }) }, () => [\n key(context),\n item(context),\n ]),\n );\n }\n default:\n return unsupported(path, node.representation?.id ?? \"an unnamed declaration\");\n }\n };\n\n const fields = requiredFields(representation, \"$\");\n\n return (context, row) => ({\n ...Object.fromEntries(\n fields.filter(([name]) => !(name in row)).map(([name, make]) => [name, make(context)]),\n ),\n ...row,\n });\n },\n catch: (cause) =>\n new ConnectorError({\n message: cause instanceof Unsupported ? cause.message : \"Failed to compile demo rows\",\n cause,\n }),\n });\n","import { Faker, base, en } from \"@faker-js/faker\";\nimport { Array as Arr, Effect, Option, Schema, Stream } from \"effect\";\n\nimport type { DemoDefinition, DemoTable } from \"./definition\";\n\nimport { ConnectorError } from \"../errors\";\nimport { ingestBatch } from \"../ingestor/instrumented\";\nimport { Ingestor, type IngestResult } from \"../ingestor/service\";\nimport { compileRow, type DemoContext } from \"./generate\";\n\nexport type RunOptions = {\n /** Stop once this many Arrow bytes are written. */\n readonly bytes: number;\n readonly seed: number;\n /** The time data is made around. Same seed, time and tables give the same rows. */\n readonly now: Date;\n /** Groups per chunk. Overrides the demo's. */\n readonly groupsPerChunk?: number;\n};\n\nexport type DemoTotals = IngestResult & {\n readonly tables: Readonly<Record<string, IngestResult>>;\n};\n\nconst empty: DemoTotals = { rows: 0, bytes: 0, tables: {} };\n\n// Wings rejects Flight messages over 4 MiB. 500 rows keeps a batch of the\n// widest demo rows well under that.\nconst batchRows = 500;\n\nconst sum = (results: ReadonlyArray<IngestResult>): IngestResult => ({\n rows: results.reduce((total, result) => total + result.rows, 0),\n bytes: results.reduce((total, result) => total + result.bytes, 0),\n});\n\nconst add = (totals: DemoTotals, written: ReadonlyArray<readonly [string, IngestResult]>) =>\n written.reduce<DemoTotals>(\n (current, [name, result]) => ({\n rows: current.rows + result.rows,\n bytes: current.bytes + result.bytes,\n tables: {\n ...current.tables,\n [name]: {\n rows: (current.tables[name]?.rows ?? 0) + result.rows,\n bytes: (current.tables[name]?.bytes ?? 0) + result.bytes,\n },\n },\n }),\n totals,\n );\n\n/**\n * Writes the setup rows, then groups, until it reaches the size or the demo's\n * count. It can go over the size by one chunk. Only bound tables are\n * written; keys still point to the others.\n */\nexport const run = Effect.fnUntraced(function* (demo: DemoDefinition, options: RunOptions) {\n const ingestor = yield* Ingestor;\n\n const bound = (table: DemoTable) =>\n ingestor.resourceNames === undefined || ingestor.resourceNames.includes(table.name);\n\n // A fresh Faker per run, so its sequence depends only on the seed.\n const faker = new Faker({ locale: [en, base] });\n faker.seed(options.seed);\n const context: DemoContext = { faker, now: options.now };\n\n const prepare = (tables: ReadonlyArray<DemoTable>) =>\n Effect.forEach(tables.filter(bound), (table) =>\n compileRow(table.rowSchema).pipe(\n Effect.map((fill) => ({\n table,\n fill,\n decode: Schema.decodeUnknownEffect(Schema.toType(table.rowSchema)),\n })),\n ),\n );\n\n const write = (\n tables: Effect.Success<ReturnType<typeof prepare>>,\n rowsOf: (name: string) => ReadonlyArray<object>,\n ) =>\n Effect.forEach(tables, ({ table, fill, decode }) =>\n Effect.forEach(rowsOf(table.name), (row) =>\n decode(fill(context, row)).pipe(\n Effect.mapError(\n (cause) => new ConnectorError({ message: `Invalid demo row for ${table.name}`, cause }),\n ),\n ),\n ).pipe(\n Effect.flatMap((rows) =>\n Effect.forEach(Arr.chunksOf(rows, batchRows), (batch) =>\n ingestBatch({\n connector: demo.name,\n resource: table.name,\n source: \"demo\",\n batch: { rows: batch },\n }),\n ),\n ),\n Effect.map((results) => [table.name, sum(results)] as const),\n ),\n );\n\n const setupTables = yield* prepare(demo.setup.tables);\n const groupTables = yield* prepare(demo.group.tables);\n\n const setup = demo.setup.rows(context);\n const afterSetup = add(empty, yield* write(setupTables, (name) => setup[name] ?? []));\n\n const totals =\n afterSetup.bytes >= options.bytes || groupTables.length === 0\n ? afterSetup\n : yield* Stream.range(0, (demo.group.count ?? Infinity) - 1).pipe(\n Stream.grouped(options.groupsPerChunk ?? demo.group.groupsPerChunk ?? 100),\n Stream.mapEffect((indexes) => {\n const groups = indexes.map((index) => demo.group.rows(index, context));\n return write(groupTables, (name) => groups.flatMap((group) => group[name] ?? []));\n }),\n Stream.scan(() => afterSetup, add),\n Stream.takeUntil((current) => current.bytes >= options.bytes),\n Stream.tap((current) =>\n Effect.logInfo(\"demo progress\").pipe(\n Effect.annotateLogs({ rows: current.rows, bytes: current.bytes }),\n ),\n ),\n Stream.runLast,\n Effect.map(Option.getOrElse(() => afterSetup)),\n );\n\n if (totals.bytes < options.bytes) {\n yield* Effect.logWarning(\n \"The selected tables ran out of rows, so the run wrote less than the size asked for\",\n ).pipe(Effect.annotateLogs({ bytes: totals.bytes, target: options.bytes }));\n }\n\n yield* Effect.logInfo(\"demo done\").pipe(\n Effect.annotateLogs({ rows: totals.rows, bytes: totals.bytes, tables: totals.tables }),\n );\n\n return totals;\n});\n","export { type DemoContext } from \"./generate\";\nexport { define, table, type DemoDefinition, type DemoRows, type DemoTable } from \"./definition\";\nexport { run, type DemoTotals, type RunOptions } from \"./run\";\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Data } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/errors/connector-error.ts
|
|
4
3
|
var ConnectorError = class extends Data.TaggedError("ConnectorError") {};
|
|
5
|
-
|
|
6
4
|
//#endregion
|
|
7
5
|
export { ConnectorError as t };
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=errors-pT0YVJU5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-pT0YVJU5.mjs","names":[],"sources":["../src/errors/connector-error.ts"],"sourcesContent":["import { Data } from \"effect\";\n\nexport class ConnectorError extends Data.TaggedError(\"ConnectorError\")<{\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n"],"mappings":";;AAEA,IAAa,iBAAb,cAAoC,KAAK,YAAY,gBAAgB,CAAC,CAGnE,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as ids, i as identifier, r as field } from "../annotations-BE74YmAO.mjs";
|
|
2
|
+
import { i as IcebergSchemaError, n as CreateTableCommitOptions, r as makeCreateTableCommitRequest } from "../index-DJhDp4Xc.mjs";
|
|
3
|
+
export { type CreateTableCommitOptions, IcebergSchemaError, field, identifier, ids, makeCreateTableCommitRequest };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { a as IcebergSchemaError, i as makeCreateTableCommitRequest } from "./table-V0tgUC5i.mjs";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
//#region src/iceberg/annotations.ts
|
|
5
|
+
/** Sets a field's Iceberg ID, and any other annotations. */
|
|
6
|
+
const field = (fieldId, annotations = {}) => (schema) => schema.pipe(Schema.annotateKey({
|
|
7
|
+
...annotations,
|
|
8
|
+
fieldId
|
|
9
|
+
}));
|
|
10
|
+
/** Adds an offset to a base ID for reusable schemas. */
|
|
11
|
+
const ids = (baseId) => (offset) => baseId + offset;
|
|
12
|
+
/**
|
|
13
|
+
* Marks the fields that identify a row. Wings upserts rows by them.
|
|
14
|
+
*
|
|
15
|
+
* Put it last. A later `.annotate()` keeps the runtime annotation, but the type
|
|
16
|
+
* loses the key, so `Resource.entity` stops compiling.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const Post = Schema.Struct({
|
|
21
|
+
* id: Schema.String.pipe(Iceberg.field(1)),
|
|
22
|
+
* updatedAt: Schema.String.pipe(Iceberg.field(2)),
|
|
23
|
+
* }).pipe(Iceberg.identifier("id"));
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
const identifier = (...keys) => (schema) => schema.annotate({ icebergIdentifierFields: keys });
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/iceberg/index.ts
|
|
29
|
+
var iceberg_exports = /* @__PURE__ */ __exportAll({
|
|
30
|
+
IcebergSchemaError: () => IcebergSchemaError,
|
|
31
|
+
field: () => field,
|
|
32
|
+
identifier: () => identifier,
|
|
33
|
+
ids: () => ids,
|
|
34
|
+
makeCreateTableCommitRequest: () => makeCreateTableCommitRequest
|
|
35
|
+
});
|
|
36
|
+
//#endregion
|
|
37
|
+
export { ids as i, field as n, identifier as r, iceberg_exports as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=iceberg-D6L8I6vA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iceberg-D6L8I6vA.mjs","names":[],"sources":["../src/iceberg/annotations.ts","../src/iceberg/index.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\ndeclare module \"effect/Schema\" {\n namespace Annotations {\n interface Annotations {\n readonly fieldId?: number | undefined;\n readonly icebergIdentifierFields?: ReadonlyArray<string> | undefined;\n }\n }\n}\n\n/** Sets a field's Iceberg ID, and any other annotations. */\nexport const field =\n <A = unknown>(fieldId: number, annotations: Schema.Annotations.Key<A> = {}) =>\n <S extends Schema.Schema<A>>(schema: S): S[\"Rebuild\"] =>\n schema.pipe(Schema.annotateKey({ ...annotations, fieldId }));\n\n/** Adds an offset to a base ID for reusable schemas. */\nexport const ids =\n (baseId: number) =>\n (offset: number): number =>\n baseId + offset;\n\ntype KnownField<S extends Schema.Top> = keyof S[\"Type\"] & string;\n\n/** A row field that cannot be null or undefined. */\nexport type RequiredField<S extends Schema.Top> = [KnownField<S>] extends [never]\n ? string\n : {\n readonly [Field in KnownField<S>]-?: undefined extends S[\"Type\"][Field]\n ? never\n : null extends S[\"Type\"][Field]\n ? never\n : Field;\n }[KnownField<S>];\n\n/** A row schema whose identifier fields are `Key`. Only the type has it. */\nexport interface Identified<Key extends string> {\n readonly \"~iceberg.identifier\": Key;\n}\n\n/**\n * Marks the fields that identify a row. Wings upserts rows by them.\n *\n * Put it last. A later `.annotate()` keeps the runtime annotation, but the type\n * loses the key, so `Resource.entity` stops compiling.\n *\n * @example\n * ```ts\n * const Post = Schema.Struct({\n * id: Schema.String.pipe(Iceberg.field(1)),\n * updatedAt: Schema.String.pipe(Iceberg.field(2)),\n * }).pipe(Iceberg.identifier(\"id\"));\n * ```\n */\nexport const identifier =\n <S extends Schema.Top, const Key extends RequiredField<S>>(\n ...keys: readonly [Key, ...ReadonlyArray<Key>]\n ) =>\n (schema: S): S[\"Rebuild\"] & Identified<Key> =>\n // Effect has no slot for the key in the schema type, so we add it.\n schema.annotate({ icebergIdentifierFields: keys }) as S[\"Rebuild\"] & Identified<Key>;\n","export { field, identifier, ids } from \"./annotations\";\nexport { IcebergSchemaError } from \"./error\";\nexport { makeCreateTableCommitRequest, type CreateTableCommitOptions } from \"./table\";\n"],"mappings":";;;;;AAYA,MAAa,SACG,SAAiB,cAAyC,CAAC,OAC5C,WAC3B,OAAO,KAAK,OAAO,YAAY;CAAE,GAAG;CAAa;AAAQ,CAAC,CAAC;;AAG/D,MAAa,OACV,YACA,WACC,SAAS;;;;;;;;;;;;;;;AAkCb,MAAa,cAET,GAAG,UAEJ,WAEC,OAAO,SAAS,EAAE,yBAAyB,KAAK,CAAC"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as StateStore } from "./index-
|
|
1
|
+
import { r as ConnectorDefinition } from "./types-xZtSmrGA.mjs";
|
|
2
|
+
import { i as StateStore } from "./index-CgvFomO6.mjs";
|
|
3
3
|
import { Schema } from "effect";
|
|
4
|
-
import { HttpRouter } from "effect/
|
|
5
|
-
import * as effect_Layer0 from "effect/Layer";
|
|
6
|
-
|
|
4
|
+
import { HttpRouter } from "effect/http";
|
|
7
5
|
//#region src/status/route.d.ts
|
|
8
|
-
declare const statusRoute: (connector: ConnectorDefinition, path?: HttpRouter.PathInput) =>
|
|
6
|
+
declare const statusRoute: (connector: ConnectorDefinition, path?: HttpRouter.PathInput) => import("effect/Layer").Layer<never, never, HttpRouter.HttpRouter | HttpRouter.Request<"Requires", StateStore>>;
|
|
9
7
|
//#endregion
|
|
10
8
|
//#region src/status/types.d.ts
|
|
11
9
|
declare const SyncStateSchema: Schema.Literals<readonly ["pending", "backfilling", "live", "error"]>;
|
|
@@ -14,8 +12,8 @@ type SyncState = Schema.Schema.Type<typeof SyncStateSchema>;
|
|
|
14
12
|
declare const ResourceErrorSchema: Schema.Struct<{
|
|
15
13
|
readonly at: Schema.String;
|
|
16
14
|
readonly source: Schema.Literals<readonly ["backfill", "changes"]>;
|
|
17
|
-
readonly operation: Schema.Literals<readonly ["fetch", "
|
|
18
|
-
readonly code: Schema.Literals<readonly ["fetch_failed", "
|
|
15
|
+
readonly operation: Schema.Literals<readonly ["fetch", "ingest", "checkpoint"]>;
|
|
16
|
+
readonly code: Schema.Literals<readonly ["fetch_failed", "ingest_failed", "checkpoint_failed"]>;
|
|
19
17
|
readonly message: Schema.String;
|
|
20
18
|
}>;
|
|
21
19
|
type ResourceError = Schema.Schema.Type<typeof ResourceErrorSchema>;
|
|
@@ -33,8 +31,8 @@ declare const ResourceStatusSchema: Schema.Struct<{
|
|
|
33
31
|
readonly lastError: Schema.optional<Schema.Struct<{
|
|
34
32
|
readonly at: Schema.String;
|
|
35
33
|
readonly source: Schema.Literals<readonly ["backfill", "changes"]>;
|
|
36
|
-
readonly operation: Schema.Literals<readonly ["fetch", "
|
|
37
|
-
readonly code: Schema.Literals<readonly ["fetch_failed", "
|
|
34
|
+
readonly operation: Schema.Literals<readonly ["fetch", "ingest", "checkpoint"]>;
|
|
35
|
+
readonly code: Schema.Literals<readonly ["fetch_failed", "ingest_failed", "checkpoint_failed"]>;
|
|
38
36
|
readonly message: Schema.String;
|
|
39
37
|
}>>;
|
|
40
38
|
readonly name: Schema.String;
|
|
@@ -57,8 +55,8 @@ declare const StatusResponseSchema: Schema.Struct<{
|
|
|
57
55
|
readonly lastError: Schema.optional<Schema.Struct<{
|
|
58
56
|
readonly at: Schema.String;
|
|
59
57
|
readonly source: Schema.Literals<readonly ["backfill", "changes"]>;
|
|
60
|
-
readonly operation: Schema.Literals<readonly ["fetch", "
|
|
61
|
-
readonly code: Schema.Literals<readonly ["fetch_failed", "
|
|
58
|
+
readonly operation: Schema.Literals<readonly ["fetch", "ingest", "checkpoint"]>;
|
|
59
|
+
readonly code: Schema.Literals<readonly ["fetch_failed", "ingest_failed", "checkpoint_failed"]>;
|
|
62
60
|
readonly message: Schema.String;
|
|
63
61
|
}>>;
|
|
64
62
|
readonly name: Schema.String;
|
|
@@ -77,4 +75,4 @@ declare namespace index_d_exports {
|
|
|
77
75
|
}
|
|
78
76
|
//#endregion
|
|
79
77
|
export { ResourceStatusSchema as a, StatusUnavailableResponse as c, SyncStateSchema as d, statusRoute as f, ResourceStatus as i, StatusUnavailableResponseSchema as l, ResourceError as n, StatusResponse as o, ResourceErrorSchema as r, StatusResponseSchema as s, index_d_exports as t, SyncState as u };
|
|
80
|
-
//# sourceMappingURL=index-
|
|
78
|
+
//# sourceMappingURL=index-BUHSGm9Q.d.mts.map
|