@homeflare/alchemy 0.52.0 → 0.53.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.
Files changed (49) hide show
  1. package/dist/grafana/folder-permission.d.ts +76 -0
  2. package/dist/grafana/folder-permission.d.ts.map +1 -0
  3. package/dist/grafana/index.d.ts +3 -1
  4. package/dist/grafana/index.d.ts.map +1 -1
  5. package/dist/grafana/index.js +133 -46
  6. package/dist/grafana/index.js.map +7 -5
  7. package/dist/grafana/providers.d.ts +1 -1
  8. package/dist/grafana/providers.d.ts.map +1 -1
  9. package/dist/grafana/provisioned.d.ts +1 -1
  10. package/dist/grafana/provisioned.d.ts.map +1 -1
  11. package/dist/grafana/team.d.ts +64 -0
  12. package/dist/grafana/team.d.ts.map +1 -0
  13. package/dist/litellm/fake-marketplace-litellm.d.ts +33 -0
  14. package/dist/litellm/fake-marketplace-litellm.d.ts.map +1 -0
  15. package/dist/litellm/index.d.ts +1 -0
  16. package/dist/litellm/index.d.ts.map +1 -1
  17. package/dist/litellm/index.js +530 -329
  18. package/dist/litellm/index.js.map +7 -4
  19. package/dist/litellm/marketplace-form.d.ts +21 -0
  20. package/dist/litellm/marketplace-form.d.ts.map +1 -0
  21. package/dist/litellm/marketplace-operations.d.ts +27 -0
  22. package/dist/litellm/marketplace-operations.d.ts.map +1 -0
  23. package/dist/litellm/marketplace-plugin.d.ts +57 -0
  24. package/dist/litellm/marketplace-plugin.d.ts.map +1 -0
  25. package/dist/litellm/marketplace-types.d.ts +55 -0
  26. package/dist/litellm/marketplace-types.d.ts.map +1 -0
  27. package/dist/litellm/providers.d.ts +1 -1
  28. package/dist/litellm/providers.d.ts.map +1 -1
  29. package/docs/litellm-marketplace.md +59 -0
  30. package/docs/litellm.md +1 -0
  31. package/package.json +1 -1
  32. package/src/grafana/folder-permission.test.ts +107 -0
  33. package/src/grafana/folder-permission.ts +128 -0
  34. package/src/grafana/index.ts +10 -1
  35. package/src/grafana/providers.ts +4 -0
  36. package/src/grafana/provisioned.ts +1 -1
  37. package/src/grafana/team.test.ts +108 -0
  38. package/src/grafana/team.ts +105 -0
  39. package/src/litellm/fake-marketplace-litellm.test.ts +51 -0
  40. package/src/litellm/fake-marketplace-litellm.ts +134 -0
  41. package/src/litellm/index.ts +8 -0
  42. package/src/litellm/marketplace-form.ts +160 -0
  43. package/src/litellm/marketplace-operations.ts +76 -0
  44. package/src/litellm/marketplace-plugin-replace.test.ts +68 -0
  45. package/src/litellm/marketplace-plugin.test.ts +181 -0
  46. package/src/litellm/marketplace-plugin.ts +156 -0
  47. package/src/litellm/marketplace-types.ts +53 -0
  48. package/src/litellm/providers.ts +2 -0
  49. package/src/litellm/registry-exports.test.ts +6 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * `Grafana.FolderPermission` — ONE team's DIRECT permission on ONE folder.
3
+ *
4
+ * Walked against `@distilled.cloud/grafana` 0.2.1 (`@homeflare/distilled-grafana`):
5
+ * `getResourcePermissions` (`GET /access-control/folders/{uid}`) and `setResourcePermissionsForTeam`
6
+ * (`POST /access-control/folders/{uid}/teams/{teamId}`).
7
+ *
8
+ * ★ ADDITIVE BY CONSTRUCTION. The per-team endpoint touches only that team's managed entry; the
9
+ * folder's other entries (built-in roles, admin users, other teams, anything inherited from a parent
10
+ * folder) are never read into a write and never changed. The whole-list `setResourcePermissions`
11
+ * would replace them all — deliberately not used.
12
+ * ★ ONLY DIRECT ENTRIES COUNT. An entry inherited from a parent folder (`isInherited`) is not this
13
+ * resource's object: it can't be changed here, so it never satisfies a declaration either.
14
+ * ★ The team is named, not numbered. Team ids differ per instance, so `teamName` is resolved through
15
+ * `findTeamByName` on every read and write; a missing team fails loudly with
16
+ * `GrafanaTeamNotFoundError` (declare the `Grafana.Team` first) instead of folding to "absent".
17
+ * ★ delete = set the team's permission to "" (Grafana's documented way to remove a managed entry),
18
+ * idempotent: an already-absent entry is a no-op (S11).
19
+ */
20
+ import { Resource } from 'alchemy';
21
+ import * as Provider from 'alchemy/Provider';
22
+ import * as grafana from '@distilled.cloud/grafana';
23
+ import * as Effect from 'effect/Effect';
24
+ import { type GrafanaSpec } from './resource.ts';
25
+ export type FolderPermissionLevel = 'View' | 'Edit' | 'Admin';
26
+ export interface FolderPermissionProps {
27
+ folderUid: string;
28
+ teamName: string;
29
+ permission: FolderPermissionLevel;
30
+ }
31
+ export interface FolderPermissionAttributes {
32
+ folderUid: string;
33
+ teamId: number;
34
+ teamName: string;
35
+ permission: string;
36
+ }
37
+ export interface GrafanaFolderPermission extends Resource<'Grafana.FolderPermission', FolderPermissionProps, FolderPermissionAttributes, never> {
38
+ }
39
+ export declare const GrafanaFolderPermission: import("alchemy").ResourceClass<GrafanaFolderPermission>;
40
+ declare const GrafanaTeamNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
41
+ readonly _tag: "GrafanaTeamNotFoundError";
42
+ } & Readonly<A>;
43
+ export declare class GrafanaTeamNotFoundError extends GrafanaTeamNotFoundError_base<{
44
+ readonly message: string;
45
+ }> {
46
+ }
47
+ interface LivePermission {
48
+ readonly teamId: number;
49
+ readonly permission: string;
50
+ }
51
+ export declare const spec: GrafanaSpec<FolderPermissionProps, LivePermission, FolderPermissionAttributes, grafana.SearchTeamsError | grafana.GetResourcePermissionsError | grafana.SetResourcePermissionsForTeamError | GrafanaTeamNotFoundError>;
52
+ export declare const handlers: {
53
+ list: () => Effect.Effect<never[], never, never>;
54
+ read: ({ olds }: {
55
+ olds: FolderPermissionProps;
56
+ }) => Effect.Effect<FolderPermissionAttributes | undefined, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaTeamNotFoundError | import("effect/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
57
+ diff: ({ news, output }: {
58
+ news: import("alchemy").Input<FolderPermissionProps>;
59
+ output: FolderPermissionAttributes | undefined;
60
+ }) => Effect.Effect<{
61
+ readonly action: 'update';
62
+ } | {
63
+ readonly action: 'noop';
64
+ } | {
65
+ readonly action: 'replace';
66
+ } | undefined, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaTeamNotFoundError | import("effect/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
67
+ reconcile: ({ news }: {
68
+ news: FolderPermissionProps;
69
+ }) => Effect.Effect<FolderPermissionAttributes, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaTeamNotFoundError | import("effect/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
70
+ delete: ({ olds }: {
71
+ olds: FolderPermissionProps;
72
+ }) => Effect.Effect<void, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaTeamNotFoundError | import("effect/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
73
+ };
74
+ export declare const GrafanaFolderPermissionProvider: () => import("effect/Layer").Layer<Provider.Provider<GrafanaFolderPermission>, never, grafana.GrafanaOpContext>;
75
+ export {};
76
+ //# sourceMappingURL=folder-permission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folder-permission.d.ts","sourceRoot":"","sources":["../../src/grafana/folder-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAC;AAEpD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,eAAe,CAAC;AAGlE,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,QAAQ,CACvD,0BAA0B,EAC1B,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,CACN;CAAG;AAEJ,eAAO,MAAM,uBAAuB,0DAEnC,CAAC;;;;AAEF,qBAAa,wBAAyB,SAAQ,8BAA6C;IACzF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;CAAG;AAEL,UAAU,cAAc;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAuBD,eAAO,MAAM,IAAI,EAAE,WAAW,CAC5B,qBAAqB,EACrB,cAAc,EACd,0BAA0B,EACxB,OAAO,CAAC,gBAAgB,GACxB,OAAO,CAAC,2BAA2B,GACnC,OAAO,CAAC,kCAAkC,GAC1C,wBAAwB,CA6B3B,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAAwB,CAAC;AAE9C,eAAO,MAAM,+BAA+B,iHAIzC,CAAC"}
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * `Grafana.Datasource`, `Grafana.Folder`, `Grafana.Dashboard`, `Grafana.ContactPoint`,
10
10
  * `Grafana.MuteTiming`, `Grafana.MessageTemplate`, `Grafana.AlertRuleGroup` and
11
- * `Grafana.NotificationPolicy` all ship here — see docs/grafana.md, docs/grafana-folder-dashboard.md,
11
+ * `Grafana.NotificationPolicy`, `Grafana.Team` and `Grafana.FolderPermission` all ship here — see docs/grafana.md, docs/grafana-folder-dashboard.md,
12
12
  * docs/grafana-alerting.md, docs/grafana-alerting-rules.md and
13
13
  * docs/grafana-notification-policy.md for what shipped.
14
14
  */
@@ -17,6 +17,8 @@ export { type NotificationPolicyAttributes, type NotificationPolicyProps, type P
17
17
  export { type DatasourceAttributes, type DatasourceProps, GrafanaDatasource, GrafanaDatasourceProvider, } from './datasource.ts';
18
18
  export { type DashboardAttributes, type DashboardModel, type DashboardProps, GrafanaDashboard, GrafanaDashboardProvider, } from './dashboard.ts';
19
19
  export { type FolderAttributes, type FolderProps, GrafanaFolder, GrafanaFolderProvider, GrafanaFolderReparentError, } from './folder.ts';
20
+ export { type TeamAttributes, type TeamProps, GrafanaTeam, GrafanaTeamProvider } from './team.ts';
21
+ export { type FolderPermissionAttributes, type FolderPermissionLevel, type FolderPermissionProps, GrafanaFolderPermission, GrafanaFolderPermissionProvider, GrafanaTeamNotFoundError, } from './folder-permission.ts';
20
22
  export { type ContactPointAttributes, type ContactPointProps, GrafanaContactPoint, GrafanaContactPointProvider, } from './contact-point.ts';
21
23
  export { type MessageTemplateAttributes, type MessageTemplateProps, GrafanaMessageTemplate, GrafanaMessageTemplateProvider, } from './message-template.ts';
22
24
  export { type MuteTimingAttributes, type MuteTimingProps, GrafanaMuteTiming, GrafanaMuteTimingProvider, } from './mute-timing.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grafana/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,aAAa,EACb,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,KAAK,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/grafana/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,aAAa,EACb,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,uBAAuB,EACvB,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,mBAAmB,EACnB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EACzB,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,KAAK,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -497,12 +497,94 @@ var spec5 = {
497
497
  };
498
498
  var handlers5 = grafanaHandlers(spec5);
499
499
  var GrafanaFolderProvider = () => Provider5.effect(GrafanaFolder, Effect11.succeed(GrafanaFolder.Provider.of(handlers5)));
500
- // src/grafana/contact-point.ts
500
+ // src/grafana/team.ts
501
501
  import { Resource as Resource6 } from "alchemy";
502
502
  import * as Provider6 from "alchemy/Provider";
503
503
  import * as grafana6 from "@distilled.cloud/grafana";
504
504
  import * as Effect12 from "effect/Effect";
505
- var GrafanaContactPoint = Resource6("Grafana.ContactPoint");
505
+ var GrafanaTeam = Resource6("Grafana.Team");
506
+ var findTeamByName = (name) => grafana6.searchTeams({ name, perpage: 100 }).pipe(Effect12.map((result) => (result.teams ?? []).find((team) => team.name === name)));
507
+ var spec6 = {
508
+ attributes: (live) => ({
509
+ email: live.email ?? "",
510
+ id: live.id,
511
+ isProvisioned: live.isProvisioned,
512
+ name: live.name,
513
+ uid: live.uid
514
+ }),
515
+ create: (props) => grafana6.createTeam({
516
+ name: props.name,
517
+ ...props.email === undefined ? {} : { email: props.email }
518
+ }),
519
+ destroy: (props, live) => Effect12.gen(function* () {
520
+ if (live.isProvisioned) {
521
+ return yield* refuseIfProvisioned("Grafana.Team", props.name, "an external team sync (isProvisioned)");
522
+ }
523
+ yield* grafana6.deleteTeam({ team_id: String(live.id) });
524
+ }),
525
+ fetchLive: (props) => findTeamByName(props.name),
526
+ matches: (attributes, props) => attributes.name === props.name && (props.email === undefined || attributes.email === props.email),
527
+ update: (props, live) => Effect12.gen(function* () {
528
+ if (live.isProvisioned) {
529
+ return yield* refuseIfProvisioned("Grafana.Team", props.name, "an external team sync (isProvisioned)");
530
+ }
531
+ return yield* grafana6.updateTeam({
532
+ team_id: String(live.id),
533
+ name: props.name,
534
+ ...props.email === undefined ? {} : { email: props.email }
535
+ });
536
+ })
537
+ };
538
+ var handlers6 = grafanaHandlers(spec6);
539
+ var GrafanaTeamProvider = () => Provider6.effect(GrafanaTeam, Effect12.succeed(GrafanaTeam.Provider.of(handlers6)));
540
+ // src/grafana/folder-permission.ts
541
+ import { Resource as Resource7 } from "alchemy";
542
+ import * as Provider7 from "alchemy/Provider";
543
+ import * as grafana7 from "@distilled.cloud/grafana";
544
+ import * as Data4 from "effect/Data";
545
+ import * as Effect13 from "effect/Effect";
546
+ var GrafanaFolderPermission = Resource7("Grafana.FolderPermission");
547
+
548
+ class GrafanaTeamNotFoundError extends Data4.TaggedError("GrafanaTeamNotFoundError") {
549
+ }
550
+ var resolveTeamId = (teamName) => findTeamByName(teamName).pipe(Effect13.flatMap((team) => team === undefined ? Effect13.fail(new GrafanaTeamNotFoundError({
551
+ message: `Grafana.FolderPermission: team '${teamName}' does not exist. Declare it with Grafana.Team first.`
552
+ })) : Effect13.succeed(team.id)));
553
+ var setTeam = (folderUid, teamId, permission) => grafana7.setResourcePermissionsForTeam({
554
+ resource: "folders",
555
+ resourceID: folderUid,
556
+ teamID: teamId,
557
+ permission
558
+ });
559
+ var spec7 = {
560
+ attributes: (live, props) => ({
561
+ folderUid: props.folderUid,
562
+ permission: live.permission,
563
+ teamId: live.teamId,
564
+ teamName: props.teamName
565
+ }),
566
+ create: (props) => resolveTeamId(props.teamName).pipe(Effect13.flatMap((teamId) => setTeam(props.folderUid, teamId, props.permission))),
567
+ destroy: (props, live) => setTeam(props.folderUid, live.teamId, ""),
568
+ fetchLive: (props) => Effect13.gen(function* () {
569
+ const teamId = yield* resolveTeamId(props.teamName);
570
+ const entries = yield* grafana7.getResourcePermissions({
571
+ resource: "folders",
572
+ resourceID: props.folderUid
573
+ });
574
+ const direct = (entries ?? []).find((entry) => entry.teamId === teamId && entry.isInherited !== true);
575
+ return direct === undefined ? undefined : { permission: direct.permission ?? "", teamId };
576
+ }),
577
+ matches: (attributes, props) => attributes.permission === props.permission,
578
+ update: (props, live) => setTeam(props.folderUid, live.teamId, props.permission)
579
+ };
580
+ var handlers7 = grafanaHandlers(spec7);
581
+ var GrafanaFolderPermissionProvider = () => Provider7.effect(GrafanaFolderPermission, Effect13.succeed(GrafanaFolderPermission.Provider.of(handlers7)));
582
+ // src/grafana/contact-point.ts
583
+ import { Resource as Resource8 } from "alchemy";
584
+ import * as Provider8 from "alchemy/Provider";
585
+ import * as grafana8 from "@distilled.cloud/grafana";
586
+ import * as Effect14 from "effect/Effect";
587
+ var GrafanaContactPoint = Resource8("Grafana.ContactPoint");
506
588
  var nonSecretSettings = (props) => {
507
589
  const refs = props.secureSettingsRefs;
508
590
  if (refs === undefined)
@@ -514,8 +596,8 @@ var nonSecretSettings = (props) => {
514
596
  }
515
597
  return out;
516
598
  };
517
- var resolveSettings = (props) => Effect12.map(resolveSecretRefs(props.secureSettingsRefs, (field) => `settings.${field}`), (secrets) => secrets === undefined ? props.settings : { ...props.settings, ...secrets });
518
- var spec6 = {
599
+ var resolveSettings = (props) => Effect14.map(resolveSecretRefs(props.secureSettingsRefs, (field) => `settings.${field}`), (secrets) => secrets === undefined ? props.settings : { ...props.settings, ...secrets });
600
+ var spec8 = {
519
601
  attributes: (live) => ({
520
602
  disableResolveMessage: live.disableResolveMessage ?? false,
521
603
  name: live.name ?? "",
@@ -524,27 +606,27 @@ var spec6 = {
524
606
  type: live.type,
525
607
  uid: live.uid ?? ""
526
608
  }),
527
- create: (props) => Effect12.flatMap(resolveSettings(props), (settings) => grafana6.routePostContactpoints({
609
+ create: (props) => Effect14.flatMap(resolveSettings(props), (settings) => grafana8.routePostContactpoints({
528
610
  name: props.name,
529
611
  settings,
530
612
  type: props.type,
531
613
  uid: props.uid,
532
614
  ...props.disableResolveMessage === undefined ? {} : { disableResolveMessage: props.disableResolveMessage }
533
615
  })),
534
- destroy: (props, live) => Effect12.gen(function* () {
616
+ destroy: (props, live) => Effect14.gen(function* () {
535
617
  if (isForeignProvenance(live.provenance)) {
536
618
  return yield* refuseIfForeignProvenance("Grafana.ContactPoint", props.uid, live.provenance);
537
619
  }
538
- yield* grafana6.routeDeleteContactpoints({ UID: props.uid });
620
+ yield* grafana8.routeDeleteContactpoints({ UID: props.uid });
539
621
  }),
540
- fetchLive: (props) => grafana6.routeGetContactpoints({}).pipe(Effect12.map((points) => points.find((point) => point.uid === props.uid))),
622
+ fetchLive: (props) => grafana8.routeGetContactpoints({}).pipe(Effect14.map((points) => points.find((point) => point.uid === props.uid))),
541
623
  matches: (attributes, props) => attributes.name === props.name && attributes.type === props.type && attributes.disableResolveMessage === (props.disableResolveMessage ?? false) && declaredContentMatches(nonSecretSettings(props), attributes.settings),
542
- update: (props, live) => Effect12.gen(function* () {
624
+ update: (props, live) => Effect14.gen(function* () {
543
625
  if (isForeignProvenance(live.provenance)) {
544
626
  return yield* refuseIfForeignProvenance("Grafana.ContactPoint", props.uid, live.provenance);
545
627
  }
546
628
  const settings = yield* resolveSettings(props);
547
- yield* grafana6.routePutContactpoint({
629
+ yield* grafana8.routePutContactpoint({
548
630
  UID: props.uid,
549
631
  name: props.name,
550
632
  settings,
@@ -554,98 +636,98 @@ var spec6 = {
554
636
  });
555
637
  })
556
638
  };
557
- var handlers6 = grafanaHandlers(spec6);
558
- var GrafanaContactPointProvider = () => Provider6.effect(GrafanaContactPoint, Effect12.succeed(GrafanaContactPoint.Provider.of(handlers6)));
639
+ var handlers8 = grafanaHandlers(spec8);
640
+ var GrafanaContactPointProvider = () => Provider8.effect(GrafanaContactPoint, Effect14.succeed(GrafanaContactPoint.Provider.of(handlers8)));
559
641
  // src/grafana/message-template.ts
560
- import { Resource as Resource7 } from "alchemy";
561
- import * as Provider7 from "alchemy/Provider";
562
- import * as grafana7 from "@distilled.cloud/grafana";
563
- import * as Effect13 from "effect/Effect";
564
- var GrafanaMessageTemplate = Resource7("Grafana.MessageTemplate");
565
- var spec7 = {
642
+ import { Resource as Resource9 } from "alchemy";
643
+ import * as Provider9 from "alchemy/Provider";
644
+ import * as grafana9 from "@distilled.cloud/grafana";
645
+ import * as Effect15 from "effect/Effect";
646
+ var GrafanaMessageTemplate = Resource9("Grafana.MessageTemplate");
647
+ var spec9 = {
566
648
  attributes: (live) => ({
567
649
  name: live.name ?? "",
568
650
  provenance: live.provenance,
569
651
  template: live.template ?? ""
570
652
  }),
571
- create: (props) => grafana7.routePutTemplate({ name: props.name, template: props.template }),
572
- destroy: (props, live) => Effect13.gen(function* () {
653
+ create: (props) => grafana9.routePutTemplate({ name: props.name, template: props.template }),
654
+ destroy: (props, live) => Effect15.gen(function* () {
573
655
  if (isForeignProvenance(live.provenance)) {
574
656
  return yield* refuseIfForeignProvenance("Grafana.MessageTemplate", props.name, live.provenance);
575
657
  }
576
- yield* grafana7.routeDeleteTemplate({ name: props.name });
658
+ yield* grafana9.routeDeleteTemplate({ name: props.name });
577
659
  }),
578
- fetchLive: (props) => grafana7.routeGetTemplate({ name: props.name }).pipe(Effect13.catchTag("NotFound", () => Effect13.succeed(undefined))),
660
+ fetchLive: (props) => grafana9.routeGetTemplate({ name: props.name }).pipe(Effect15.catchTag("NotFound", () => Effect15.succeed(undefined))),
579
661
  matches: (attributes, props) => attributes.template === props.template,
580
- update: (props, live) => Effect13.gen(function* () {
662
+ update: (props, live) => Effect15.gen(function* () {
581
663
  if (isForeignProvenance(live.provenance)) {
582
664
  return yield* refuseIfForeignProvenance("Grafana.MessageTemplate", props.name, live.provenance);
583
665
  }
584
- yield* grafana7.routePutTemplate({
666
+ yield* grafana9.routePutTemplate({
585
667
  name: props.name,
586
668
  template: props.template,
587
669
  ...live.version === undefined ? {} : { version: live.version }
588
670
  });
589
671
  })
590
672
  };
591
- var handlers7 = grafanaHandlers(spec7);
592
- var GrafanaMessageTemplateProvider = () => Provider7.effect(GrafanaMessageTemplate, Effect13.succeed(GrafanaMessageTemplate.Provider.of(handlers7)));
673
+ var handlers9 = grafanaHandlers(spec9);
674
+ var GrafanaMessageTemplateProvider = () => Provider9.effect(GrafanaMessageTemplate, Effect15.succeed(GrafanaMessageTemplate.Provider.of(handlers9)));
593
675
  // src/grafana/mute-timing.ts
594
- import { Resource as Resource8 } from "alchemy";
595
- import * as Provider8 from "alchemy/Provider";
596
- import * as grafana8 from "@distilled.cloud/grafana";
597
- import * as Effect14 from "effect/Effect";
598
- var GrafanaMuteTiming = Resource8("Grafana.MuteTiming");
599
- var spec8 = {
676
+ import { Resource as Resource10 } from "alchemy";
677
+ import * as Provider10 from "alchemy/Provider";
678
+ import * as grafana10 from "@distilled.cloud/grafana";
679
+ import * as Effect16 from "effect/Effect";
680
+ var GrafanaMuteTiming = Resource10("Grafana.MuteTiming");
681
+ var spec10 = {
600
682
  attributes: (live) => ({
601
683
  name: live.name ?? "",
602
684
  provenance: live.provenance,
603
685
  timeIntervals: live.time_intervals ?? []
604
686
  }),
605
- create: (props) => grafana8.routePostMuteTiming({
687
+ create: (props) => grafana10.routePostMuteTiming({
606
688
  name: props.name,
607
689
  time_intervals: props.timeIntervals
608
690
  }),
609
- destroy: (props, live) => Effect14.gen(function* () {
691
+ destroy: (props, live) => Effect16.gen(function* () {
610
692
  if (isForeignProvenance(live.provenance)) {
611
693
  return yield* refuseIfForeignProvenance("Grafana.MuteTiming", props.name, live.provenance);
612
694
  }
613
- yield* grafana8.routeDeleteMuteTiming({
695
+ yield* grafana10.routeDeleteMuteTiming({
614
696
  name: props.name,
615
697
  ...live.version === undefined ? {} : { version: live.version }
616
698
  });
617
699
  }),
618
- fetchLive: (props) => grafana8.routeGetMuteTiming({ name: props.name }).pipe(Effect14.map((live) => live), Effect14.catchTag("NotFound", () => Effect14.succeed(undefined))),
700
+ fetchLive: (props) => grafana10.routeGetMuteTiming({ name: props.name }).pipe(Effect16.map((live) => live), Effect16.catchTag("NotFound", () => Effect16.succeed(undefined))),
619
701
  matches: (attributes, props) => declaredContentMatches(props.timeIntervals, attributes.timeIntervals),
620
- update: (props, live) => Effect14.gen(function* () {
702
+ update: (props, live) => Effect16.gen(function* () {
621
703
  if (isForeignProvenance(live.provenance)) {
622
704
  return yield* refuseIfForeignProvenance("Grafana.MuteTiming", props.name, live.provenance);
623
705
  }
624
- yield* grafana8.routePutMuteTiming({
706
+ yield* grafana10.routePutMuteTiming({
625
707
  name: props.name,
626
708
  time_intervals: props.timeIntervals
627
709
  });
628
710
  })
629
711
  };
630
- var handlers8 = grafanaHandlers(spec8);
631
- var GrafanaMuteTimingProvider = () => Provider8.effect(GrafanaMuteTiming, Effect14.succeed(GrafanaMuteTiming.Provider.of(handlers8)));
712
+ var handlers10 = grafanaHandlers(spec10);
713
+ var GrafanaMuteTimingProvider = () => Provider10.effect(GrafanaMuteTiming, Effect16.succeed(GrafanaMuteTiming.Provider.of(handlers10)));
632
714
  // src/grafana/credentials.ts
633
715
  import { Credentials } from "@distilled.cloud/grafana/Credentials";
634
716
  import { ConfigError } from "@distilled.cloud/grafana/Errors";
635
- import * as Effect15 from "effect/Effect";
717
+ import * as Effect17 from "effect/Effect";
636
718
  import * as Layer from "effect/Layer";
637
719
  import * as Redacted from "effect/Redacted";
638
- var resolve = (target) => Effect15.sync(() => process.env[target.tokenEnv]).pipe(Effect15.flatMap((raw) => raw === undefined || raw.trim() === "" ? Effect15.fail(new ConfigError({
720
+ var resolve = (target) => Effect17.sync(() => process.env[target.tokenEnv]).pipe(Effect17.flatMap((raw) => raw === undefined || raw.trim() === "" ? Effect17.fail(new ConfigError({
639
721
  message: `${target.tokenEnv} is not set. Export the Grafana service-account token there ` + `— never as an Alchemy prop — before running a stack that declares a resource ` + `against ${target.baseUrl}.`
640
- })) : Effect15.succeed({
722
+ })) : Effect17.succeed({
641
723
  apiBaseUrl: target.baseUrl.replace(/\/+$/, ""),
642
724
  token: Redacted.make(raw.trim()),
643
725
  ...target.orgId === undefined ? {} : { orgId: target.orgId }
644
- })), Effect15.orDie);
726
+ })), Effect17.orDie);
645
727
  var grafanaCredentials = (target) => Layer.succeed(Credentials, resolve(target));
646
728
  // src/grafana/providers.ts
647
729
  import * as Layer2 from "effect/Layer";
648
- var grafanaProviders = (target) => Layer2.mergeAll(GrafanaDatasourceProvider(), GrafanaFolderProvider(), GrafanaDashboardProvider(), GrafanaContactPointProvider(), GrafanaMuteTimingProvider(), GrafanaMessageTemplateProvider(), GrafanaAlertRuleGroupProvider(), GrafanaNotificationPolicyProvider()).pipe(Layer2.provide(grafanaCredentials(target)));
730
+ var grafanaProviders = (target) => Layer2.mergeAll(GrafanaDatasourceProvider(), GrafanaFolderProvider(), GrafanaTeamProvider(), GrafanaFolderPermissionProvider(), GrafanaDashboardProvider(), GrafanaContactPointProvider(), GrafanaMuteTimingProvider(), GrafanaMessageTemplateProvider(), GrafanaAlertRuleGroupProvider(), GrafanaNotificationPolicyProvider()).pipe(Layer2.provide(grafanaCredentials(target)));
649
731
  export {
650
732
  GrafanaAlertRuleGroup,
651
733
  GrafanaAlertRuleGroupProvider,
@@ -656,6 +738,8 @@ export {
656
738
  GrafanaDatasource,
657
739
  GrafanaDatasourceProvider,
658
740
  GrafanaFolder,
741
+ GrafanaFolderPermission,
742
+ GrafanaFolderPermissionProvider,
659
743
  GrafanaFolderProvider,
660
744
  GrafanaFolderReparentError,
661
745
  GrafanaMessageTemplate,
@@ -666,9 +750,12 @@ export {
666
750
  GrafanaNotificationPolicyProvider,
667
751
  GrafanaProvisionedObjectError,
668
752
  GrafanaSecretRefUnsetError,
753
+ GrafanaTeam,
754
+ GrafanaTeamNotFoundError,
755
+ GrafanaTeamProvider,
669
756
  grafanaCredentials,
670
757
  grafanaProviders
671
758
  };
672
759
 
673
- //# debugId=5578DCEDF956037C64756E2164756E21
760
+ //# debugId=D033FF5CB01A84D864756E2164756E21
674
761
  //# sourceMappingURL=index.js.map