effect-start 0.22.0 → 0.23.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/dist/BlobStore.d.ts +80 -0
- package/dist/BlobStore.js +19 -0
- package/dist/ChildProcess.d.ts +60 -0
- package/dist/ChildProcess.js +30 -0
- package/dist/Commander.d.ts +3 -6
- package/dist/Commander.js +6 -13
- package/dist/ContentNegotiation.d.ts +8 -9
- package/dist/ContentNegotiation.js +32 -37
- package/dist/Cookies.d.ts +47 -0
- package/dist/Cookies.js +273 -363
- package/dist/Development.d.ts +2 -2
- package/dist/Development.js +3 -4
- package/dist/Effectify.d.ts +1 -4
- package/dist/FilePathPattern.d.ts +3 -3
- package/dist/FileRouter.d.ts +5 -8
- package/dist/FileRouter.js +9 -10
- package/dist/FileRouterCodegen.d.ts +1 -1
- package/dist/FileRouterCodegen.js +33 -13
- package/dist/FileSystem.d.ts +158 -0
- package/dist/FileSystem.js +64 -125
- package/dist/Http.js +2 -6
- package/dist/PathPattern.d.ts +7 -7
- package/dist/PathPattern.js +1 -3
- package/dist/PlatformError.d.ts +24 -32
- package/dist/PlatformError.js +3 -21
- package/dist/PlatformRuntime.js +5 -10
- package/dist/Route.d.ts +14 -19
- package/dist/Route.js +8 -11
- package/dist/RouteBody.d.ts +6 -12
- package/dist/RouteBody.js +2 -2
- package/dist/RouteError.d.ts +98 -0
- package/dist/RouteError.js +55 -0
- package/dist/RouteHook.js +6 -11
- package/dist/RouteHttp.d.ts +3 -3
- package/dist/RouteHttp.js +27 -22
- package/dist/RouteMount.d.ts +16 -50
- package/dist/RouteMount.js +6 -20
- package/dist/RouteSchema.d.ts +22 -1
- package/dist/RouteSchema.js +33 -0
- package/dist/RouteSse.js +4 -10
- package/dist/RouteTree.d.ts +2 -1
- package/dist/RouteTree.js +17 -15
- package/dist/RouteTrie.d.ts +2 -2
- package/dist/RouteTrie.js +4 -9
- package/dist/SchemaExtra.d.ts +1 -1
- package/dist/Socket.d.ts +27 -0
- package/dist/Socket.js +20 -28
- package/dist/Sql.d.ts +34 -0
- package/dist/Sql.js +5 -0
- package/dist/SqlIntrospect.d.ts +91 -0
- package/dist/SqlIntrospect.js +466 -0
- package/dist/Start.d.ts +4 -6
- package/dist/Start.js +10 -2
- package/dist/StreamExtra.d.ts +1 -1
- package/dist/StreamExtra.js +9 -9
- package/dist/System.d.ts +7 -0
- package/dist/System.js +22 -0
- package/dist/TuplePathPattern.js +55 -50
- package/dist/Unique.js +7 -7
- package/dist/Values.d.ts +2 -1
- package/dist/Values.js +19 -13
- package/dist/bun/BunBlobStoreDisk.d.ts +6 -0
- package/dist/bun/BunBlobStoreDisk.js +116 -0
- package/dist/bun/BunBlobStoreS3.d.ts +11 -0
- package/dist/bun/BunBlobStoreS3.js +89 -0
- package/dist/bun/BunBlobWatcherDisk.d.ts +6 -0
- package/dist/bun/BunBlobWatcherDisk.js +60 -0
- package/dist/bun/BunBlobWatcherQueue.d.ts +6 -0
- package/dist/bun/BunBlobWatcherQueue.js +17 -0
- package/dist/bun/BunBundle.d.ts +5 -6
- package/dist/bun/BunBundle.js +7 -15
- package/dist/bun/BunChildProcessSpawner.d.ts +3 -0
- package/dist/bun/BunChildProcessSpawner.js +103 -0
- package/dist/bun/BunImportTrackerPlugin.d.ts +1 -1
- package/dist/bun/BunImportTrackerPlugin.js +3 -5
- package/dist/bun/BunRoute.d.ts +3 -2
- package/dist/bun/BunRoute.js +5 -7
- package/dist/bun/BunRuntime.js +1 -1
- package/dist/bun/BunServer.d.ts +11 -4
- package/dist/bun/BunServer.js +35 -11
- package/dist/bun/BunSql.d.ts +4 -0
- package/dist/bun/BunSql.js +81 -0
- package/dist/bun/_BunEnhancedResolve.d.ts +3 -3
- package/dist/bun/_BunEnhancedResolve.js +2 -4
- package/dist/bun/index.d.ts +1 -0
- package/dist/bun/index.js +1 -0
- package/dist/bundler/Bundle.d.ts +2 -1
- package/dist/bundler/Bundle.js +1 -1
- package/dist/bundler/BundleFiles.d.ts +5 -5
- package/dist/bundler/BundleFiles.js +10 -8
- package/dist/bundler/BundleRoute.d.ts +27 -0
- package/dist/bundler/BundleRoute.js +51 -0
- package/dist/client/ScrollState.js +2 -6
- package/dist/client/index.js +6 -8
- package/dist/console/Console.d.ts +6 -0
- package/dist/console/Console.js +26 -0
- package/dist/console/ConsoleErrors.d.ts +3 -0
- package/dist/console/ConsoleErrors.js +200 -0
- package/dist/console/ConsoleLogger.d.ts +3 -0
- package/dist/console/ConsoleLogger.js +47 -0
- package/dist/console/ConsoleMetrics.d.ts +3 -0
- package/dist/console/ConsoleMetrics.js +61 -0
- package/dist/console/ConsoleProcess.d.ts +3 -0
- package/dist/console/ConsoleProcess.js +49 -0
- package/dist/console/ConsoleStore.d.ts +144 -0
- package/dist/console/ConsoleStore.js +61 -0
- package/dist/console/ConsoleTracer.d.ts +3 -0
- package/dist/console/ConsoleTracer.js +94 -0
- package/dist/console/Simulation.d.ts +2 -0
- package/dist/console/Simulation.js +633 -0
- package/dist/console/index.d.ts +3 -0
- package/dist/console/index.js +3 -0
- package/dist/console/routes/errors/route.d.ts +10 -0
- package/dist/console/routes/errors/route.js +47 -0
- package/dist/console/routes/fiberDetail.d.ts +16 -0
- package/dist/console/routes/fiberDetail.js +38 -0
- package/dist/console/routes/fibers/route.d.ts +10 -0
- package/dist/console/routes/fibers/route.js +19 -0
- package/dist/console/routes/git/route.d.ts +11 -0
- package/dist/console/routes/git/route.js +33 -0
- package/dist/console/routes/layout.d.ts +9 -0
- package/dist/console/routes/layout.js +3 -0
- package/dist/console/routes/logs/route.d.ts +10 -0
- package/dist/console/routes/logs/route.js +32 -0
- package/dist/console/routes/metrics/route.d.ts +10 -0
- package/dist/console/routes/metrics/route.js +17 -0
- package/dist/console/routes/route.d.ts +6 -0
- package/dist/console/routes/route.js +5 -0
- package/dist/console/routes/routes/route.d.ts +6 -0
- package/dist/console/routes/routes/route.js +20 -0
- package/dist/console/routes/services/route.d.ts +6 -0
- package/dist/console/routes/services/route.js +12 -0
- package/dist/console/routes/system/route.d.ts +10 -0
- package/dist/console/routes/system/route.js +18 -0
- package/dist/console/routes/traceDetail.d.ts +16 -0
- package/dist/console/routes/traceDetail.js +14 -0
- package/dist/console/routes/traces/route.d.ts +10 -0
- package/dist/console/routes/traces/route.js +39 -0
- package/dist/console/routes/tree.d.ts +153 -0
- package/dist/console/routes/tree.js +29 -0
- package/dist/console/ui/Errors.d.ts +4 -0
- package/dist/console/ui/Errors.js +15 -0
- package/dist/console/ui/Fibers.d.ts +24 -0
- package/dist/console/ui/Fibers.js +121 -0
- package/dist/console/ui/Git.d.ts +20 -0
- package/dist/console/ui/Git.js +95 -0
- package/dist/console/ui/Logs.d.ts +4 -0
- package/dist/console/ui/Logs.js +25 -0
- package/dist/console/ui/Metrics.d.ts +4 -0
- package/dist/console/ui/Metrics.js +26 -0
- package/dist/console/ui/Routes.d.ts +8 -0
- package/dist/console/ui/Routes.js +70 -0
- package/dist/console/ui/Services.d.ts +10 -0
- package/dist/console/ui/Services.js +246 -0
- package/dist/console/ui/Shell.d.ts +10 -0
- package/dist/console/ui/Shell.js +7 -0
- package/dist/console/ui/System.d.ts +4 -0
- package/dist/console/ui/System.js +35 -0
- package/dist/console/ui/Traces.d.ts +12 -0
- package/dist/console/ui/Traces.js +179 -0
- package/dist/datastar/actions/fetch.d.ts +1 -1
- package/dist/datastar/actions/fetch.js +10 -18
- package/dist/datastar/actions/peek.js +1 -2
- package/dist/datastar/actions/setAll.js +1 -2
- package/dist/datastar/actions/toggleAll.js +1 -2
- package/dist/datastar/attributes/attr.js +1 -2
- package/dist/datastar/attributes/bind.js +10 -18
- package/dist/datastar/attributes/class.js +2 -5
- package/dist/datastar/attributes/computed.js +2 -3
- package/dist/datastar/attributes/effect.js +1 -2
- package/dist/datastar/attributes/indicator.js +2 -4
- package/dist/datastar/attributes/init.js +2 -3
- package/dist/datastar/attributes/jsonSignals.js +1 -2
- package/dist/datastar/attributes/on.js +41 -22
- package/dist/datastar/attributes/onIntersect.js +2 -3
- package/dist/datastar/attributes/onInterval.js +2 -3
- package/dist/datastar/attributes/onSignalPatch.js +2 -4
- package/dist/datastar/attributes/ref.js +1 -2
- package/dist/datastar/attributes/show.js +1 -2
- package/dist/datastar/attributes/signals.js +1 -2
- package/dist/datastar/attributes/style.js +6 -12
- package/dist/datastar/attributes/text.js +1 -2
- package/dist/datastar/engine.d.ts +13 -7
- package/dist/datastar/engine.js +76 -48
- package/dist/datastar/happydom.d.ts +1 -0
- package/dist/datastar/happydom.js +8 -0
- package/dist/datastar/index.d.ts +1 -1
- package/dist/datastar/index.js +1 -1
- package/dist/datastar/utils.js +4 -7
- package/dist/datastar/watchers/patchElements.js +24 -45
- package/dist/datastar/watchers/patchSignals.js +1 -2
- package/dist/experimental/EncryptedCookies.d.ts +2 -5
- package/dist/experimental/EncryptedCookies.js +17 -48
- package/dist/experimental/index.d.ts +0 -1
- package/dist/experimental/index.js +0 -1
- package/dist/hyper/Hyper.d.ts +2 -9
- package/dist/hyper/Hyper.js +1 -12
- package/dist/hyper/HyperHtml.d.ts +1 -1
- package/dist/hyper/HyperHtml.js +18 -12
- package/dist/hyper/HyperHtml.test.d.ts +1 -0
- package/dist/hyper/HyperHtml.test.js +197 -0
- package/dist/hyper/HyperRoute.test.js +14 -3
- package/dist/hyper/html.d.ts +11 -0
- package/dist/hyper/html.js +30 -0
- package/dist/hyper/index.d.ts +2 -0
- package/dist/hyper/index.js +1 -0
- package/dist/hyper/jsx-runtime.d.ts +1 -1
- package/dist/hyper/jsx-runtime.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lint/plugin.d.ts +86 -0
- package/dist/lint/plugin.js +341 -0
- package/dist/node/NodeFileSystem.d.ts +2 -2
- package/dist/node/NodeFileSystem.js +4 -14
- package/dist/sql/bun/index.d.ts +3 -0
- package/dist/sql/bun/index.js +75 -0
- package/dist/sql/mssql/docker.d.ts +2 -0
- package/dist/sql/mssql/docker.js +67 -0
- package/dist/sql/mssql/index.d.ts +21 -0
- package/dist/sql/mssql/index.js +113 -0
- package/dist/testing/TestLogger.js +4 -1
- package/dist/testing/index.d.ts +0 -1
- package/dist/testing/index.js +0 -1
- package/dist/testing/utils.d.ts +3 -3
- package/dist/testing/utils.js +4 -4
- package/dist/x/cloudflare/CloudflareTunnel.d.ts +2 -5
- package/dist/x/cloudflare/CloudflareTunnel.js +14 -27
- package/dist/x/datastar/Datastar.d.ts +1 -1
- package/dist/x/datastar/Datastar.js +13 -12
- package/dist/x/datastar/index.d.ts +1 -2
- package/dist/x/datastar/index.js +1 -2
- package/dist/x/tailscale/TailscaleTunnel.d.ts +15 -0
- package/dist/x/tailscale/TailscaleTunnel.js +68 -0
- package/dist/x/tailscale/index.d.ts +1 -0
- package/dist/x/tailscale/index.js +1 -0
- package/dist/x/tailwind/TailwindPlugin.js +19 -19
- package/dist/x/tailwind/compile.d.ts +2 -2
- package/dist/x/tailwind/compile.js +2 -4
- package/package.json +22 -10
- package/src/ChildProcess.ts +145 -0
- package/src/PlatformError.ts +27 -50
- package/src/Route.ts +2 -2
- package/src/RouteError.ts +76 -0
- package/src/RouteHttp.ts +13 -5
- package/src/RouteSchema.ts +96 -1
- package/src/RouteTree.ts +12 -0
- package/src/Sql.ts +51 -0
- package/src/SqlIntrospect.ts +620 -0
- package/src/Start.ts +15 -3
- package/src/System.ts +43 -0
- package/src/Values.ts +7 -0
- package/src/bun/BunChildProcessSpawner.ts +143 -0
- package/src/bun/BunRoute.ts +5 -2
- package/src/bun/BunServer.ts +22 -1
- package/src/bun/index.ts +1 -0
- package/src/bundler/BundleRoute.ts +66 -0
- package/src/console/Console.ts +42 -0
- package/src/console/ConsoleErrors.ts +213 -0
- package/src/console/ConsoleLogger.ts +56 -0
- package/src/console/ConsoleMetrics.ts +72 -0
- package/src/console/ConsoleProcess.ts +59 -0
- package/src/console/ConsoleStore.ts +187 -0
- package/src/console/ConsoleTracer.ts +107 -0
- package/src/console/Simulation.ts +814 -0
- package/src/console/console.html +340 -0
- package/src/console/index.ts +3 -0
- package/src/console/routes/errors/route.tsx +97 -0
- package/src/console/routes/fiberDetail.tsx +54 -0
- package/src/console/routes/fibers/route.tsx +45 -0
- package/src/console/routes/git/route.tsx +64 -0
- package/src/console/routes/layout.tsx +4 -0
- package/src/console/routes/logs/route.tsx +77 -0
- package/src/console/routes/metrics/route.tsx +36 -0
- package/src/console/routes/route.tsx +8 -0
- package/src/console/routes/routes/route.tsx +30 -0
- package/src/console/routes/services/route.tsx +21 -0
- package/src/console/routes/system/route.tsx +43 -0
- package/src/console/routes/traceDetail.tsx +22 -0
- package/src/console/routes/traces/route.tsx +81 -0
- package/src/console/routes/tree.ts +30 -0
- package/src/console/ui/Errors.tsx +76 -0
- package/src/console/ui/Fibers.tsx +321 -0
- package/src/console/ui/Git.tsx +182 -0
- package/src/console/ui/Logs.tsx +46 -0
- package/src/console/ui/Metrics.tsx +78 -0
- package/src/console/ui/Routes.tsx +125 -0
- package/src/console/ui/Services.tsx +273 -0
- package/src/console/ui/Shell.tsx +62 -0
- package/src/console/ui/System.tsx +131 -0
- package/src/console/ui/Traces.tsx +426 -0
- package/src/datastar/README.md +6 -1
- package/src/datastar/actions/fetch.ts +0 -1
- package/src/datastar/attributes/on.ts +40 -20
- package/src/datastar/engine.ts +51 -0
- package/src/datastar/jsx.d.ts +79 -0
- package/src/hyper/Hyper.ts +1 -16
- package/src/hyper/HyperHtml.ts +6 -4
- package/src/hyper/HyperRoute.ts +2 -1
- package/src/hyper/html.ts +47 -0
- package/src/hyper/index.ts +2 -0
- package/src/hyper/jsx.d.ts +5 -3
- package/src/index.ts +1 -0
- package/src/lint/plugin.js +129 -0
- package/src/sql/bun/index.ts +147 -0
- package/src/sql/mssql/docker.ts +117 -0
- package/src/sql/mssql/index.ts +223 -0
- package/src/sql/mssql/mssql.d.ts +41 -0
- package/src/x/cloudflare/CloudflareTunnel.ts +8 -36
- package/src/x/tailscale/TailscaleTunnel.ts +113 -0
- package/src/x/tailscale/index.ts +1 -0
- package/src/x/datastar/Datastar.ts +0 -61
- package/src/x/datastar/index.ts +0 -2
- package/src/x/datastar/jsx-datastar.d.ts +0 -60
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @see https://oxc.rs/docs/guide/usage/linter/js-plugins.html#using-js-plugins
|
|
3
|
+
*/
|
|
4
|
+
const forceNamespace = new Set(["bun:test"]);
|
|
5
|
+
export default {
|
|
6
|
+
meta: {
|
|
7
|
+
name: "effect-start",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
},
|
|
10
|
+
rules: {
|
|
11
|
+
"prefer-namespace-import": {
|
|
12
|
+
meta: {
|
|
13
|
+
type: "suggestion",
|
|
14
|
+
docs: {
|
|
15
|
+
description: "Enforce namespace imports for modules with capitalized base names or specific forced modules",
|
|
16
|
+
},
|
|
17
|
+
fixable: "code",
|
|
18
|
+
hasSuggestions: true,
|
|
19
|
+
schema: [],
|
|
20
|
+
messages: {
|
|
21
|
+
preferNamespace: 'Use namespace import for module "{{source}}": import {{typePrefix}}* as {{baseName}} from "{{source}}"',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
create(context) {
|
|
25
|
+
return {
|
|
26
|
+
ImportDeclaration(node) {
|
|
27
|
+
const source = node.source.value;
|
|
28
|
+
if (typeof source !== "string")
|
|
29
|
+
return;
|
|
30
|
+
const baseName = getBaseName(source);
|
|
31
|
+
if (!baseName)
|
|
32
|
+
return;
|
|
33
|
+
const forced = forceNamespace.has(source);
|
|
34
|
+
if (!forced && !isCapitalized(baseName))
|
|
35
|
+
return;
|
|
36
|
+
// Already a namespace import (with or without type-only)
|
|
37
|
+
if (node.specifiers.length === 1 &&
|
|
38
|
+
node.specifiers[0].type === "ImportNamespaceSpecifier") {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Skip if there are no specifiers (side-effect import)
|
|
42
|
+
if (node.specifiers.length === 0)
|
|
43
|
+
return;
|
|
44
|
+
// Skip if it's only a default import (not applicable for forced modules)
|
|
45
|
+
if (!forced) {
|
|
46
|
+
const hasNamedImports = node.specifiers.some((s) => s.type === "ImportSpecifier");
|
|
47
|
+
if (!hasNamedImports)
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const typePrefix = node.importKind === "type" ? "type " : "";
|
|
51
|
+
context.report({
|
|
52
|
+
node,
|
|
53
|
+
messageId: "preferNamespace",
|
|
54
|
+
data: { source, baseName, typePrefix },
|
|
55
|
+
fix(fixer) {
|
|
56
|
+
return fixer.replaceText(node, `import ${typePrefix}* as ${baseName} from "${source}"`);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
"test-space-around": {
|
|
64
|
+
meta: {
|
|
65
|
+
type: "layout",
|
|
66
|
+
docs: {
|
|
67
|
+
description: "Enforce blank lines around test calls (test.describe, test.it, etc.)",
|
|
68
|
+
},
|
|
69
|
+
fixable: "whitespace",
|
|
70
|
+
schema: [],
|
|
71
|
+
messages: {
|
|
72
|
+
requireBlankBefore: "Test call should be preceded by a blank line",
|
|
73
|
+
requireBlankAfter: "Test call should be followed by a blank line",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
create(context) {
|
|
77
|
+
const filename = context.filename || context.getFilename();
|
|
78
|
+
if (!filename.endsWith(".test.ts") && !filename.endsWith(".test.tsx")) {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
function isTestCall(node) {
|
|
82
|
+
return (node &&
|
|
83
|
+
node.type === "ExpressionStatement" &&
|
|
84
|
+
node.expression.type === "CallExpression" &&
|
|
85
|
+
node.expression.callee.type === "MemberExpression" &&
|
|
86
|
+
node.expression.callee.object.type === "Identifier" &&
|
|
87
|
+
node.expression.callee.object.name === "test");
|
|
88
|
+
}
|
|
89
|
+
function checkBlankLines(siblings) {
|
|
90
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
91
|
+
for (let i = 0; i < siblings.length; i++) {
|
|
92
|
+
const node = siblings[i];
|
|
93
|
+
if (!isTestCall(node))
|
|
94
|
+
continue;
|
|
95
|
+
const prev = siblings[i - 1];
|
|
96
|
+
const next = siblings[i + 1];
|
|
97
|
+
if (prev) {
|
|
98
|
+
if (node.loc.start.line - prev.loc.end.line < 2) {
|
|
99
|
+
context.report({
|
|
100
|
+
node,
|
|
101
|
+
messageId: "requireBlankBefore",
|
|
102
|
+
fix(fixer) {
|
|
103
|
+
return fixer.insertTextAfter(sourceCode.getLastToken(prev), "\n");
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (next) {
|
|
109
|
+
if (next.loc.start.line - node.loc.end.line < 2) {
|
|
110
|
+
context.report({
|
|
111
|
+
node,
|
|
112
|
+
messageId: "requireBlankAfter",
|
|
113
|
+
fix(fixer) {
|
|
114
|
+
return fixer.insertTextAfter(sourceCode.getLastToken(node), "\n");
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
Program(node) {
|
|
123
|
+
checkBlankLines(node.body);
|
|
124
|
+
},
|
|
125
|
+
BlockStatement(node) {
|
|
126
|
+
checkBlankLines(node.body);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
// this doens't work reliably and may cause runtime errors
|
|
132
|
+
"export-default-before-functions": {
|
|
133
|
+
meta: {
|
|
134
|
+
type: "suggestion",
|
|
135
|
+
docs: {
|
|
136
|
+
description: "Enforce export default appears before any function declarations",
|
|
137
|
+
},
|
|
138
|
+
schema: [],
|
|
139
|
+
messages: {
|
|
140
|
+
defaultAfterFunction: "export default should appear before function declarations",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
create(context) {
|
|
144
|
+
return {
|
|
145
|
+
Program(node) {
|
|
146
|
+
let seenFunction = false;
|
|
147
|
+
for (const stmt of node.body) {
|
|
148
|
+
if (!seenFunction && isFunction(stmt)) {
|
|
149
|
+
seenFunction = true;
|
|
150
|
+
}
|
|
151
|
+
if (seenFunction && stmt.type === "ExportDefaultDeclaration") {
|
|
152
|
+
context.report({
|
|
153
|
+
node: stmt,
|
|
154
|
+
messageId: "defaultAfterFunction",
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
"test-assertion-newline": {
|
|
163
|
+
meta: {
|
|
164
|
+
type: "layout",
|
|
165
|
+
docs: {
|
|
166
|
+
description: "Enforce newlines between chained test assertion methods (test.expect().toBe())",
|
|
167
|
+
},
|
|
168
|
+
fixable: "whitespace",
|
|
169
|
+
schema: [],
|
|
170
|
+
messages: {
|
|
171
|
+
requireNewline: "Each chained method in a test assertion should be on its own line",
|
|
172
|
+
requireBlankBefore: "Test assertion should be preceded by an empty line (unless preceded by another assertion)",
|
|
173
|
+
requireBlankAfter: "Test assertion should be followed by an empty line (unless followed by another assertion)",
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
create(context) {
|
|
177
|
+
const filename = context.filename || context.getFilename();
|
|
178
|
+
if (!filename.endsWith(".test.ts") && !filename.endsWith(".test.tsx")) {
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Check if a call expression is rooted in test.expect or test.expectTypeOf
|
|
183
|
+
*/
|
|
184
|
+
function isTestAssertionChain(node) {
|
|
185
|
+
let current = node;
|
|
186
|
+
while (current) {
|
|
187
|
+
if (current.type === "CallExpression" && current.callee.type === "MemberExpression") {
|
|
188
|
+
const obj = current.callee.object;
|
|
189
|
+
// Check for test.expect(...) or test.expectTypeOf(...)
|
|
190
|
+
if (obj.type === "CallExpression" &&
|
|
191
|
+
obj.callee.type === "MemberExpression" &&
|
|
192
|
+
obj.callee.object.type === "Identifier" &&
|
|
193
|
+
obj.callee.object.name === "test" &&
|
|
194
|
+
obj.callee.property.type === "Identifier" &&
|
|
195
|
+
(obj.callee.property.name === "expect" ||
|
|
196
|
+
obj.callee.property.name === "expectTypeOf")) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
// Direct: test.expect(...) or test.expectTypeOf(...)
|
|
200
|
+
if (current.callee.object.type === "Identifier" &&
|
|
201
|
+
current.callee.object.name === "test" &&
|
|
202
|
+
current.callee.property.type === "Identifier" &&
|
|
203
|
+
(current.callee.property.name === "expect" ||
|
|
204
|
+
current.callee.property.name === "expectTypeOf")) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
// Walk up the chain
|
|
208
|
+
current = current.callee.object;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
// Handle non-call member access like .not
|
|
212
|
+
if (current.type === "MemberExpression") {
|
|
213
|
+
current = current.object;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Collect all member expressions in a chained call.
|
|
222
|
+
*/
|
|
223
|
+
function getChainedMembers(node) {
|
|
224
|
+
const members = [];
|
|
225
|
+
let current = node;
|
|
226
|
+
while (current.type === "CallExpression" && current.callee.type === "MemberExpression") {
|
|
227
|
+
members.push(current.callee);
|
|
228
|
+
current = current.callee.object;
|
|
229
|
+
}
|
|
230
|
+
return members;
|
|
231
|
+
}
|
|
232
|
+
function isAssertionStatement(stmt) {
|
|
233
|
+
return (stmt &&
|
|
234
|
+
stmt.type === "ExpressionStatement" &&
|
|
235
|
+
stmt.expression.type === "CallExpression" &&
|
|
236
|
+
isTestAssertionChain(stmt.expression));
|
|
237
|
+
}
|
|
238
|
+
function checkChainedNewlines(node) {
|
|
239
|
+
const members = getChainedMembers(node.expression);
|
|
240
|
+
for (const member of members) {
|
|
241
|
+
const objectEndLine = member.object.loc.end.line;
|
|
242
|
+
const propertyStartLine = member.property.loc.start.line;
|
|
243
|
+
if (objectEndLine === propertyStartLine) {
|
|
244
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
245
|
+
const dot = sourceCode.getTokenBefore(member.property);
|
|
246
|
+
if (dot && dot.value === ".") {
|
|
247
|
+
context.report({
|
|
248
|
+
node: member.property,
|
|
249
|
+
messageId: "requireNewline",
|
|
250
|
+
fix(fixer) {
|
|
251
|
+
const stmtStartCol = node.loc.start.column;
|
|
252
|
+
const indent = " ".repeat(stmtStartCol + 2);
|
|
253
|
+
return fixer.replaceTextRange([member.object.range[1], member.property.range[0]], "\n" + indent + ".");
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function checkBlankLines(siblings) {
|
|
261
|
+
const sourceCode = context.sourceCode || context.getSourceCode();
|
|
262
|
+
for (let i = 0; i < siblings.length; i++) {
|
|
263
|
+
const node = siblings[i];
|
|
264
|
+
if (!isAssertionStatement(node))
|
|
265
|
+
continue;
|
|
266
|
+
const prev = siblings[i - 1];
|
|
267
|
+
const next = siblings[i + 1];
|
|
268
|
+
if (prev && !isAssertionStatement(prev)) {
|
|
269
|
+
if (node.loc.start.line - prev.loc.end.line < 2) {
|
|
270
|
+
context.report({
|
|
271
|
+
node,
|
|
272
|
+
messageId: "requireBlankBefore",
|
|
273
|
+
fix(fixer) {
|
|
274
|
+
return fixer.insertTextAfter(sourceCode.getLastToken(prev), "\n");
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (next && !isAssertionStatement(next)) {
|
|
280
|
+
if (next.loc.start.line - node.loc.end.line < 2) {
|
|
281
|
+
context.report({
|
|
282
|
+
node,
|
|
283
|
+
messageId: "requireBlankAfter",
|
|
284
|
+
fix(fixer) {
|
|
285
|
+
return fixer.insertTextAfter(sourceCode.getLastToken(node), "\n");
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
ExpressionStatement(node) {
|
|
294
|
+
if (node.expression.type !== "CallExpression")
|
|
295
|
+
return;
|
|
296
|
+
if (!isTestAssertionChain(node.expression))
|
|
297
|
+
return;
|
|
298
|
+
checkChainedNewlines(node);
|
|
299
|
+
},
|
|
300
|
+
Program(node) {
|
|
301
|
+
checkBlankLines(node.body);
|
|
302
|
+
},
|
|
303
|
+
BlockStatement(node) {
|
|
304
|
+
checkBlankLines(node.body);
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
function getBaseName(source) {
|
|
312
|
+
// Handle node: and bun: protocols
|
|
313
|
+
if (source.startsWith("node:")) {
|
|
314
|
+
return source.slice(5);
|
|
315
|
+
}
|
|
316
|
+
if (source.startsWith("bun:")) {
|
|
317
|
+
return source.slice(4);
|
|
318
|
+
}
|
|
319
|
+
// Get last path segment
|
|
320
|
+
const segments = source.split("/");
|
|
321
|
+
let last = segments[segments.length - 1];
|
|
322
|
+
// Strip file extension (.ts, .tsx, .js, .jsx, .mjs, .cjs)
|
|
323
|
+
last = last.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
324
|
+
return last;
|
|
325
|
+
}
|
|
326
|
+
function isCapitalized(name) {
|
|
327
|
+
return name.length > 0 && name[0] >= "A" && name[0] <= "Z";
|
|
328
|
+
}
|
|
329
|
+
function isFunction(stmt) {
|
|
330
|
+
const decl = stmt.type === "ExportNamedDeclaration" && stmt.declaration ? stmt.declaration : stmt;
|
|
331
|
+
if (decl.type === "FunctionDeclaration")
|
|
332
|
+
return true;
|
|
333
|
+
if (decl.type === "VariableDeclaration" &&
|
|
334
|
+
decl.declarations.length > 0 &&
|
|
335
|
+
decl.declarations[0].init &&
|
|
336
|
+
(decl.declarations[0].init.type === "ArrowFunctionExpression" ||
|
|
337
|
+
decl.declarations[0].init.type === "FunctionExpression")) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as FileSystem from "@effect/platform/FileSystem";
|
|
2
1
|
import * as Layer from "effect/Layer";
|
|
2
|
+
import * as FileSystem from "../FileSystem.ts";
|
|
3
3
|
import * as NFS from "node:fs";
|
|
4
4
|
import * as PlatformError from "../PlatformError.ts";
|
|
5
5
|
export declare const layer: Layer.Layer<FileSystem.FileSystem, never, never>;
|
|
6
|
-
export {
|
|
6
|
+
export { PlatformError as Error };
|
|
7
7
|
export declare function handleErrnoException(module: PlatformError.SystemError["module"], method: string): (err: NodeJS.ErrnoException, [path]: [path: NFS.PathLike | number, ...args: Array<any>]) => PlatformError.PlatformError;
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Adapted from @effect/platform
|
|
3
|
-
*/
|
|
4
|
-
import * as FileSystem from "@effect/platform/FileSystem";
|
|
5
1
|
import * as Effect from "effect/Effect";
|
|
6
2
|
import * as Function from "effect/Function";
|
|
7
3
|
import * as Layer from "effect/Layer";
|
|
8
4
|
import * as Option from "effect/Option";
|
|
5
|
+
import * as FileSystem from "../FileSystem.js";
|
|
9
6
|
import * as Stream from "effect/Stream";
|
|
10
7
|
import * as NCrypto from "node:crypto";
|
|
11
8
|
import * as NFS from "node:fs";
|
|
@@ -66,9 +63,7 @@ const makeTempDirectoryFactory = (method) => {
|
|
|
66
63
|
const nodeMkdtemp = Effectify.effectify(NFS.mkdtemp, handleErrnoException("FileSystem", method), handleBadArgument(method));
|
|
67
64
|
return (options) => Effect.suspend(() => {
|
|
68
65
|
const prefix = options?.prefix ?? "";
|
|
69
|
-
const directory = typeof options?.directory === "string"
|
|
70
|
-
? NPath.join(options.directory, ".")
|
|
71
|
-
: NOS.tmpdir();
|
|
66
|
+
const directory = typeof options?.directory === "string" ? NPath.join(options.directory, ".") : NOS.tmpdir();
|
|
72
67
|
return nodeMkdtemp(prefix ? NPath.join(directory, prefix) : directory + "/");
|
|
73
68
|
});
|
|
74
69
|
};
|
|
@@ -374,13 +369,8 @@ const make = Effect.map(Effect.serviceOption(FileSystem.WatchBackend), (backend)
|
|
|
374
369
|
},
|
|
375
370
|
writeFile,
|
|
376
371
|
}));
|
|
377
|
-
export const layer = Layer.
|
|
378
|
-
|
|
379
|
-
const mod = yield* Effect.tryPromise(() => import("@effect/platform/FileSystem"));
|
|
380
|
-
return Layer.effect(mod.FileSystem, make);
|
|
381
|
-
})
|
|
382
|
-
.pipe(Effect.catchAll(() => Effect.die(new globalThis.Error("@effect/platform is not installed")))));
|
|
383
|
-
export { FileSystem, PlatformError as Error, };
|
|
372
|
+
export const layer = Layer.effect(FileSystem.FileSystem, make);
|
|
373
|
+
export { PlatformError as Error };
|
|
384
374
|
export function handleErrnoException(module, method) {
|
|
385
375
|
return function (err, [path]) {
|
|
386
376
|
let reason = "Unknown";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Exit from "effect/Exit";
|
|
3
|
+
import * as FiberRef from "effect/FiberRef";
|
|
4
|
+
import * as GlobalValue from "effect/GlobalValue";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Sql from "../../Sql.js";
|
|
8
|
+
const errorCode = (error) => {
|
|
9
|
+
const e = error;
|
|
10
|
+
if (typeof e?.errno === "string")
|
|
11
|
+
return e.errno;
|
|
12
|
+
return e?.code ?? "UNKNOWN";
|
|
13
|
+
};
|
|
14
|
+
const wrapError = (error) => new Sql.SqlError({
|
|
15
|
+
code: errorCode(error),
|
|
16
|
+
message: error instanceof Error ? error.message : String(error),
|
|
17
|
+
cause: error,
|
|
18
|
+
});
|
|
19
|
+
const wrap = (fn) => Effect.tryPromise({ try: () => Promise.resolve(fn()), catch: wrapError });
|
|
20
|
+
const makeValues = (obj, ...columns) => {
|
|
21
|
+
const items = Array.isArray(obj) ? obj : [obj];
|
|
22
|
+
const cols = columns.length > 0 ? columns : Object.keys(items[0]);
|
|
23
|
+
return { value: items, columns: cols };
|
|
24
|
+
};
|
|
25
|
+
const currentTransaction = GlobalValue.globalValue(Symbol.for("effect-start/sql/bun/currentTransaction"), () => FiberRef.unsafeMake(Option.none()));
|
|
26
|
+
const makeRun = (bunSql) => (fn) => Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => wrap(() => fn(Option.isSome(txOpt) ? txOpt.value.conn : bunSql)));
|
|
27
|
+
const makeWithTransaction = (bunSql) => (self) => Effect.uninterruptibleMask((restore) => Effect.flatMap(FiberRef.get(currentTransaction), (txOpt) => {
|
|
28
|
+
if (Option.isSome(txOpt)) {
|
|
29
|
+
const { conn, depth } = txOpt.value;
|
|
30
|
+
const name = `sp_${depth}`;
|
|
31
|
+
return Effect.gen(function* () {
|
|
32
|
+
yield* wrap(() => conn.unsafe(`SAVEPOINT ${name}`));
|
|
33
|
+
const exit = yield* Effect.exit(restore(Effect.locally(self, currentTransaction, Option.some({ conn, depth: depth + 1 }))));
|
|
34
|
+
if (Exit.isSuccess(exit)) {
|
|
35
|
+
yield* wrap(() => conn.unsafe(`RELEASE SAVEPOINT ${name}`));
|
|
36
|
+
return exit.value;
|
|
37
|
+
}
|
|
38
|
+
yield* wrap(() => conn.unsafe(`ROLLBACK TO SAVEPOINT ${name}`)).pipe(Effect.orDie);
|
|
39
|
+
return yield* exit;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const runTx = (conn) => Effect.gen(function* () {
|
|
43
|
+
yield* wrap(() => conn.unsafe("BEGIN"));
|
|
44
|
+
const exit = yield* Effect.exit(restore(Effect.locally(self, currentTransaction, Option.some({ conn, depth: 1 }))));
|
|
45
|
+
if (Exit.isSuccess(exit)) {
|
|
46
|
+
yield* wrap(() => conn.unsafe("COMMIT"));
|
|
47
|
+
return exit.value;
|
|
48
|
+
}
|
|
49
|
+
yield* wrap(() => conn.unsafe("ROLLBACK")).pipe(Effect.orDie);
|
|
50
|
+
return yield* exit;
|
|
51
|
+
});
|
|
52
|
+
return Effect.matchEffect(wrap(() => bunSql.reserve()), {
|
|
53
|
+
onFailure: () => runTx(bunSql),
|
|
54
|
+
onSuccess: (reserved) => Effect.ensuring(runTx(reserved), Effect.sync(() => reserved.release())),
|
|
55
|
+
});
|
|
56
|
+
}));
|
|
57
|
+
export const layer = (config) => Layer.scoped(Sql.SqlClient, Effect.acquireRelease(Effect.try({
|
|
58
|
+
try: () => {
|
|
59
|
+
const bunSql = new Bun.SQL(config);
|
|
60
|
+
const run = makeRun(bunSql);
|
|
61
|
+
const use = (fn) => Effect.tryPromise({ try: () => Promise.resolve(fn(bunSql)), catch: wrapError });
|
|
62
|
+
return Object.assign((strings, ...values) => run((conn) => conn(strings, ...values)), {
|
|
63
|
+
unsafe: (query, values) => run((conn) => conn.unsafe(query, values)),
|
|
64
|
+
values: makeValues,
|
|
65
|
+
withTransaction: makeWithTransaction(bunSql),
|
|
66
|
+
reserve: Effect.acquireRelease(wrap(() => bunSql.reserve()), (reserved) => Effect.sync(() => reserved.release())).pipe(Effect.map((reserved) => Object.assign((strings, ...values) => wrap(() => reserved(strings, ...values)), {
|
|
67
|
+
unsafe: (query, values) => wrap(() => reserved.unsafe(query, values)),
|
|
68
|
+
values: makeValues,
|
|
69
|
+
}))),
|
|
70
|
+
close: (options) => use((bunSql) => bunSql.close(options)),
|
|
71
|
+
use,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
catch: wrapError,
|
|
75
|
+
}), (client) => client.close().pipe(Effect.orDie)));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Stream from "effect/Stream";
|
|
3
|
+
import * as System from "../../System.js";
|
|
4
|
+
import * as BunChildProcessSpawner from "../../bun/BunChildProcessSpawner.js";
|
|
5
|
+
const PORT = 1433;
|
|
6
|
+
const PASSWORD = "TestPass123";
|
|
7
|
+
const CONTAINER = "effect-start-mssql";
|
|
8
|
+
const exec = (...args) => Effect.scoped(Effect.gen(function* () {
|
|
9
|
+
const handle = yield* System.spawn("docker", args, {
|
|
10
|
+
stdout: "ignore",
|
|
11
|
+
stderr: "inherit",
|
|
12
|
+
});
|
|
13
|
+
return yield* handle.exitCode;
|
|
14
|
+
}));
|
|
15
|
+
const execStdout = (...args) => Effect.scoped(Effect.gen(function* () {
|
|
16
|
+
const handle = yield* System.spawn("docker", args, {
|
|
17
|
+
stdout: "pipe",
|
|
18
|
+
stderr: "inherit",
|
|
19
|
+
});
|
|
20
|
+
const [stdout] = yield* Effect.all([handle.stdout.pipe(Stream.decodeText("utf-8"), Stream.mkString), handle.exitCode], { concurrency: 2 });
|
|
21
|
+
return stdout;
|
|
22
|
+
}));
|
|
23
|
+
const containerRunning = execStdout("ps", "-q", "-f", `name=${CONTAINER}`).pipe(Effect.map((stdout) => stdout.trim().length > 0));
|
|
24
|
+
const removeContainer = exec("rm", "-f", CONTAINER).pipe(Effect.ignore);
|
|
25
|
+
const loadMssql = () => import("mssql");
|
|
26
|
+
const canConnect = Effect.tryPromise({
|
|
27
|
+
try: async () => {
|
|
28
|
+
const { ConnectionPool } = await loadMssql();
|
|
29
|
+
const pool = new ConnectionPool({
|
|
30
|
+
server: "localhost",
|
|
31
|
+
user: "sa",
|
|
32
|
+
password: PASSWORD,
|
|
33
|
+
port: PORT,
|
|
34
|
+
options: { encrypt: true, trustServerCertificate: true, connectTimeout: 3000 },
|
|
35
|
+
});
|
|
36
|
+
await pool.connect();
|
|
37
|
+
await pool.close();
|
|
38
|
+
return true;
|
|
39
|
+
},
|
|
40
|
+
catch: () => false,
|
|
41
|
+
}).pipe(Effect.orElseSucceed(() => false));
|
|
42
|
+
const waitReady = Effect.gen(function* () {
|
|
43
|
+
const deadline = Date.now() + 60_000;
|
|
44
|
+
while (Date.now() < deadline) {
|
|
45
|
+
if (yield* canConnect)
|
|
46
|
+
return;
|
|
47
|
+
yield* Effect.sleep("2 seconds");
|
|
48
|
+
}
|
|
49
|
+
return yield* Effect.fail(new Error("Timed out waiting for MSSQL"));
|
|
50
|
+
});
|
|
51
|
+
const program = Effect.gen(function* () {
|
|
52
|
+
if (yield* containerRunning) {
|
|
53
|
+
yield* Effect.log("MSSQL container already running");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
yield* removeContainer;
|
|
57
|
+
yield* Effect.log("Starting MSSQL container...");
|
|
58
|
+
const code = yield* exec("run", "-d", "--name", CONTAINER, "-p", `${PORT}:1433`, "-e", "ACCEPT_EULA=Y", "-e", `MSSQL_SA_PASSWORD=${PASSWORD}`, "mcr.microsoft.com/azure-sql-edge");
|
|
59
|
+
if (code !== 0) {
|
|
60
|
+
return yield* Effect.fail(new Error(`docker run exited with code ${code}`));
|
|
61
|
+
}
|
|
62
|
+
yield* waitReady;
|
|
63
|
+
yield* Effect.log("MSSQL ready");
|
|
64
|
+
});
|
|
65
|
+
const run = (effect) => Effect.runPromise(Effect.provide(effect, BunChildProcessSpawner.layer));
|
|
66
|
+
export const start = () => run(program);
|
|
67
|
+
export const stop = () => run(removeContainer);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as Layer from "effect/Layer";
|
|
2
|
+
import * as Sql from "../../Sql.ts";
|
|
3
|
+
export interface MssqlConfig {
|
|
4
|
+
readonly server: string;
|
|
5
|
+
readonly database?: string;
|
|
6
|
+
readonly user?: string;
|
|
7
|
+
readonly password?: string;
|
|
8
|
+
readonly port?: number;
|
|
9
|
+
readonly pool?: {
|
|
10
|
+
readonly max?: number;
|
|
11
|
+
readonly min?: number;
|
|
12
|
+
readonly idleTimeoutMillis?: number;
|
|
13
|
+
};
|
|
14
|
+
readonly options?: {
|
|
15
|
+
readonly encrypt?: boolean;
|
|
16
|
+
readonly trustServerCertificate?: boolean;
|
|
17
|
+
readonly requestTimeout?: number;
|
|
18
|
+
readonly connectionTimeout?: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const layer: (config: MssqlConfig) => Layer.Layer<Sql.SqlClient, Sql.SqlError>;
|