alchemy 2.0.0-beta.18 → 2.0.0-beta.19
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/bin/alchemy.js +428 -80
- package/bin/alchemy.js.map +1 -1
- package/bin/alchemy.ts +2 -0
- package/bin/commands/_shared.ts +34 -0
- package/bin/commands/bootstrap.ts +10 -3
- package/bin/commands/deploy.ts +23 -3
- package/bin/commands/login.ts +18 -3
- package/bin/commands/logs.ts +11 -2
- package/bin/commands/profile.ts +11 -5
- package/bin/commands/state.ts +21 -13
- package/bin/commands/tail.ts +10 -2
- package/lib/Agent/lsp/client.d.ts +2 -2
- package/lib/Apply.d.ts.map +1 -1
- package/lib/Apply.js +41 -9
- package/lib/Apply.js.map +1 -1
- package/lib/Axiom/Annotation.d.ts +49 -0
- package/lib/Axiom/Annotation.d.ts.map +1 -0
- package/lib/Axiom/Annotation.js +74 -0
- package/lib/Axiom/Annotation.js.map +1 -0
- package/lib/Axiom/ApiToken.d.ts +62 -0
- package/lib/Axiom/ApiToken.d.ts.map +1 -0
- package/lib/Axiom/ApiToken.js +98 -0
- package/lib/Axiom/ApiToken.js.map +1 -0
- package/lib/Axiom/AuthProvider.d.ts +48 -0
- package/lib/Axiom/AuthProvider.d.ts.map +1 -0
- package/lib/Axiom/AuthProvider.js +177 -0
- package/lib/Axiom/AuthProvider.js.map +1 -0
- package/lib/Axiom/Chart.d.ts +72 -0
- package/lib/Axiom/Chart.d.ts.map +1 -0
- package/lib/Axiom/Chart.js +14 -0
- package/lib/Axiom/Chart.js.map +1 -0
- package/lib/Axiom/Credentials.d.ts +12 -0
- package/lib/Axiom/Credentials.d.ts.map +1 -0
- package/lib/Axiom/Credentials.js +34 -0
- package/lib/Axiom/Credentials.js.map +1 -0
- package/lib/Axiom/Dashboard.d.ts +124 -0
- package/lib/Axiom/Dashboard.d.ts.map +1 -0
- package/lib/Axiom/Dashboard.js +140 -0
- package/lib/Axiom/Dashboard.js.map +1 -0
- package/lib/Axiom/Dataset.d.ts +101 -0
- package/lib/Axiom/Dataset.d.ts.map +1 -0
- package/lib/Axiom/Dataset.js +183 -0
- package/lib/Axiom/Dataset.js.map +1 -0
- package/lib/Axiom/Monitor.d.ts +74 -0
- package/lib/Axiom/Monitor.d.ts.map +1 -0
- package/lib/Axiom/Monitor.js +103 -0
- package/lib/Axiom/Monitor.js.map +1 -0
- package/lib/Axiom/Notifier.d.ts +63 -0
- package/lib/Axiom/Notifier.d.ts.map +1 -0
- package/lib/Axiom/Notifier.js +83 -0
- package/lib/Axiom/Notifier.js.map +1 -0
- package/lib/Axiom/Providers.d.ts +15 -0
- package/lib/Axiom/Providers.d.ts.map +1 -0
- package/lib/Axiom/Providers.js +32 -0
- package/lib/Axiom/Providers.js.map +1 -0
- package/lib/Axiom/View.d.ts +55 -0
- package/lib/Axiom/View.d.ts.map +1 -0
- package/lib/Axiom/View.js +79 -0
- package/lib/Axiom/View.js.map +1 -0
- package/lib/Axiom/VirtualField.d.ts +42 -0
- package/lib/Axiom/VirtualField.d.ts.map +1 -0
- package/lib/Axiom/VirtualField.js +71 -0
- package/lib/Axiom/VirtualField.js.map +1 -0
- package/lib/Axiom/index.d.ts +13 -0
- package/lib/Axiom/index.d.ts.map +1 -0
- package/lib/Axiom/index.js +13 -0
- package/lib/Axiom/index.js.map +1 -0
- package/lib/Bundle/Bundle.d.ts +20 -2
- package/lib/Bundle/Bundle.d.ts.map +1 -1
- package/lib/Bundle/Bundle.js +18 -3
- package/lib/Bundle/Bundle.js.map +1 -1
- package/lib/Bundle/PurePlugin.d.ts +109 -0
- package/lib/Bundle/PurePlugin.d.ts.map +1 -0
- package/lib/Bundle/PurePlugin.js +469 -0
- package/lib/Bundle/PurePlugin.js.map +1 -0
- package/lib/Bundle/index.d.ts +1 -0
- package/lib/Bundle/index.d.ts.map +1 -1
- package/lib/Bundle/index.js +1 -0
- package/lib/Bundle/index.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +12 -0
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +19 -4
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Output.d.ts.map +1 -1
- package/lib/Output.js +1 -1
- package/lib/Output.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +10 -4
- package/lib/Plan.js.map +1 -1
- package/lib/Resource.d.ts +2 -2
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Telemetry/Attributes.d.ts +43 -0
- package/lib/Telemetry/Attributes.d.ts.map +1 -0
- package/lib/Telemetry/Attributes.js +144 -0
- package/lib/Telemetry/Attributes.js.map +1 -0
- package/lib/Telemetry/Layer.d.ts +14 -0
- package/lib/Telemetry/Layer.d.ts.map +1 -0
- package/lib/Telemetry/Layer.js +50 -0
- package/lib/Telemetry/Layer.js.map +1 -0
- package/lib/Telemetry/Metrics.d.ts +34 -0
- package/lib/Telemetry/Metrics.d.ts.map +1 -0
- package/lib/Telemetry/Metrics.js +57 -0
- package/lib/Telemetry/Metrics.js.map +1 -0
- package/package.json +12 -1
- package/src/Apply.ts +118 -9
- package/src/Axiom/Annotation.ts +95 -0
- package/src/Axiom/ApiToken.ts +125 -0
- package/src/Axiom/AuthProvider.ts +341 -0
- package/src/Axiom/Chart.ts +94 -0
- package/src/Axiom/Credentials.ts +70 -0
- package/src/Axiom/Dashboard.ts +192 -0
- package/src/Axiom/Dataset.ts +291 -0
- package/src/Axiom/Monitor.ts +122 -0
- package/src/Axiom/Notifier.ts +104 -0
- package/src/Axiom/Providers.ts +58 -0
- package/src/Axiom/View.ts +106 -0
- package/src/Axiom/VirtualField.ts +90 -0
- package/src/Axiom/index.ts +12 -0
- package/src/Bundle/Bundle.ts +39 -1
- package/src/Bundle/PurePlugin.ts +556 -0
- package/src/Bundle/index.ts +1 -0
- package/src/Cloudflare/Workers/Worker.ts +37 -6
- package/src/Output.ts +2 -1
- package/src/Plan.ts +13 -4
- package/src/Resource.ts +2 -2
- package/src/Telemetry/Attributes.ts +216 -0
- package/src/Telemetry/Layer.ts +65 -0
- package/src/Telemetry/Metrics.ts +101 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as Operations from "@distilled.cloud/axiom/Operations";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Provider from "../Provider.ts";
|
|
4
|
+
import { Resource } from "../Resource.ts";
|
|
5
|
+
import type { Providers } from "./Providers.ts";
|
|
6
|
+
|
|
7
|
+
export type NotifierProps = Operations.CreateNotifierInput;
|
|
8
|
+
|
|
9
|
+
export type Notifier = Resource<
|
|
10
|
+
"Axiom.Notifier",
|
|
11
|
+
NotifierProps,
|
|
12
|
+
Operations.CreateNotifierOutput & { id: string },
|
|
13
|
+
never,
|
|
14
|
+
Providers
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An Axiom notifier — an alert destination (Slack, email, PagerDuty,
|
|
19
|
+
* Opsgenie, Discord, Microsoft Teams, generic webhook, or a fully custom
|
|
20
|
+
* webhook with templated body/headers) that {@link Monitor monitors} target
|
|
21
|
+
* via `notifierIds`. Exactly one channel under `properties` should be set.
|
|
22
|
+
*
|
|
23
|
+
* @see https://axiom.co/docs/monitor-data/notifiers
|
|
24
|
+
*
|
|
25
|
+
* @section Creating a Notifier
|
|
26
|
+
* @example Slack incoming webhook
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const slack = yield* Axiom.Notifier("ops-slack", {
|
|
29
|
+
* name: "ops-channel",
|
|
30
|
+
* properties: {
|
|
31
|
+
* slack: { slackUrl: process.env.SLACK_WEBHOOK_URL! },
|
|
32
|
+
* },
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example Email distribution list
|
|
37
|
+
* ```typescript
|
|
38
|
+
* yield* Axiom.Notifier("ops-email", {
|
|
39
|
+
* name: "ops-team",
|
|
40
|
+
* properties: { email: { emails: ["sre@example.com", "oncall@example.com"] } },
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example PagerDuty integration
|
|
45
|
+
* ```typescript
|
|
46
|
+
* yield* Axiom.Notifier("pagerduty", {
|
|
47
|
+
* name: "primary-oncall",
|
|
48
|
+
* properties: {
|
|
49
|
+
* pagerduty: { routingKey: process.env.PAGERDUTY_ROUTING_KEY!, token: "" },
|
|
50
|
+
* },
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example Custom webhook with templated body
|
|
55
|
+
* ```typescript
|
|
56
|
+
* yield* Axiom.Notifier("incident-webhook", {
|
|
57
|
+
* name: "incident.io",
|
|
58
|
+
* properties: {
|
|
59
|
+
* customWebhook: {
|
|
60
|
+
* url: "https://api.incident.io/v2/alert_events",
|
|
61
|
+
* headers: { "Content-Type": "application/json" },
|
|
62
|
+
* secretHeaders: { Authorization: `Bearer ${process.env.INCIDENT_TOKEN}` },
|
|
63
|
+
* body: '{"title": "{{.Monitor.Name}}", "status": "firing"}',
|
|
64
|
+
* },
|
|
65
|
+
* },
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export const Notifier = Resource<Notifier>("Axiom.Notifier");
|
|
70
|
+
|
|
71
|
+
export const NotifierProvider = () =>
|
|
72
|
+
Provider.effect(
|
|
73
|
+
Notifier,
|
|
74
|
+
Effect.gen(function* () {
|
|
75
|
+
const create = yield* Operations.createNotifier;
|
|
76
|
+
const update = yield* Operations.updateNotifier;
|
|
77
|
+
const get = yield* Operations.getNotifier;
|
|
78
|
+
const del = yield* Operations.deleteNotifier;
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
stables: ["id"],
|
|
82
|
+
create: Effect.fn(function* ({ news }) {
|
|
83
|
+
const result = yield* create(news);
|
|
84
|
+
return { ...result, id: result.id ?? "" };
|
|
85
|
+
}),
|
|
86
|
+
update: Effect.fn(function* ({ news, output }) {
|
|
87
|
+
const result = yield* update({ ...news, id: output.id });
|
|
88
|
+
return { ...result, id: result.id ?? output.id };
|
|
89
|
+
}),
|
|
90
|
+
delete: Effect.fn(function* ({ output }) {
|
|
91
|
+
yield* del({ id: output.id }).pipe(
|
|
92
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
93
|
+
);
|
|
94
|
+
}),
|
|
95
|
+
read: Effect.fn(function* ({ output }) {
|
|
96
|
+
if (!output?.id) return undefined;
|
|
97
|
+
return yield* get({ id: output.id }).pipe(
|
|
98
|
+
Effect.map((current) => ({ ...current, id: current.id ?? output.id })),
|
|
99
|
+
Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
|
|
100
|
+
);
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
|
|
2
|
+
import * as Layer from "effect/Layer";
|
|
3
|
+
import * as Provider from "../Provider.ts";
|
|
4
|
+
import { Annotation, AnnotationProvider } from "./Annotation.ts";
|
|
5
|
+
import { ApiToken, ApiTokenProvider } from "./ApiToken.ts";
|
|
6
|
+
import { AxiomAuth } from "./AuthProvider.ts";
|
|
7
|
+
import * as Credentials from "./Credentials.ts";
|
|
8
|
+
import { Dashboard, DashboardProvider } from "./Dashboard.ts";
|
|
9
|
+
import { Dataset, DatasetProvider } from "./Dataset.ts";
|
|
10
|
+
import { Monitor, MonitorProvider } from "./Monitor.ts";
|
|
11
|
+
import { Notifier, NotifierProvider } from "./Notifier.ts";
|
|
12
|
+
import { View, ViewProvider } from "./View.ts";
|
|
13
|
+
import { VirtualField, VirtualFieldProvider } from "./VirtualField.ts";
|
|
14
|
+
|
|
15
|
+
export { Credentials } from "@distilled.cloud/axiom/Credentials";
|
|
16
|
+
|
|
17
|
+
export class Providers extends Provider.ProviderCollection<Providers>()(
|
|
18
|
+
"Axiom",
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
export type ProviderRequirements = Layer.Services<ReturnType<typeof providers>>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Axiom providers and credentials. Wires up Dataset, ApiToken, Notifier,
|
|
25
|
+
* Monitor, Dashboard, VirtualField, View and Annotation resources, and
|
|
26
|
+
* registers the Axiom AuthProvider so `alchemy login` can configure it.
|
|
27
|
+
*/
|
|
28
|
+
export const providers = () =>
|
|
29
|
+
Layer.effect(
|
|
30
|
+
Providers,
|
|
31
|
+
Provider.collection([
|
|
32
|
+
Annotation,
|
|
33
|
+
ApiToken,
|
|
34
|
+
Dashboard,
|
|
35
|
+
Dataset,
|
|
36
|
+
Monitor,
|
|
37
|
+
Notifier,
|
|
38
|
+
View,
|
|
39
|
+
VirtualField,
|
|
40
|
+
]),
|
|
41
|
+
).pipe(
|
|
42
|
+
Layer.provide(
|
|
43
|
+
Layer.mergeAll(
|
|
44
|
+
AnnotationProvider(),
|
|
45
|
+
ApiTokenProvider(),
|
|
46
|
+
DashboardProvider(),
|
|
47
|
+
DatasetProvider(),
|
|
48
|
+
MonitorProvider(),
|
|
49
|
+
NotifierProvider(),
|
|
50
|
+
ViewProvider(),
|
|
51
|
+
VirtualFieldProvider(),
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
Layer.provideMerge(Credentials.fromAuthProvider()),
|
|
55
|
+
Layer.provideMerge(FetchHttpClient.layer),
|
|
56
|
+
Layer.provideMerge(AxiomAuth),
|
|
57
|
+
Layer.orDie,
|
|
58
|
+
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as Operations from "@distilled.cloud/axiom/Operations";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { isResolved } from "../Diff.ts";
|
|
4
|
+
import * as Provider from "../Provider.ts";
|
|
5
|
+
import { Resource } from "../Resource.ts";
|
|
6
|
+
import type { Providers } from "./Providers.ts";
|
|
7
|
+
|
|
8
|
+
export type ViewProps = Operations.CreateViewInput;
|
|
9
|
+
|
|
10
|
+
export type View = Resource<
|
|
11
|
+
"Axiom.View",
|
|
12
|
+
ViewProps,
|
|
13
|
+
Operations.CreateViewOutput & {
|
|
14
|
+
/**
|
|
15
|
+
* Path identifier used by `updateView` / `getView` / `deleteView`.
|
|
16
|
+
* Currently derived from `name` because Axiom's view list/get responses
|
|
17
|
+
* don't expose a separate id field.
|
|
18
|
+
*/
|
|
19
|
+
id: string;
|
|
20
|
+
},
|
|
21
|
+
never,
|
|
22
|
+
Providers
|
|
23
|
+
>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An Axiom saved view — a named, shareable APL query. Useful for building
|
|
27
|
+
* starter dashboards, providing canned "open in Axiom" links from your app,
|
|
28
|
+
* or pinning common investigations the team revisits.
|
|
29
|
+
*
|
|
30
|
+
* The path identifier is `name`. Renaming a view triggers a replacement
|
|
31
|
+
* (the old one is deleted, a new one is created).
|
|
32
|
+
*
|
|
33
|
+
* @see https://axiom.co/docs/query-data/datasets — APL query reference
|
|
34
|
+
*
|
|
35
|
+
* @section Creating a View
|
|
36
|
+
* @example Recent errors across one dataset
|
|
37
|
+
* ```typescript
|
|
38
|
+
* yield* Axiom.View("recent-errors", {
|
|
39
|
+
* name: "recent-errors",
|
|
40
|
+
* description: "Last 100 5xx responses",
|
|
41
|
+
* datasets: ["my-app-traces"],
|
|
42
|
+
* aplQuery: `
|
|
43
|
+
* ['my-app-traces']
|
|
44
|
+
* | where status >= 500
|
|
45
|
+
* | order by _time desc
|
|
46
|
+
* | take 100
|
|
47
|
+
* `,
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Cross-dataset join (logs + traces by trace_id)
|
|
52
|
+
* ```typescript
|
|
53
|
+
* yield* Axiom.View("trace-with-logs", {
|
|
54
|
+
* name: "trace-with-logs",
|
|
55
|
+
* datasets: ["my-app-traces", "my-app-logs"],
|
|
56
|
+
* aplQuery: `
|
|
57
|
+
* ['my-app-traces']
|
|
58
|
+
* | where duration_ms > 1000
|
|
59
|
+
* | join kind=leftouter (['my-app-logs']) on trace_id
|
|
60
|
+
* `,
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export const View = Resource<View>("Axiom.View");
|
|
65
|
+
|
|
66
|
+
export const ViewProvider = () =>
|
|
67
|
+
Provider.effect(
|
|
68
|
+
View,
|
|
69
|
+
Effect.gen(function* () {
|
|
70
|
+
const create = yield* Operations.createView;
|
|
71
|
+
const update = yield* Operations.updateView;
|
|
72
|
+
const get = yield* Operations.getView;
|
|
73
|
+
const del = yield* Operations.deleteView;
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
stables: ["id"],
|
|
77
|
+
diff: Effect.fn(function* ({ news, output }) {
|
|
78
|
+
if (!isResolved(news)) return undefined;
|
|
79
|
+
if (output && news.name !== output.name) {
|
|
80
|
+
return { action: "replace" } as const;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}),
|
|
84
|
+
create: Effect.fn(function* ({ news }) {
|
|
85
|
+
const result = yield* create(news);
|
|
86
|
+
return { ...result, id: news.name };
|
|
87
|
+
}),
|
|
88
|
+
update: Effect.fn(function* ({ news, output }) {
|
|
89
|
+
const result = yield* update({ ...news, id: output.id });
|
|
90
|
+
return { ...result, id: output.id };
|
|
91
|
+
}),
|
|
92
|
+
delete: Effect.fn(function* ({ output }) {
|
|
93
|
+
yield* del({ id: output.id }).pipe(
|
|
94
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
95
|
+
);
|
|
96
|
+
}),
|
|
97
|
+
read: Effect.fn(function* ({ output }) {
|
|
98
|
+
if (!output?.id) return undefined;
|
|
99
|
+
return yield* get({ id: output.id }).pipe(
|
|
100
|
+
Effect.map((current) => ({ ...current, id: output.id })),
|
|
101
|
+
Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
|
|
102
|
+
);
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as Operations from "@distilled.cloud/axiom/Operations";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { isResolved } from "../Diff.ts";
|
|
4
|
+
import * as Provider from "../Provider.ts";
|
|
5
|
+
import { Resource } from "../Resource.ts";
|
|
6
|
+
import type { Providers } from "./Providers.ts";
|
|
7
|
+
|
|
8
|
+
export type VirtualFieldProps = Operations.CreateVirtualFieldInput;
|
|
9
|
+
|
|
10
|
+
export type VirtualField = Resource<
|
|
11
|
+
"Axiom.VirtualField",
|
|
12
|
+
VirtualFieldProps,
|
|
13
|
+
Operations.CreateVirtualFieldOutput,
|
|
14
|
+
never,
|
|
15
|
+
Providers
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* An Axiom virtual field — a saved APL expression that appears as a derived
|
|
20
|
+
* column on a dataset at query time. Use these to standardise common
|
|
21
|
+
* computations (status classes, latency buckets, parsed JSON paths) so
|
|
22
|
+
* dashboards and monitors don't have to redefine them.
|
|
23
|
+
*
|
|
24
|
+
* Bound to a single `dataset`; changing the dataset triggers a replacement.
|
|
25
|
+
*
|
|
26
|
+
* @see https://axiom.co/docs/query-data/virtual-fields
|
|
27
|
+
*
|
|
28
|
+
* @section Creating a Virtual Field
|
|
29
|
+
* @example HTTP status class (e.g. 200 → "2xx")
|
|
30
|
+
* ```typescript
|
|
31
|
+
* yield* Axiom.VirtualField("status-class", {
|
|
32
|
+
* dataset: "my-app-traces",
|
|
33
|
+
* name: "status_class",
|
|
34
|
+
* description: "HTTP response class bucket",
|
|
35
|
+
* expression: 'strcat(tostring(toint(status / 100)), "xx")',
|
|
36
|
+
* type: "string",
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example Latency bucket in seconds
|
|
41
|
+
* ```typescript
|
|
42
|
+
* yield* Axiom.VirtualField("latency-bucket", {
|
|
43
|
+
* dataset: "my-app-traces",
|
|
44
|
+
* name: "latency_bucket_s",
|
|
45
|
+
* expression: "bin(duration_ms / 1000.0, 0.5)",
|
|
46
|
+
* type: "number",
|
|
47
|
+
* unit: "s",
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export const VirtualField = Resource<VirtualField>("Axiom.VirtualField");
|
|
52
|
+
|
|
53
|
+
export const VirtualFieldProvider = () =>
|
|
54
|
+
Provider.effect(
|
|
55
|
+
VirtualField,
|
|
56
|
+
Effect.gen(function* () {
|
|
57
|
+
const create = yield* Operations.createVirtualField;
|
|
58
|
+
const update = yield* Operations.updateVirtualField;
|
|
59
|
+
const get = yield* Operations.getVirtualField;
|
|
60
|
+
const del = yield* Operations.deleteVirtualField;
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
stables: ["id"],
|
|
64
|
+
diff: Effect.fn(function* ({ news, output }) {
|
|
65
|
+
if (!isResolved(news)) return undefined;
|
|
66
|
+
if (output && news.dataset !== output.dataset) {
|
|
67
|
+
return { action: "replace" } as const;
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}),
|
|
71
|
+
create: Effect.fn(function* ({ news }) {
|
|
72
|
+
return yield* create(news);
|
|
73
|
+
}),
|
|
74
|
+
update: Effect.fn(function* ({ news, output }) {
|
|
75
|
+
return yield* update({ ...news, id: output.id });
|
|
76
|
+
}),
|
|
77
|
+
delete: Effect.fn(function* ({ output }) {
|
|
78
|
+
yield* del({ id: output.id }).pipe(
|
|
79
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
80
|
+
);
|
|
81
|
+
}),
|
|
82
|
+
read: Effect.fn(function* ({ output }) {
|
|
83
|
+
if (!output?.id) return undefined;
|
|
84
|
+
return yield* get({ id: output.id }).pipe(
|
|
85
|
+
Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
|
|
86
|
+
);
|
|
87
|
+
}),
|
|
88
|
+
};
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from "./Annotation.ts";
|
|
2
|
+
export * from "./ApiToken.ts";
|
|
3
|
+
export * from "./AuthProvider.ts";
|
|
4
|
+
export * from "./Chart.ts";
|
|
5
|
+
export * from "./Credentials.ts";
|
|
6
|
+
export * from "./Dashboard.ts";
|
|
7
|
+
export * from "./Dataset.ts";
|
|
8
|
+
export * from "./Monitor.ts";
|
|
9
|
+
export * from "./Notifier.ts";
|
|
10
|
+
export * from "./Providers.ts";
|
|
11
|
+
export * from "./View.ts";
|
|
12
|
+
export * from "./VirtualField.ts";
|
package/src/Bundle/Bundle.ts
CHANGED
|
@@ -7,6 +7,25 @@ import * as Stream from "effect/Stream";
|
|
|
7
7
|
import assert from "node:assert";
|
|
8
8
|
import * as rolldown from "rolldown";
|
|
9
9
|
import { sha256, sha256Object } from "../Util/sha256.ts";
|
|
10
|
+
import { purePlugin, type PurePluginOptions } from "./PurePlugin.ts";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extra options accepted by {@link build} / {@link watch} on top of the
|
|
14
|
+
* standard rolldown input/output options.
|
|
15
|
+
*/
|
|
16
|
+
export interface BundleExtraOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Configures the {@link purePlugin} which annotates top-level
|
|
19
|
+
* call/new expressions in matching packages with `/*#__PURE__*\/`
|
|
20
|
+
* so rolldown can tree-shake them.
|
|
21
|
+
*
|
|
22
|
+
* - `undefined` (default): plugin is enabled with default packages
|
|
23
|
+
* (`effect`, `@effect/*`).
|
|
24
|
+
* - `PurePluginOptions`: plugin is enabled with the provided options.
|
|
25
|
+
* - `false`: plugin is disabled.
|
|
26
|
+
*/
|
|
27
|
+
readonly pure?: PurePluginOptions | false;
|
|
28
|
+
}
|
|
10
29
|
|
|
11
30
|
export interface BundleOutput {
|
|
12
31
|
/**
|
|
@@ -40,11 +59,13 @@ export class BundleError extends Data.TaggedError("BundleError")<{
|
|
|
40
59
|
export const build = (
|
|
41
60
|
inputOptions: rolldown.InputOptions,
|
|
42
61
|
outputOptions?: rolldown.OutputOptions,
|
|
62
|
+
extra?: BundleExtraOptions,
|
|
43
63
|
): Effect.Effect<BundleOutput, BundleError> =>
|
|
44
64
|
Effect.tryPromise({
|
|
45
65
|
try: async () => {
|
|
46
66
|
const bundle = await rolldown.rolldown({
|
|
47
67
|
...inputOptions,
|
|
68
|
+
plugins: withPurePlugin(inputOptions.plugins, extra?.pure),
|
|
48
69
|
optimization: inputOptions.optimization ?? {
|
|
49
70
|
inlineConst: {
|
|
50
71
|
mode: "smart",
|
|
@@ -71,6 +92,7 @@ export const build = (
|
|
|
71
92
|
export const watch = (
|
|
72
93
|
inputOptions: rolldown.InputOptions,
|
|
73
94
|
outputOptions?: rolldown.OutputOptions,
|
|
95
|
+
extra?: BundleExtraOptions,
|
|
74
96
|
): Stream.Stream<Result.Result<BundleOutput, BundleError>> =>
|
|
75
97
|
Stream.callback<Result.Result<rolldown.OutputBundle, BundleError>>((queue) =>
|
|
76
98
|
Effect.acquireRelease(
|
|
@@ -78,7 +100,7 @@ export const watch = (
|
|
|
78
100
|
const watcher = rolldown.watch({
|
|
79
101
|
...inputOptions,
|
|
80
102
|
plugins: [
|
|
81
|
-
inputOptions.plugins,
|
|
103
|
+
withPurePlugin(inputOptions.plugins, extra?.pure),
|
|
82
104
|
// The watcher event listener does not receive the bundle output, so we grab it using a plugin.
|
|
83
105
|
{
|
|
84
106
|
name: "alchemy:watch-bundle",
|
|
@@ -179,6 +201,22 @@ export function bundleOutputFromRolldownOutputBundle(
|
|
|
179
201
|
).pipe(Effect.flatMap(bundleOutputFromFiles));
|
|
180
202
|
}
|
|
181
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Composes the user-provided plugin chain with the default
|
|
206
|
+
* {@link purePlugin} according to the `pure` option.
|
|
207
|
+
*
|
|
208
|
+
* The pure plugin is appended LAST so it sees module ids that have already
|
|
209
|
+
* been resolved into `node_modules/<pkg>/...` by upstream resolver plugins
|
|
210
|
+
* such as `@distilled.cloud/cloudflare-rolldown-plugin`.
|
|
211
|
+
*/
|
|
212
|
+
function withPurePlugin(
|
|
213
|
+
plugins: rolldown.RolldownPluginOption,
|
|
214
|
+
pure: PurePluginOptions | false | undefined,
|
|
215
|
+
): rolldown.RolldownPluginOption {
|
|
216
|
+
if (pure === false) return plugins;
|
|
217
|
+
return [plugins, purePlugin(pure ?? {})];
|
|
218
|
+
}
|
|
219
|
+
|
|
182
220
|
function bundleErrorFromUnknown(error: unknown): BundleError {
|
|
183
221
|
const message = error instanceof Error ? error.message : String(error);
|
|
184
222
|
return new BundleError({
|