snowpipe-streaming 1.4.0
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 +104 -0
- package/package.json +37 -0
- package/src/channel.js +241 -0
- package/src/channel_status.js +179 -0
- package/src/client.js +216 -0
- package/src/errors.js +110 -0
- package/src/index.d.ts +351 -0
- package/src/index.js +51 -0
- package/src/loader.js +167 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Snowflake Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
"use strict";
|
|
19
|
+
|
|
20
|
+
const { loadNativeAddon } = require("./loader.js");
|
|
21
|
+
const { StreamingIngestError } = require("./errors.js");
|
|
22
|
+
const { ChannelStatus } = require("./channel_status.js");
|
|
23
|
+
const { StreamingIngestClient, createClient: _createClient } = require("./client.js");
|
|
24
|
+
const { StreamingIngestChannel } = require("./channel.js");
|
|
25
|
+
|
|
26
|
+
// Load native addon and bootstrap the Rust runtime
|
|
27
|
+
const native = loadNativeAddon();
|
|
28
|
+
native.bootstrap(process.versions.node);
|
|
29
|
+
|
|
30
|
+
// Build error codes from Rust — single source of truth.
|
|
31
|
+
// Converts camelCase variant names to SCREAMING_SNAKE_CASE keys.
|
|
32
|
+
// e.g., "ConfigError" -> { CONFIG_ERROR: "ConfigError" }
|
|
33
|
+
function toScreamingSnake(s) {
|
|
34
|
+
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const errorCodes = native.getErrorCodes();
|
|
38
|
+
const StreamingIngestErrorCode = Object.freeze(
|
|
39
|
+
Object.fromEntries(errorCodes.map((code) => [toScreamingSnake(code), code])),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
module.exports = {
|
|
43
|
+
createClient: (options) => _createClient(native, options),
|
|
44
|
+
StreamingIngestClient,
|
|
45
|
+
StreamingIngestChannel,
|
|
46
|
+
StreamingIngestError,
|
|
47
|
+
StreamingIngestErrorCode,
|
|
48
|
+
ChannelStatus,
|
|
49
|
+
// E2E testing only - available when compiled with e2e_test feature
|
|
50
|
+
registerMockRoute: native.registerMockRoute,
|
|
51
|
+
};
|
package/src/loader.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Snowflake Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
"use strict";
|
|
19
|
+
|
|
20
|
+
const path = require("node:path");
|
|
21
|
+
const fs = require("node:fs");
|
|
22
|
+
|
|
23
|
+
const LOG_PREFIX = "[snowpipe-streaming]";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Platform package name mappings.
|
|
27
|
+
* Maps (os, arch, libc) to the npm package suffix.
|
|
28
|
+
*/
|
|
29
|
+
const PLATFORM_PACKAGES = {
|
|
30
|
+
"darwin-arm64": "darwin-arm64",
|
|
31
|
+
"linux-x64-glibc": "linux-x64-gnu",
|
|
32
|
+
"linux-x64-musl": "linux-x64-musl",
|
|
33
|
+
"linux-arm64-glibc": "linux-arm64-gnu",
|
|
34
|
+
"linux-arm64-musl": "linux-arm64-musl",
|
|
35
|
+
"win32-x64": "win32-x64-msvc",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Detect whether the Linux system uses musl or glibc.
|
|
40
|
+
* Uses multiple detection strategies for reliability.
|
|
41
|
+
* @returns {"glibc" | "musl"}
|
|
42
|
+
*/
|
|
43
|
+
function detectLibc() {
|
|
44
|
+
// Strategy 1: Check if /lib/ld-musl-* exists (Alpine, musl-based distros)
|
|
45
|
+
try {
|
|
46
|
+
const libDir = fs.readdirSync("/lib");
|
|
47
|
+
if (libDir.some((f) => f.startsWith("ld-musl-"))) {
|
|
48
|
+
console.log(`${LOG_PREFIX} Detected musl libc (found /lib/ld-musl-*)`);
|
|
49
|
+
return "musl";
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// /lib doesn't exist or not readable, continue to next strategy
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Strategy 2: Check ldd version output
|
|
56
|
+
try {
|
|
57
|
+
const { execSync } = require("node:child_process");
|
|
58
|
+
const lddOutput = execSync("ldd --version 2>&1", { encoding: "utf8" });
|
|
59
|
+
if (lddOutput.includes("musl")) {
|
|
60
|
+
console.log(`${LOG_PREFIX} Detected musl libc (ldd --version)`);
|
|
61
|
+
return "musl";
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// ldd not available or failed, continue
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Strategy 3: Check process.report (Node.js 12+)
|
|
68
|
+
if (process.report && typeof process.report.getReport === "function") {
|
|
69
|
+
const report = process.report.getReport();
|
|
70
|
+
if (report?.header?.glibcVersionRuntime) {
|
|
71
|
+
console.log(
|
|
72
|
+
`${LOG_PREFIX} Detected glibc ${report.header.glibcVersionRuntime} (process.report)`,
|
|
73
|
+
);
|
|
74
|
+
return "glibc";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Default to glibc (most common)
|
|
79
|
+
console.log(`${LOG_PREFIX} Defaulting to glibc (no musl indicators found)`);
|
|
80
|
+
return "glibc";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get the platform key for the current system.
|
|
85
|
+
* @returns {string} Platform key like "linux-x64-glibc" or "darwin-arm64"
|
|
86
|
+
*/
|
|
87
|
+
function getPlatformKey() {
|
|
88
|
+
const platform = process.platform;
|
|
89
|
+
const arch = process.arch;
|
|
90
|
+
|
|
91
|
+
if (platform === "linux") {
|
|
92
|
+
const libc = detectLibc();
|
|
93
|
+
const key = `${platform}-${arch}-${libc}`;
|
|
94
|
+
console.log(`${LOG_PREFIX} Platform: ${key} (os=${platform}, arch=${arch}, libc=${libc})`);
|
|
95
|
+
return key;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const key = `${platform}-${arch}`;
|
|
99
|
+
console.log(`${LOG_PREFIX} Platform: ${key} (os=${platform}, arch=${arch})`);
|
|
100
|
+
return key;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Load the native addon for the current platform.
|
|
105
|
+
* Supports three loading modes:
|
|
106
|
+
* 1. ADDON_PATH env var (Bazel development)
|
|
107
|
+
* 2. Platform-specific npm package (production via npm install)
|
|
108
|
+
* 3. Local .node file fallback (legacy/testing)
|
|
109
|
+
*
|
|
110
|
+
* @returns {object} The loaded native addon
|
|
111
|
+
*/
|
|
112
|
+
function loadNativeAddon() {
|
|
113
|
+
// Mode 1: Bazel development - ADDON_PATH points directly to the .node file
|
|
114
|
+
if (process.env.ADDON_PATH) {
|
|
115
|
+
const addonPath = path.resolve(process.env.ADDON_PATH);
|
|
116
|
+
console.log(`${LOG_PREFIX} Loading native addon from ADDON_PATH: ${addonPath}`);
|
|
117
|
+
const addon = require(addonPath);
|
|
118
|
+
console.log(`${LOG_PREFIX} Native addon loaded successfully from ADDON_PATH`);
|
|
119
|
+
return addon;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Mode 2: Production - load from platform-specific npm package
|
|
123
|
+
const platformKey = getPlatformKey();
|
|
124
|
+
const packageSuffix = PLATFORM_PACKAGES[platformKey];
|
|
125
|
+
|
|
126
|
+
if (packageSuffix) {
|
|
127
|
+
const packageName = `snowpipe-streaming-${packageSuffix}`;
|
|
128
|
+
console.log(`${LOG_PREFIX} Attempting to load platform package: ${packageName}`);
|
|
129
|
+
try {
|
|
130
|
+
const addon = require(packageName);
|
|
131
|
+
console.log(`${LOG_PREFIX} Native addon loaded successfully from ${packageName}`);
|
|
132
|
+
return addon;
|
|
133
|
+
} catch (err) {
|
|
134
|
+
// Package not installed - fall through to fallback
|
|
135
|
+
if (err.code !== "MODULE_NOT_FOUND") {
|
|
136
|
+
console.error(`${LOG_PREFIX} Failed to load ${packageName}: ${err.message}`);
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
console.log(`${LOG_PREFIX} Platform package ${packageName} not found, trying local fallback`);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
console.log(
|
|
143
|
+
`${LOG_PREFIX} No platform package mapping for ${platformKey}, trying local fallback`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Mode 3: Fallback - local .node file (for testing or manual installation)
|
|
148
|
+
const localAddon = path.resolve(__dirname, "..", "snowpipe_streaming.node");
|
|
149
|
+
console.log(`${LOG_PREFIX} Checking for local addon: ${localAddon}`);
|
|
150
|
+
if (fs.existsSync(localAddon)) {
|
|
151
|
+
console.log(`${LOG_PREFIX} Loading native addon from local file: ${localAddon}`);
|
|
152
|
+
const addon = require(localAddon);
|
|
153
|
+
console.log(`${LOG_PREFIX} Native addon loaded successfully from local file`);
|
|
154
|
+
return addon;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// No addon found - provide helpful error message
|
|
158
|
+
const supported = Object.keys(PLATFORM_PACKAGES).join(", ");
|
|
159
|
+
const errorMsg =
|
|
160
|
+
`Unsupported platform: ${platformKey}. ` +
|
|
161
|
+
`Supported platforms: ${supported}. ` +
|
|
162
|
+
`If you're on a supported platform, ensure the package installed correctly.`;
|
|
163
|
+
console.error(`${LOG_PREFIX} ${errorMsg}`);
|
|
164
|
+
throw new Error(errorMsg);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { loadNativeAddon };
|