@ingestron/core 0.12.2 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/compiler-fingerprint.json +22 -20
- package/dist/core/authoring.js +42 -9
- package/dist/core/connections.js +19 -10
- package/dist/core/connector-package.d.ts +1 -0
- package/dist/core/connector-package.js +5 -1
- package/dist/core/ecosystem-authoring.js +2 -1
- package/dist/core/packages.d.ts +5 -0
- package/dist/core/packages.js +19 -1
- package/dist/core/planner.d.ts +4 -0
- package/dist/core/planner.js +3 -2
- package/dist/core/project-build.js +4 -3
- package/dist/core/project-packages.d.ts +7 -0
- package/dist/core/project-packages.js +6 -0
- package/dist/core/provider-commands.js +6 -5
- package/dist/core/schema.d.ts +6 -2
- package/dist/core/schema.js +2 -1
- package/dist/core/workflows.js +47 -15
- package/dist/plugins/authoring.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@ connector runtime assets and standards through explicit package references.
|
|
|
9
9
|
|
|
10
10
|
## Use the library
|
|
11
11
|
|
|
12
|
-
Requires Node 22.12 or newer for runtime operations. The npm package name is
|
|
13
|
-
|
|
12
|
+
Requires Node 22.12 or newer for runtime operations. The npm package name is
|
|
13
|
+
`@ingestron/core`. To build the public source checkout:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
16
|
pnpm install --frozen-lockfile
|
|
@@ -36,6 +36,14 @@ project through a reviewed change proposal. It needs no provider, cloud account
|
|
|
36
36
|
source data. Building native assets requires an installed provider and configured
|
|
37
37
|
flows.
|
|
38
38
|
|
|
39
|
+
In a project, `packages` maps short names to exact installed releases. The
|
|
40
|
+
`packages.lock.yaml` file retains each full repository reference, commit and
|
|
41
|
+
file hashes. An ingestion connection holds endpoint and authentication settings;
|
|
42
|
+
each `flow.tables` entry selects one physical source object and its ODCS contract
|
|
43
|
+
selects the output columns. Connector packages define the allowed table source
|
|
44
|
+
shape, so the same project layout works across source types. Older stream-based
|
|
45
|
+
connector releases remain supported.
|
|
46
|
+
|
|
39
47
|
## Integration guides
|
|
40
48
|
|
|
41
49
|
- [Operation and editor API](docs/api.md): requests, results, permissions, errors
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
"dist/assets/schemas/ODCS-LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
|
|
4
4
|
"dist/assets/schemas/odcs-3.1.0.json": "1a35de14c688b400fef306564f66e2af3304f057cd5cd6e7b847c1a8bf252c5b",
|
|
5
5
|
"dist/assets/schemas/provenance.json": "4b5eb1fd89b81223f7946113b651d5a3a18adaa28948e43c3615dd851fb6844e",
|
|
6
|
-
"dist/core/authoring.js": "
|
|
6
|
+
"dist/core/authoring.js": "c144374cccbb512be7b3cd26700bc29538236eeeb35493eeec3bab938e08ff2a",
|
|
7
7
|
"dist/core/config.js": "b7e7138f7cc4a7b4ec8f6d0f0616c8802f2d802ec29aa09b40c1fc5c9324e016",
|
|
8
|
-
"dist/core/connections.js": "
|
|
9
|
-
"dist/core/connector-package.js": "
|
|
8
|
+
"dist/core/connections.js": "37b797b402788e00c51f3cac93b87342d158ed9b279753db91006d2d6c66bb4a",
|
|
9
|
+
"dist/core/connector-package.js": "de9729e9e4b0cf05bd1ef347e57ffd489245bb68efce5c313ccba72b78409f41",
|
|
10
10
|
"dist/core/contracts.js": "a1b7fd28f776117cca86a25c6c70e852ff57ffea2bb9e7accbf2d583948d9dde",
|
|
11
11
|
"dist/core/deliveries.js": "a4d2cb1213bc4c02cffb962dcb943ba98e261d37cfb21041948ec637599db080",
|
|
12
12
|
"dist/core/delivery-exports.js": "d895b044c08f2059f0275724205120c72dd4bf5b74170bb01bdf42dd9d526d56",
|
|
13
13
|
"dist/core/development.js": "2b55b15d545172e527cf66868d96d97c5ca081d0a83892ffd253eadaa3cc1b39",
|
|
14
|
-
"dist/core/ecosystem-authoring.js": "
|
|
14
|
+
"dist/core/ecosystem-authoring.js": "4320560eac2d2060e9e20be6a097759512c709a04fb7dc0520147ecd5ff6655e",
|
|
15
15
|
"dist/core/errors.js": "8117e35fba84ae34627cb7d3bef46aaf6d8718c512140fa0ab08ccbdeeeec8c3",
|
|
16
16
|
"dist/core/execution.js": "496807e7428528e31e76d51144dfd84682d435467b30a35574310af525ddeca7",
|
|
17
17
|
"dist/core/extension-packs.js": "6b2aaa83e51f40e176cc4cfed574a4a17646bb3f526666fe8e0456d2912a8045",
|
|
@@ -23,14 +23,15 @@
|
|
|
23
23
|
"dist/core/model-packs.js": "fee776ea0804dc66c9f140e57d94a3922d69c52d03c72079842ec43417616b0d",
|
|
24
24
|
"dist/core/operations.js": "7f4a9eeee19d3e1e4c1beecc0350e38d386f012edfb31c3248efcd22ebd40a77",
|
|
25
25
|
"dist/core/package-references.js": "bd3085eb6dcdac399d79af109d0a9e710a0532eba61e5298dc842aec9c7ef10a",
|
|
26
|
-
"dist/core/packages.js": "
|
|
27
|
-
"dist/core/planner.js": "
|
|
28
|
-
"dist/core/project-build.js": "
|
|
29
|
-
"dist/core/
|
|
26
|
+
"dist/core/packages.js": "c6bcbc90aa3597fcd4205b27136221229d9efedc9bfa68a83a134cb5e8f51d2b",
|
|
27
|
+
"dist/core/planner.js": "974c6bac5c533a32a7c45f797ef4d857c644448aa243a929caca5917fb9f3fb8",
|
|
28
|
+
"dist/core/project-build.js": "18ffe962068967af255e77f1dc48fa4dd9161cd50659a8a3d9ac3b161856082e",
|
|
29
|
+
"dist/core/project-packages.js": "b031dd9e3c5c147e8e1ed589b5eab21b9067acbefc1d4cd1dc5b6b7018cc39cf",
|
|
30
|
+
"dist/core/provider-commands.js": "4f9b1565b3252a8c9c49a19a69b92fb6a72cc800cadc3e97812bf88c7e808466",
|
|
30
31
|
"dist/core/provider-starter.js": "69795c1b79360e48664e91db0768f813fe4efc91aede003e1bf032f71731754c",
|
|
31
32
|
"dist/core/report-pack-schema.js": "fe8ecdc2b8deacd8b2a1e46588ee06744a7b6d8e7342786e320f74cc848665fa",
|
|
32
|
-
"dist/core/schema.js": "
|
|
33
|
-
"dist/core/workflows.js": "
|
|
33
|
+
"dist/core/schema.js": "821e79cfc56dbd8c206959c53c0cda6d81507ae78010da1ec614e204c17d96eb",
|
|
34
|
+
"dist/core/workflows.js": "e0b9e34fdd9b3f56403e8beb58e2b0bfbc0604beccb3113fc529c460817bc4d4",
|
|
34
35
|
"dist/plugins/authoring.js": "ff985a7173c7aeda4a431a8603a4ab8631dc5134486578ede7d1301ebc3e6a19",
|
|
35
36
|
"dist/plugins/compatibility.js": "a6591cfa4ca5a324fd29856e51319e39be470d6ed835ee268b293727ce11f8b7",
|
|
36
37
|
"dist/plugins/generation.js": "7b0bae4de23edab4c2596d1f8ed2244d70b30fcae60395994b3964ffc845e9d5",
|
|
@@ -42,15 +43,15 @@
|
|
|
42
43
|
"dist/version.js": "48af2aa1e425f1e387c082bbf0ad2c0c8d757c468101a614c3864153a94e6889"
|
|
43
44
|
},
|
|
44
45
|
"sources": {
|
|
45
|
-
"src/core/authoring.ts": "
|
|
46
|
+
"src/core/authoring.ts": "4389a1c8994b1c5da6d470e29806e547d9e5c13ed481b5e34acbe919b6b4b3d8",
|
|
46
47
|
"src/core/config.ts": "f282eb246438608e1951556dfeab9372daf65330a15a9d159d36d1f940370344",
|
|
47
|
-
"src/core/connections.ts": "
|
|
48
|
-
"src/core/connector-package.ts": "
|
|
48
|
+
"src/core/connections.ts": "dbdaca4193efa203cffa02fd819b95f82bbd604a7678ba7dc6ba065205c49ce7",
|
|
49
|
+
"src/core/connector-package.ts": "a36151f6ffb49836547984eae871023ad1ad69a136f33cd6ad608496f84c85f8",
|
|
49
50
|
"src/core/contracts.ts": "b7445086085b17d5ae8d5a7f4e2e849f286948e1a2a146ceb79660846e8616e5",
|
|
50
51
|
"src/core/deliveries.ts": "6be0a7059c057420ba22a5515703164a892fac9e79a5bdb0e0871ea0b92ddd15",
|
|
51
52
|
"src/core/delivery-exports.ts": "45a4d13e73a3809340fcd0f018dd06e2e360c67c1a117c672cd48be463c82d58",
|
|
52
53
|
"src/core/development.ts": "decd47d8f6ca3289fea45331f27b99b0feb7188ae0a9e152c6459cc00658e7bd",
|
|
53
|
-
"src/core/ecosystem-authoring.ts": "
|
|
54
|
+
"src/core/ecosystem-authoring.ts": "61a44100843273e74b385704195b5e36a72afb9482f910eaacdcf3abda7be38e",
|
|
54
55
|
"src/core/errors.ts": "55e7ec3239bb3bcae73cf37e700cd83b9ea3336bf5514062827a3627a606977d",
|
|
55
56
|
"src/core/execution.ts": "44ebbe7b6f64e0c3c224dd6f419939e500de92b7e4e8b283b0b33266e1d1fbf1",
|
|
56
57
|
"src/core/extension-packs.ts": "76671a6971598212c9ec0bb0ce9b75feee13dec09565fa0adc9f050a6ae668ec",
|
|
@@ -62,14 +63,15 @@
|
|
|
62
63
|
"src/core/model-packs.ts": "a110d319f6feeff22a2d0d3a99ce5e49e56817d0cc27ab77d831d04a945ddfd3",
|
|
63
64
|
"src/core/operations.ts": "e0a5a0e869e96de4e869f89e0fd794cb9fa537a16fb1f37fd8cf2b7ca777c08d",
|
|
64
65
|
"src/core/package-references.ts": "5c5cee7e140158928e2e5a37f426520c7c2f042546a37eed4507d79326181f5a",
|
|
65
|
-
"src/core/packages.ts": "
|
|
66
|
-
"src/core/planner.ts": "
|
|
67
|
-
"src/core/project-build.ts": "
|
|
68
|
-
"src/core/
|
|
66
|
+
"src/core/packages.ts": "8a9b6612325de68ab2610f540bd39e4f899b06d1cc1fbd54ecfd2abb8b4e9c40",
|
|
67
|
+
"src/core/planner.ts": "2c6f0d53e21cbb60fc2433e7da1245707133336274c60b9a5678614dabf09bca",
|
|
68
|
+
"src/core/project-build.ts": "7fa5038e7e2ff2625a30ffae282369954a5989347c6435849b72c95f2e52e247",
|
|
69
|
+
"src/core/project-packages.ts": "4c5cb98aeb5030db7cf2c851cd9e40ed9aae038517fba2d8d7159e884f08b7a0",
|
|
70
|
+
"src/core/provider-commands.ts": "195133079085aae57208bee607af439d0ea09456d526e27ec73bfdc9d727805f",
|
|
69
71
|
"src/core/provider-starter.ts": "eeb504e347638bb933d204dd4d5a7e3e94ff45db136c5edd3fb457061342e405",
|
|
70
72
|
"src/core/report-pack-schema.ts": "cf2c68f3725cef847627ce61acd0887f04d0067bc324841d8a552bcb12d274b0",
|
|
71
|
-
"src/core/schema.ts": "
|
|
72
|
-
"src/core/workflows.ts": "
|
|
73
|
+
"src/core/schema.ts": "a99a90e51be10ed56713573df6f238e6aca5b897a9679fe7bd2a8c0ad1e7f586",
|
|
74
|
+
"src/core/workflows.ts": "f9e8d7f0a3841b5e385a5279e202f5a3334972bb549c8c85f01e7cfbb4e16f25",
|
|
73
75
|
"src/plugins/authoring.ts": "a0d68d406b4569c0b48eec458407d24c3d4eeed5b7918c6c4fcb3828ada93fe5",
|
|
74
76
|
"src/plugins/compatibility.ts": "b5d357a1dc2a972cf8209311602f9fd816ba0a59cbe747f86f1b5567754073ea",
|
|
75
77
|
"src/plugins/generation.ts": "a495906af09cf7bf820c7aba390bf742d7e94328ce708a2ff40f613f451fe237",
|
package/dist/core/authoring.js
CHANGED
|
@@ -5,8 +5,28 @@ import { resolve, dirname, relative } from "node:path";
|
|
|
5
5
|
import { parseDocument, stringify } from "yaml";
|
|
6
6
|
import { check, digest, canonical, merge, Problem } from "./errors.js";
|
|
7
7
|
import { Configuration } from "./config.js";
|
|
8
|
+
import { packageReferenceSchema, projectSchema } from "./schema.js";
|
|
9
|
+
import { projectPackages } from "./project-packages.js";
|
|
8
10
|
import { contractColumns } from "./contracts.js";
|
|
9
|
-
import { fence, installedProviders, canonicalPackageReference, } from "./packages.js";
|
|
11
|
+
import { fence, installedProviders, canonicalPackageReference, configuredPackageReference, resolvePackage, packageYaml, } from "./packages.js";
|
|
12
|
+
function concisePackageReference(root, value) {
|
|
13
|
+
const pkg = packageReferenceSchema.parse(value);
|
|
14
|
+
const reference = configuredPackageReference(pkg);
|
|
15
|
+
const installed = resolvePackage(root, reference);
|
|
16
|
+
const manifest = packageYaml(installed.file);
|
|
17
|
+
const short = `${manifest.id}@${manifest.version}`;
|
|
18
|
+
try {
|
|
19
|
+
const selected = resolvePackage(root, short);
|
|
20
|
+
if (selected.entry.repository === installed.entry.repository &&
|
|
21
|
+
selected.entry.path === installed.entry.path &&
|
|
22
|
+
selected.entry.commit === installed.entry.commit)
|
|
23
|
+
return short;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Keep an explicit reference if multiple installed packages share the ID.
|
|
27
|
+
}
|
|
28
|
+
return `${pkg.source}@${pkg.version}`;
|
|
29
|
+
}
|
|
10
30
|
const yaml = (text, file) => {
|
|
11
31
|
const doc = parseDocument(text, { uniqueKeys: true });
|
|
12
32
|
check(!doc.errors.length, "YAML", doc.errors[0]?.message ?? "Invalid YAML", file);
|
|
@@ -114,7 +134,8 @@ export function initialise(root, options) {
|
|
|
114
134
|
"project.yaml": stringify({
|
|
115
135
|
apiVersion: "ingestron.project/v1",
|
|
116
136
|
id: options.id,
|
|
117
|
-
|
|
137
|
+
packages: {},
|
|
138
|
+
providers: { configurations: {} },
|
|
118
139
|
defaults: {},
|
|
119
140
|
environments: Object.fromEntries(environments.map((name) => [
|
|
120
141
|
name,
|
|
@@ -148,6 +169,16 @@ export function initialise(root, options) {
|
|
|
148
169
|
name === ".gitignore" ||
|
|
149
170
|
/^environments\/[\w-]+\.yaml$/.test(name));
|
|
150
171
|
check(files["project.yaml"], "PROVIDER", "Provider must author a project");
|
|
172
|
+
const authored = yaml(files["project.yaml"], "project.yaml").toJS();
|
|
173
|
+
const providerPackages = authored.providers?.packages ?? {};
|
|
174
|
+
authored.packages ??= {};
|
|
175
|
+
for (const [name, value] of Object.entries(providerPackages)) {
|
|
176
|
+
check(!Object.hasOwn(authored.packages, name), "PACKAGE", `Duplicate package alias ${name}`);
|
|
177
|
+
authored.packages[name] = concisePackageReference(root, value);
|
|
178
|
+
}
|
|
179
|
+
if (authored.providers)
|
|
180
|
+
delete authored.providers.packages;
|
|
181
|
+
files["project.yaml"] = stringify(authored);
|
|
151
182
|
// Providers may return JSON (valid YAML); editable scaffolds use block YAML.
|
|
152
183
|
for (const [name, text] of Object.entries(files)) {
|
|
153
184
|
if (name.endsWith(".yaml"))
|
|
@@ -159,12 +190,14 @@ export function initialise(root, options) {
|
|
|
159
190
|
}
|
|
160
191
|
export function migrateProvider(root, options) {
|
|
161
192
|
const reader = new Configuration(root), doc = yaml(reader.text("project.yaml"), "project.yaml");
|
|
162
|
-
|
|
193
|
+
const location = doc.hasIn(["packages", options.package])
|
|
194
|
+
? ["packages", options.package]
|
|
195
|
+
: ["providers", "packages", options.package];
|
|
196
|
+
check(doc.hasIn(location), "PACKAGE", "Unknown project package");
|
|
163
197
|
const selected = providerReference(root, options.to);
|
|
164
|
-
doc.setIn(
|
|
165
|
-
|
|
166
|
-
version: selected.version
|
|
167
|
-
});
|
|
198
|
+
doc.setIn(location, location[0] === "packages"
|
|
199
|
+
? concisePackageReference(root, `${selected.source}@${selected.version}`)
|
|
200
|
+
: { source: selected.source, version: selected.version });
|
|
168
201
|
return preview(root, { "project.yaml": doc.toString() });
|
|
169
202
|
}
|
|
170
203
|
function flowFile(root, id) {
|
|
@@ -186,7 +219,7 @@ export function addFlow(root, options) {
|
|
|
186
219
|
const configuration = options.provider ?? resolved.defaults.provider;
|
|
187
220
|
const config = resolved.providers.configurations[configuration];
|
|
188
221
|
check(config, "PROVIDER", "Select a provider configuration for this flow");
|
|
189
|
-
const pkg = resolved
|
|
222
|
+
const pkg = projectPackages(projectSchema.parse(resolved))[config.package];
|
|
190
223
|
const environments = Object.values(raw.environments).map((ref) => {
|
|
191
224
|
check(ref.$resolve, "AUTHORING", "Keep editable environments in referenced files");
|
|
192
225
|
const file = reader.path(ref.$resolve);
|
|
@@ -196,7 +229,7 @@ export function addFlow(root, options) {
|
|
|
196
229
|
value: yaml(reader.text(file), file).toJS(),
|
|
197
230
|
};
|
|
198
231
|
});
|
|
199
|
-
const files = providerAuthor(root,
|
|
232
|
+
const files = providerAuthor(root, resolvePackage(root, configuredPackageReference(pkg)).reference, {
|
|
200
233
|
operation: "flow",
|
|
201
234
|
options,
|
|
202
235
|
configuration,
|
package/dist/core/connections.js
CHANGED
|
@@ -7,8 +7,9 @@ import { resolveModelContracts } from "./model-packs.js";
|
|
|
7
7
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
8
8
|
import { Configuration } from "./config.js";
|
|
9
9
|
import { projectSchema, flowSchema } from "./schema.js";
|
|
10
|
+
import { projectPackages } from "./project-packages.js";
|
|
10
11
|
import { canonical, check, digest, isMap } from "./errors.js";
|
|
11
|
-
import {
|
|
12
|
+
import { configuredPackageReference, resolvePackage, packageYaml, providerPackageSchema, } from "./packages.js";
|
|
12
13
|
import { checkProviderCompatibility } from "../plugins/compatibility.js";
|
|
13
14
|
import { runProviderCommand, validateSchemaShape, } from "./provider-commands.js";
|
|
14
15
|
function validate(schema, value, label) {
|
|
@@ -37,17 +38,18 @@ export function prepareConnection(root, environment, flowId, validateOnly = fals
|
|
|
37
38
|
check(connection, "CONNECTION", "Unknown ingestion connection");
|
|
38
39
|
const configured = project.providers.configurations[flow.provider ?? project.defaults.provider ?? ""];
|
|
39
40
|
check(configured, "PROVIDER", "Select the execution provider configuration");
|
|
40
|
-
const
|
|
41
|
-
const
|
|
41
|
+
const packages = projectPackages(project);
|
|
42
|
+
const owner = packages[connection.package];
|
|
43
|
+
const executor = packages[configured.package];
|
|
42
44
|
check(owner && executor, "PACKAGE", "Unknown connection/execution package");
|
|
43
45
|
const load = (pkg) => {
|
|
44
|
-
const ref =
|
|
46
|
+
const ref = configuredPackageReference(pkg);
|
|
45
47
|
const locked = resolvePackage(root, ref);
|
|
46
48
|
const manifest = providerPackageSchema.parse(packageYaml(locked.file));
|
|
47
49
|
checkProviderCompatibility(manifest);
|
|
48
50
|
return { ref, locked, manifest };
|
|
49
51
|
};
|
|
50
|
-
const sourceRef =
|
|
52
|
+
const sourceRef = configuredPackageReference(owner);
|
|
51
53
|
const sourceLock = resolvePackage(root, sourceRef);
|
|
52
54
|
const sourceRaw = packageYaml(sourceLock.file);
|
|
53
55
|
check(sourceRaw.apiVersion === "ingestron.connector/v1", "CONNECTION", "Select an independently installed source connector package");
|
|
@@ -88,15 +90,22 @@ export function prepareConnection(root, environment, flowId, validateOnly = fals
|
|
|
88
90
|
check(flow.tables && Object.keys(flow.tables).length > 0, "CONNECTION", "Select at least one table with an ODCS contract");
|
|
89
91
|
const streams = new Set();
|
|
90
92
|
const tables = Object.fromEntries(Object.entries(flow.tables).map(([name, table]) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const source = descriptor.tableSourceSchema
|
|
94
|
+
? { ...table.source, stream: name }
|
|
95
|
+
: table.source;
|
|
96
|
+
if (descriptor.tableSourceSchema)
|
|
97
|
+
validate(descriptor.tableSourceSchema, table.source, `${name} source`);
|
|
98
|
+
else
|
|
99
|
+
check(Object.keys(table.source).length === 1 &&
|
|
100
|
+
typeof table.source.stream === "string", "CONNECTION", `${name}: source must identify one connector stream`);
|
|
101
|
+
check(typeof source.stream === "string", "CONNECTION", `${name}: invalid source stream`);
|
|
102
|
+
check(!streams.has(source.stream), "CONNECTION", "Duplicate source stream");
|
|
103
|
+
streams.add(source.stream);
|
|
95
104
|
check(!table.ingestion && !Object.keys(table.steps).length, "CONNECTION", "Connection tables do not accept ingestion/step overrides");
|
|
96
105
|
return [
|
|
97
106
|
name,
|
|
98
107
|
{
|
|
99
|
-
source
|
|
108
|
+
source,
|
|
100
109
|
contract: table.contract,
|
|
101
110
|
columns: contractColumns(table.contract),
|
|
102
111
|
},
|
|
@@ -29,6 +29,7 @@ export declare const connectorPackageSchema: z.ZodObject<{
|
|
|
29
29
|
definition: z.ZodObject<{
|
|
30
30
|
settingsSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
31
31
|
selectionSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
32
|
+
tableSourceSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
32
33
|
}, z.core.$strict>;
|
|
33
34
|
execution: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
34
35
|
modes: z.ZodArray<z.ZodString>;
|
|
@@ -31,7 +31,11 @@ export const connectorPackageSchema = z
|
|
|
31
31
|
})
|
|
32
32
|
.strict(),
|
|
33
33
|
definition: z
|
|
34
|
-
.object({
|
|
34
|
+
.object({
|
|
35
|
+
settingsSchema: schema,
|
|
36
|
+
selectionSchema: schema,
|
|
37
|
+
tableSourceSchema: schema.optional(),
|
|
38
|
+
})
|
|
35
39
|
.strict(),
|
|
36
40
|
execution: z.record(z.string(), z
|
|
37
41
|
.object({
|
|
@@ -4,6 +4,7 @@ import { Configuration } from "./config.js";
|
|
|
4
4
|
import { preview } from "./authoring.js";
|
|
5
5
|
import { check } from "./errors.js";
|
|
6
6
|
import { projectSchema } from "./schema.js";
|
|
7
|
+
import { projectPackages } from "./project-packages.js";
|
|
7
8
|
import { extensionPackSchema, packageYaml, resolvePackage, providerPackageSchema, } from "./packages.js";
|
|
8
9
|
import { extensionActivities } from "./extension-packs.js";
|
|
9
10
|
import { checkProviderCompatibility } from "../plugins/compatibility.js";
|
|
@@ -31,7 +32,7 @@ export function configurePack(root, args) {
|
|
|
31
32
|
const configuration = project.providers.configurations[args.provider];
|
|
32
33
|
check(configuration, "PROVIDER", "Unknown provider configuration");
|
|
33
34
|
check(!project.providers.packs[args.name], "PACK", "Pack name already exists");
|
|
34
|
-
const pkg = project
|
|
35
|
+
const pkg = projectPackages(project)[configuration.package];
|
|
35
36
|
const file = pkg.source.startsWith(".")
|
|
36
37
|
? reader.path(pkg.source)
|
|
37
38
|
: resolvePackage(root, `${pkg.source}@${pkg.version}`).file;
|
package/dist/core/packages.d.ts
CHANGED
|
@@ -180,6 +180,10 @@ export declare function fence(root: string, name: string): string;
|
|
|
180
180
|
export declare function packageYaml(file: string): any;
|
|
181
181
|
/** Stable convenience names; locks always retain the explicit repository and path. */
|
|
182
182
|
export declare function canonicalPackageReference(reference: string): string;
|
|
183
|
+
export declare function configuredPackageReference(pkg: {
|
|
184
|
+
source: string;
|
|
185
|
+
version: string;
|
|
186
|
+
}): string;
|
|
183
187
|
export declare function packageLock(root: string): {
|
|
184
188
|
apiVersion: "ingestron.packages-lock/v1";
|
|
185
189
|
packages: Record<string, {
|
|
@@ -190,6 +194,7 @@ export declare function packageLock(root: string): {
|
|
|
190
194
|
}>;
|
|
191
195
|
};
|
|
192
196
|
export declare function resolvePackage(root: string, reference: string): {
|
|
197
|
+
reference: string;
|
|
193
198
|
file: string;
|
|
194
199
|
root: string;
|
|
195
200
|
entry: {
|
package/dist/core/packages.js
CHANGED
|
@@ -276,6 +276,12 @@ export function canonicalPackageReference(reference) {
|
|
|
276
276
|
check(repository.includes("/"), "PACKAGE", "Unknown plugin name; use an explicit owner/repository@version");
|
|
277
277
|
return `${repository}/plugin/provider.yaml@${short[2]}`;
|
|
278
278
|
}
|
|
279
|
+
export function configuredPackageReference(pkg) {
|
|
280
|
+
const reference = `${pkg.source}@${pkg.version}`;
|
|
281
|
+
return /^[a-z][a-z0-9-]*@(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/.test(reference)
|
|
282
|
+
? reference
|
|
283
|
+
: canonicalPackageReference(reference);
|
|
284
|
+
}
|
|
279
285
|
const parseReference = (reference) => {
|
|
280
286
|
check(!reference.endsWith("@latest"), "PACKAGE", "@latest is not supported: packages must be pinned to an exact semantic version or commit. Use plugin_versions with an explicit repository to inspect available versions.");
|
|
281
287
|
const m = /^([\w.-]+\/[\w.-]+)\/(.+\.ya?ml)@(v1|(?:0|[1-9]\d*)\.\d+\.\d+|[a-f0-9]{40})$/.exec(reference);
|
|
@@ -302,6 +308,18 @@ export function packageLock(root) {
|
|
|
302
308
|
};
|
|
303
309
|
}
|
|
304
310
|
export function resolvePackage(root, reference) {
|
|
311
|
+
if (/^[a-z][a-z0-9-]*@(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/.test(reference)) {
|
|
312
|
+
const [name, version] = reference.split("@");
|
|
313
|
+
const matches = Object.keys(packageLock(root).packages).filter((lockedReference) => {
|
|
314
|
+
const installed = resolvePackage(root, lockedReference);
|
|
315
|
+
const manifest = packageYaml(installed.file);
|
|
316
|
+
return manifest.id === name && manifest.version === version;
|
|
317
|
+
});
|
|
318
|
+
check(matches.length === 1, "PACKAGE", matches.length
|
|
319
|
+
? `Ambiguous installed package ${reference}; use an explicit reference`
|
|
320
|
+
: `Install ${reference} before building this project`);
|
|
321
|
+
return resolvePackage(root, matches[0]);
|
|
322
|
+
}
|
|
305
323
|
reference = canonicalPackageReference(reference);
|
|
306
324
|
const parsed = parseReference(reference), entry = packageLock(root).packages[reference];
|
|
307
325
|
check(entry &&
|
|
@@ -314,7 +332,7 @@ export function resolvePackage(root, reference) {
|
|
|
314
332
|
check(canonical(inventory(cache)) === canonical(Object.keys(entry.files).sort()), "PACKAGE", "Package file inventory changed");
|
|
315
333
|
for (const [file, hash] of Object.entries(entry.files))
|
|
316
334
|
check(digest(readFileSync(fence(cache, file))) === hash, "PACKAGE", `Package integrity failed: ${file}`);
|
|
317
|
-
return { file: fence(cache, entry.path), root: cache, entry };
|
|
335
|
+
return { reference, file: fence(cache, entry.path), root: cache, entry };
|
|
318
336
|
}
|
|
319
337
|
/** Derived information lives outside the integrity-checked source cache. */
|
|
320
338
|
export function savePluginInformation(root, reference) {
|
package/dist/core/planner.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export declare function inspectProject(root: string, environment?: string, optio
|
|
|
17
17
|
apiVersion: "ingestron.project/v1";
|
|
18
18
|
id: string;
|
|
19
19
|
description?: string | undefined;
|
|
20
|
+
packages: Record<string, {
|
|
21
|
+
source: string;
|
|
22
|
+
version: string;
|
|
23
|
+
}>;
|
|
20
24
|
defaults: {
|
|
21
25
|
provider?: string | undefined;
|
|
22
26
|
naming: {
|
package/dist/core/planner.js
CHANGED
|
@@ -6,6 +6,7 @@ import addFormats from "ajv-formats";
|
|
|
6
6
|
import { resolve, relative, dirname } from "node:path";
|
|
7
7
|
import { Configuration } from "./config.js";
|
|
8
8
|
import { projectSchema, flowSchema, stepSchema, } from "./schema.js";
|
|
9
|
+
import { projectPackages } from "./project-packages.js";
|
|
9
10
|
import { check, canonical, digest, isMap, merge, Problem } from "./errors.js";
|
|
10
11
|
import { executeProvider } from "../plugins/provider-renderer.js";
|
|
11
12
|
import { contractColumns } from "./contracts.js";
|
|
@@ -115,7 +116,7 @@ function provider(project, bindings, reader, selected) {
|
|
|
115
116
|
check(name, "PROVIDER", "Select a provider or set defaults.provider");
|
|
116
117
|
const configured = project.providers.configurations[name];
|
|
117
118
|
check(configured, "PROVIDER", `Unknown provider configuration ${name}`);
|
|
118
|
-
const pkg = project
|
|
119
|
+
const pkg = projectPackages(project)[configured.package];
|
|
119
120
|
check(pkg, "PROVIDER", `Unknown provider package ${configured.package}`);
|
|
120
121
|
let rendererCode;
|
|
121
122
|
let plannerCode;
|
|
@@ -283,7 +284,7 @@ export function planProject(root, environment = "dev", options = {}) {
|
|
|
283
284
|
const configuration = project.providers.configurations[flow.provider ?? project.defaults.provider ?? ""];
|
|
284
285
|
check(configuration, "PROVIDER", "Select a provider for the ingestion flow");
|
|
285
286
|
const selectedProvider = provider(project, profile.bindings, reader, flow.provider);
|
|
286
|
-
const providerSource = project
|
|
287
|
+
const providerSource = projectPackages(project)[configuration.package]?.source;
|
|
287
288
|
check(selectedProvider.plannerCode, "PROVIDER", "Ingestion requires a provider planner");
|
|
288
289
|
const preset = flow.ingestion.preset
|
|
289
290
|
? selectedProvider.packs[String(flow.ingestion.preset)]
|
|
@@ -4,7 +4,7 @@ import { dirname, relative, resolve } from "node:path";
|
|
|
4
4
|
import { validateProviderFiles } from "../plugins/generation.js";
|
|
5
5
|
import { inspectProject, planProject } from "./planner.js";
|
|
6
6
|
import { canonical, check, digest, isMap } from "./errors.js";
|
|
7
|
-
import {
|
|
7
|
+
import { configuredPackageReference, fence, packageYaml, providerPackageSchema, resolvePackage, } from "./packages.js";
|
|
8
8
|
import { checkProviderCompatibility } from "../plugins/compatibility.js";
|
|
9
9
|
import { prepareConnection } from "./connections.js";
|
|
10
10
|
import { runProviderCommand } from "./provider-commands.js";
|
|
@@ -12,6 +12,7 @@ import { deliveryExports } from "./delivery-exports.js";
|
|
|
12
12
|
import { renderProject, validateGeneratedFiles, writeOutput, } from "./generate.js";
|
|
13
13
|
import { compilerFingerprint } from "./fingerprint.js";
|
|
14
14
|
import { version } from "../version.js";
|
|
15
|
+
import { projectPackages } from "./project-packages.js";
|
|
15
16
|
export function buildProject(root, environment, args) {
|
|
16
17
|
const { project, flows, reader, profile } = inspectProject(root, environment);
|
|
17
18
|
check(!(args.provider && args.flow), "SELECT", "Choose provider or flow, not both");
|
|
@@ -116,9 +117,9 @@ export function buildProject(root, environment, args) {
|
|
|
116
117
|
const selected = flows.filter((f) => wanted.has(f.id) && owner(f) === configuration);
|
|
117
118
|
const config = project.providers.configurations[configuration];
|
|
118
119
|
check(config, "PROVIDER", `Unknown provider configuration ${configuration}`);
|
|
119
|
-
const pkg = project
|
|
120
|
+
const pkg = projectPackages(project)[config.package];
|
|
120
121
|
check(pkg, "PACKAGE", `Missing execution package ${config.package}`);
|
|
121
|
-
const reference =
|
|
122
|
+
const reference = configuredPackageReference(pkg);
|
|
122
123
|
const locked = pkg.source.startsWith(".")
|
|
123
124
|
? { file: reader.path(pkg.source), root, entry: undefined }
|
|
124
125
|
: resolvePackage(root, reference);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { check } from "./errors.js";
|
|
2
|
+
export function projectPackages(project) {
|
|
3
|
+
for (const name of Object.keys(project.packages))
|
|
4
|
+
check(!Object.hasOwn(project.providers.packages, name), "PACKAGE", `Package alias ${name} is declared twice`);
|
|
5
|
+
return { ...project.providers.packages, ...project.packages };
|
|
6
|
+
}
|
|
@@ -6,8 +6,9 @@ import { dirname, relative, resolve } from "node:path";
|
|
|
6
6
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
7
7
|
import { Configuration } from "./config.js";
|
|
8
8
|
import { projectSchema } from "./schema.js";
|
|
9
|
+
import { projectPackages } from "./project-packages.js";
|
|
9
10
|
import { canonical, check, digest } from "./errors.js";
|
|
10
|
-
import {
|
|
11
|
+
import { configuredPackageReference, fence, packageYaml, providerPackageSchema, resolvePackage, } from "./packages.js";
|
|
11
12
|
import { executeProvider } from "../plugins/provider-renderer.js";
|
|
12
13
|
import { checkProviderCompatibility } from "../plugins/compatibility.js";
|
|
13
14
|
// No references, regular expressions or schema code: validation itself must be bounded.
|
|
@@ -65,9 +66,9 @@ function selected(root, environment, configuration) {
|
|
|
65
66
|
check(project.environments[environment], "ENVIRONMENT", `Unknown environment ${environment}`);
|
|
66
67
|
const configured = project.providers.configurations[configuration];
|
|
67
68
|
check(configured, "PROVIDER", `Unknown provider configuration ${configuration}`);
|
|
68
|
-
const pkg = project
|
|
69
|
+
const pkg = projectPackages(project)[configured.package];
|
|
69
70
|
check(pkg && !pkg.source.startsWith("builtin:") && !pkg.source.startsWith("."), "PACKAGE", "Provider commands require an installed locked provider");
|
|
70
|
-
const reference =
|
|
71
|
+
const reference = configuredPackageReference(pkg);
|
|
71
72
|
const source = resolvePackage(reader.root, reference);
|
|
72
73
|
const manifest = providerPackageSchema.parse(packageYaml(source.file));
|
|
73
74
|
checkProviderCompatibility(manifest);
|
|
@@ -209,10 +210,10 @@ export function pluginCommands(root, environment) {
|
|
|
209
210
|
const bindings = [];
|
|
210
211
|
const owners = new Map();
|
|
211
212
|
for (const [configuration, binding] of Object.entries(project.providers.configurations)) {
|
|
212
|
-
const pkg = project
|
|
213
|
+
const pkg = projectPackages(project)[binding.package];
|
|
213
214
|
if (!pkg || pkg.source.startsWith("builtin:") || pkg.source.startsWith("."))
|
|
214
215
|
continue;
|
|
215
|
-
const reference =
|
|
216
|
+
const reference = configuredPackageReference(pkg);
|
|
216
217
|
const source = resolvePackage(reader.root, reference);
|
|
217
218
|
const manifest = providerPackageSchema.parse(packageYaml(source.file));
|
|
218
219
|
if (!manifest.commands)
|
package/dist/core/schema.d.ts
CHANGED
|
@@ -19,11 +19,15 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
19
19
|
apiVersion: z.ZodLiteral<"ingestron.project/v1">;
|
|
20
20
|
id: z.ZodString;
|
|
21
21
|
description: z.ZodOptional<z.ZodString>;
|
|
22
|
+
packages: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodObject<{
|
|
23
|
+
source: z.ZodString;
|
|
24
|
+
version: z.ZodString;
|
|
25
|
+
}, z.core.$strict>, unknown>>>;
|
|
22
26
|
providers: z.ZodObject<{
|
|
23
|
-
packages: z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodObject<{
|
|
27
|
+
packages: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodPreprocess<z.ZodObject<{
|
|
24
28
|
source: z.ZodString;
|
|
25
29
|
version: z.ZodString;
|
|
26
|
-
}, z.core.$strict>, unknown
|
|
30
|
+
}, z.core.$strict>, unknown>>>;
|
|
27
31
|
configurations: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
28
32
|
package: z.ZodString;
|
|
29
33
|
binding: z.ZodString;
|
package/dist/core/schema.js
CHANGED
|
@@ -30,9 +30,10 @@ export const projectSchema = z
|
|
|
30
30
|
apiVersion: z.literal("ingestron.project/v1"),
|
|
31
31
|
id,
|
|
32
32
|
description: z.string().optional(),
|
|
33
|
+
packages: z.record(id, packageReferenceSchema).default({}),
|
|
33
34
|
providers: z
|
|
34
35
|
.object({
|
|
35
|
-
packages: z.record(id, packageReferenceSchema),
|
|
36
|
+
packages: z.record(id, packageReferenceSchema).default({}),
|
|
36
37
|
configurations: z.record(id, providerSchema),
|
|
37
38
|
packs: z.record(id, packageReferenceSchema).default({}),
|
|
38
39
|
})
|
package/dist/core/workflows.js
CHANGED
|
@@ -148,6 +148,33 @@ function packageEditor(root) {
|
|
|
148
148
|
};
|
|
149
149
|
return { reader, project, finish };
|
|
150
150
|
}
|
|
151
|
+
function packageValue(raw, name) {
|
|
152
|
+
return raw.packages?.[name] ?? raw.providers?.packages?.[name];
|
|
153
|
+
}
|
|
154
|
+
function packagePath(raw, name) {
|
|
155
|
+
return raw.packages?.[name] ||
|
|
156
|
+
(raw.packages && !raw.providers?.packages?.[name])
|
|
157
|
+
? ["packages", name]
|
|
158
|
+
: ["providers", "packages", name];
|
|
159
|
+
}
|
|
160
|
+
function sameInstalledPackage(root, left, right) {
|
|
161
|
+
try {
|
|
162
|
+
const a = resolvePackage(root, left).entry;
|
|
163
|
+
const b = resolvePackage(root, right).entry;
|
|
164
|
+
return (a.repository === b.repository &&
|
|
165
|
+
a.path === b.path &&
|
|
166
|
+
a.commit === b.commit);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function preferredReference(root, raw, full, id, version) {
|
|
173
|
+
const short = `${id}@${version}`;
|
|
174
|
+
return raw.packages && sameInstalledPackage(root, short, full)
|
|
175
|
+
? short
|
|
176
|
+
: friendlyReference(full);
|
|
177
|
+
}
|
|
151
178
|
export function pluginConfigure(root, args) {
|
|
152
179
|
const reference = canonicalPackageReference(args.reference);
|
|
153
180
|
const sourceManifest = packageYaml(resolvePackage(root, reference).file);
|
|
@@ -156,41 +183,46 @@ export function pluginConfigure(root, args) {
|
|
|
156
183
|
const { project, finish } = packageEditor(root);
|
|
157
184
|
const name = identifier.parse(args.name ?? connector.id);
|
|
158
185
|
const at = reference.lastIndexOf("@");
|
|
159
|
-
const
|
|
186
|
+
const raw = project.toJS();
|
|
187
|
+
const friendly = preferredReference(root, raw, reference, connector.id, connector.version);
|
|
160
188
|
const value = {
|
|
161
189
|
source: friendly.slice(0, friendly.lastIndexOf("@")),
|
|
162
190
|
version: reference.slice(at + 1),
|
|
163
191
|
};
|
|
164
|
-
const previous =
|
|
192
|
+
const previous = packageValue(raw, name);
|
|
165
193
|
if (previous) {
|
|
166
|
-
const old = packageReferenceSchema.parse(
|
|
167
|
-
check(
|
|
168
|
-
(args.update &&
|
|
194
|
+
const old = packageReferenceSchema.parse(previous);
|
|
195
|
+
check(sameInstalledPackage(root, `${old.source}@${old.version}`, reference) ||
|
|
196
|
+
(args.update &&
|
|
197
|
+
(old.source === value.source ||
|
|
198
|
+
old.source ===
|
|
199
|
+
friendlyReference(reference).slice(0, -value.version.length - 1))), "CONFLICT", "Connector package key already exists; choose a different name");
|
|
169
200
|
}
|
|
170
|
-
project.setIn(
|
|
201
|
+
project.setIn(packagePath(raw, name), `${value.source}@${value.version}`);
|
|
171
202
|
return finish({ "project.yaml": project.toString() });
|
|
172
203
|
}
|
|
173
204
|
const { reader, project, finish } = packageEditor(root);
|
|
174
205
|
const raw = project.toJS(), selected = providerReference(root, args.reference);
|
|
206
|
+
const preferred = preferredReference(root, raw, canonicalPackageReference(args.reference), selected.manifest.id, selected.manifest.version);
|
|
175
207
|
const name = identifier.parse(args.name ?? selected.manifest.platform);
|
|
176
208
|
const configurations = raw.providers.configurations;
|
|
177
209
|
if (configurations[name]) {
|
|
178
|
-
const existing = packageReferenceSchema.parse(raw
|
|
210
|
+
const existing = packageReferenceSchema.parse(packageValue(raw, configurations[name].package));
|
|
179
211
|
check(args.update ||
|
|
180
|
-
(
|
|
181
|
-
existing.version === selected.version), "CONFLICT", `Provider configuration ${name} already exists; use provider_migrate or a different name`);
|
|
212
|
+
sameInstalledPackage(root, `${existing.source}@${existing.version}`, args.reference), "CONFLICT", `Provider configuration ${name} already exists; use provider_migrate or a different name`);
|
|
182
213
|
if (args.update) {
|
|
183
|
-
check(
|
|
184
|
-
|
|
214
|
+
check(existing.source === preferred.slice(0, preferred.lastIndexOf("@")) ||
|
|
215
|
+
friendlyReference(existing.source) === selected.source, "CONFLICT", "Use plugin migrate to change provider identity");
|
|
216
|
+
project.setIn(packagePath(raw, configurations[name].package), preferred);
|
|
185
217
|
return finish({ "project.yaml": project.toString() });
|
|
186
218
|
}
|
|
187
|
-
if (existing.source
|
|
188
|
-
project.setIn(
|
|
219
|
+
if (!sameInstalledPackage(root, `${existing.source}@${existing.version}`, args.reference)) {
|
|
220
|
+
project.setIn(packagePath(raw, configurations[name].package), preferred);
|
|
189
221
|
return finish({ "project.yaml": project.toString() });
|
|
190
222
|
}
|
|
191
223
|
return finish({});
|
|
192
224
|
}
|
|
193
|
-
check(!raw
|
|
225
|
+
check(!packageValue(raw, name), "CONFLICT", `Package key ${name} already exists`);
|
|
194
226
|
const environmentNames = Object.keys(raw.environments);
|
|
195
227
|
const files = providerAuthor(root, args.reference, {
|
|
196
228
|
operation: "initialise",
|
|
@@ -204,7 +236,7 @@ export function pluginConfigure(root, args) {
|
|
|
204
236
|
const skeleton = parseDocument(files["project.yaml"]).toJS();
|
|
205
237
|
const defaults = skeleton.providers.configurations[skeleton.defaults.provider];
|
|
206
238
|
check(defaults, "PROVIDER", "Provider did not supply its default configuration");
|
|
207
|
-
project.setIn(
|
|
239
|
+
project.setIn(packagePath(raw, name), preferred);
|
|
208
240
|
const bindingName = `${name}_${defaults.binding}`;
|
|
209
241
|
project.setIn(["providers", "configurations", name], {
|
|
210
242
|
...defaults,
|