@alchemy.run/turso 0.0.0 → 2.0.0-beta.85

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 (83) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +68 -4
  3. package/lib/ApiToken.d.ts +82 -0
  4. package/lib/ApiToken.d.ts.map +1 -0
  5. package/lib/ApiToken.js +128 -0
  6. package/lib/ApiToken.js.map +1 -0
  7. package/lib/AuthProvider.d.ts +36 -0
  8. package/lib/AuthProvider.d.ts.map +1 -0
  9. package/lib/AuthProvider.js +85 -0
  10. package/lib/AuthProvider.js.map +1 -0
  11. package/lib/Connect.d.ts +79 -0
  12. package/lib/Connect.d.ts.map +1 -0
  13. package/lib/Connect.js +22 -0
  14. package/lib/Connect.js.map +1 -0
  15. package/lib/Contributions.d.ts +7 -0
  16. package/lib/Contributions.d.ts.map +1 -0
  17. package/lib/Contributions.js +6 -0
  18. package/lib/Contributions.js.map +1 -0
  19. package/lib/Credentials.d.ts +39 -0
  20. package/lib/Credentials.d.ts.map +1 -0
  21. package/lib/Credentials.js +76 -0
  22. package/lib/Credentials.js.map +1 -0
  23. package/lib/Database.d.ts +226 -0
  24. package/lib/Database.d.ts.map +1 -0
  25. package/lib/Database.js +277 -0
  26. package/lib/Database.js.map +1 -0
  27. package/lib/DatabaseToken.d.ts +104 -0
  28. package/lib/DatabaseToken.d.ts.map +1 -0
  29. package/lib/DatabaseToken.js +133 -0
  30. package/lib/DatabaseToken.js.map +1 -0
  31. package/lib/Group.d.ts +102 -0
  32. package/lib/Group.d.ts.map +1 -0
  33. package/lib/Group.js +171 -0
  34. package/lib/Group.js.map +1 -0
  35. package/lib/GroupToken.d.ts +57 -0
  36. package/lib/GroupToken.d.ts.map +1 -0
  37. package/lib/GroupToken.js +88 -0
  38. package/lib/GroupToken.js.map +1 -0
  39. package/lib/Hrana.d.ts +42 -0
  40. package/lib/Hrana.d.ts.map +1 -0
  41. package/lib/Hrana.js +109 -0
  42. package/lib/Hrana.js.map +1 -0
  43. package/lib/ManageDatabases.d.ts +73 -0
  44. package/lib/ManageDatabases.d.ts.map +1 -0
  45. package/lib/ManageDatabases.js +81 -0
  46. package/lib/ManageDatabases.js.map +1 -0
  47. package/lib/OrganizationInvite.d.ts +46 -0
  48. package/lib/OrganizationInvite.d.ts.map +1 -0
  49. package/lib/OrganizationInvite.js +72 -0
  50. package/lib/OrganizationInvite.js.map +1 -0
  51. package/lib/OrganizationMember.d.ts +47 -0
  52. package/lib/OrganizationMember.d.ts.map +1 -0
  53. package/lib/OrganizationMember.js +81 -0
  54. package/lib/OrganizationMember.js.map +1 -0
  55. package/lib/OrganizationSettings.d.ts +52 -0
  56. package/lib/OrganizationSettings.d.ts.map +1 -0
  57. package/lib/OrganizationSettings.js +93 -0
  58. package/lib/OrganizationSettings.js.map +1 -0
  59. package/lib/Providers.d.ts +24 -0
  60. package/lib/Providers.d.ts.map +1 -0
  61. package/lib/Providers.js +42 -0
  62. package/lib/Providers.js.map +1 -0
  63. package/lib/index.d.ts +14 -0
  64. package/lib/index.d.ts.map +1 -0
  65. package/lib/index.js +14 -0
  66. package/lib/index.js.map +1 -0
  67. package/package.json +54 -3
  68. package/src/ApiToken.ts +207 -0
  69. package/src/AuthProvider.ts +113 -0
  70. package/src/Connect.ts +103 -0
  71. package/src/Contributions.ts +9 -0
  72. package/src/Credentials.ts +112 -0
  73. package/src/Database.ts +519 -0
  74. package/src/DatabaseToken.ts +213 -0
  75. package/src/Group.ts +269 -0
  76. package/src/GroupToken.ts +127 -0
  77. package/src/Hrana.ts +184 -0
  78. package/src/ManageDatabases.ts +195 -0
  79. package/src/OrganizationInvite.ts +118 -0
  80. package/src/OrganizationMember.ts +122 -0
  81. package/src/OrganizationSettings.ts +145 -0
  82. package/src/Providers.ts +67 -0
  83. package/src/index.ts +20 -0
@@ -0,0 +1,145 @@
1
+ import * as turso from "@distilled.cloud/turso/turso";
2
+ import * as Provider from "alchemy/Provider";
3
+ import { Resource } from "alchemy/Resource";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Schedule from "effect/Schedule";
6
+ import { organization } from "./Credentials.ts";
7
+ import type { Providers } from "./Providers.ts";
8
+
9
+ export interface OrganizationSettingsProps {
10
+ /** Allow usage beyond the plan's quota to be billed as overages. */
11
+ overages?: boolean;
12
+ /**
13
+ * Require every member to enable multi-factor authentication. The
14
+ * deploying user must have MFA enabled first.
15
+ */
16
+ requireMfa?: boolean;
17
+ /**
18
+ * Keep deleted databases and groups recoverable. Requires an admin or
19
+ * owner.
20
+ */
21
+ restoreEnabled?: boolean;
22
+ }
23
+
24
+ interface Settings {
25
+ overages: boolean;
26
+ requireMfa: boolean;
27
+ restoreEnabled: boolean;
28
+ }
29
+
30
+ export interface OrganizationSettingsAttributes extends Settings {
31
+ /** The organization slug. */
32
+ organization: string;
33
+ /** Settings observed before Alchemy first changed them; restored on destroy. */
34
+ original: Settings;
35
+ }
36
+
37
+ export type OrganizationSettings = Resource<
38
+ "Turso.OrganizationSettings",
39
+ OrganizationSettingsProps,
40
+ OrganizationSettingsAttributes,
41
+ never,
42
+ Providers
43
+ >;
44
+
45
+ /**
46
+ * Settings of the Turso organization your credentials act on. Only the
47
+ * settings you set are managed; destroying the resource restores the values
48
+ * observed before Alchemy first changed them.
49
+ * @see https://docs.turso.tech/api-reference/organizations/update
50
+ *
51
+ * ### Configuring the Organization
52
+ * **Example:** Enable overages and require MFA
53
+ * ```typescript
54
+ * yield* Turso.OrganizationSettings("Org", {
55
+ * overages: true,
56
+ * requireMfa: true,
57
+ * });
58
+ * ```
59
+ *
60
+ * @resource
61
+ * @product Organization
62
+ */
63
+ export const OrganizationSettings = Resource<OrganizationSettings>("Turso.OrganizationSettings");
64
+
65
+ const toSettings = (org: turso.Organization | undefined): Settings => ({
66
+ overages: org?.overages ?? false,
67
+ requireMfa: org?.require_mfa ?? false,
68
+ restoreEnabled: org?.restore_enabled ?? false,
69
+ });
70
+
71
+ export const OrganizationSettingsProvider = () =>
72
+ Provider.effect(
73
+ OrganizationSettings,
74
+ Effect.gen(function* () {
75
+ const observe = (slug: string) =>
76
+ turso
77
+ .getOrganization({ organizationSlug: slug })
78
+ .pipe(Effect.map(({ organization }) => toSettings(organization)));
79
+
80
+ // `restore_enabled` must be updated on its own (per the API).
81
+ const apply = (slug: string, observed: Settings, desired: Partial<Settings>) =>
82
+ Effect.gen(function* () {
83
+ const patch: { overages?: boolean; require_mfa?: boolean } = {};
84
+ if (desired.overages !== undefined && desired.overages !== observed.overages) {
85
+ patch.overages = desired.overages;
86
+ }
87
+ if (desired.requireMfa !== undefined && desired.requireMfa !== observed.requireMfa) {
88
+ patch.require_mfa = desired.requireMfa;
89
+ }
90
+ if (Object.keys(patch).length > 0) {
91
+ yield* turso.updateOrganization({ organizationSlug: slug, ...patch });
92
+ }
93
+ if (
94
+ desired.restoreEnabled !== undefined &&
95
+ desired.restoreEnabled !== observed.restoreEnabled
96
+ ) {
97
+ yield* turso.updateOrganization({
98
+ organizationSlug: slug,
99
+ restore_enabled: desired.restoreEnabled,
100
+ });
101
+ }
102
+ });
103
+
104
+ return {
105
+ stables: ["organization", "original"],
106
+ read: Effect.fn(function* ({ output }) {
107
+ if (!output) return undefined;
108
+ return { ...output, ...(yield* observe(output.organization)) };
109
+ }),
110
+ reconcile: Effect.fn(function* ({ news, output }) {
111
+ const slug = output?.organization ?? (yield* organization);
112
+ const observed = yield* observe(slug);
113
+ yield* apply(slug, observed, news);
114
+ // Organization reads can briefly lag a PATCH; wait until the
115
+ // settings we set are visible.
116
+ const settled = yield* observe(slug).pipe(
117
+ Effect.repeat({
118
+ schedule: Schedule.spaced("1 second"),
119
+ until: (current) =>
120
+ (news.overages === undefined || current.overages === news.overages) &&
121
+ (news.requireMfa === undefined || current.requireMfa === news.requireMfa) &&
122
+ (news.restoreEnabled === undefined ||
123
+ current.restoreEnabled === news.restoreEnabled),
124
+ times: 10,
125
+ }),
126
+ );
127
+ return {
128
+ organization: slug,
129
+ original: output?.original ?? observed,
130
+ ...settled,
131
+ };
132
+ }),
133
+ delete: Effect.fn(function* ({ olds, output }) {
134
+ const observed = yield* observe(output.organization);
135
+ // Restore only the settings this resource managed.
136
+ yield* apply(output.organization, observed, {
137
+ overages: olds.overages !== undefined ? output.original.overages : undefined,
138
+ requireMfa: olds.requireMfa !== undefined ? output.original.requireMfa : undefined,
139
+ restoreEnabled:
140
+ olds.restoreEnabled !== undefined ? output.original.restoreEnabled : undefined,
141
+ });
142
+ }),
143
+ };
144
+ }),
145
+ );
@@ -0,0 +1,67 @@
1
+ import { CredentialsStoreLive } from "alchemy/Auth/Credentials";
2
+ import { ProfileStoreLive } from "alchemy/Auth/Profile";
3
+ import * as Provider from "alchemy/Provider";
4
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
5
+ import * as Layer from "effect/Layer";
6
+ import { ApiToken, ApiTokenProvider } from "./ApiToken.ts";
7
+ import { TursoAuth } from "./AuthProvider.ts";
8
+ import * as Credentials from "./Credentials.ts";
9
+ import { Database, DatabaseProvider } from "./Database.ts";
10
+ import { DatabaseToken, DatabaseTokenProvider } from "./DatabaseToken.ts";
11
+ import { Group, GroupProvider } from "./Group.ts";
12
+ import { GroupToken, GroupTokenProvider } from "./GroupToken.ts";
13
+ import { OrganizationInvite, OrganizationInviteProvider } from "./OrganizationInvite.ts";
14
+ import { OrganizationMember, OrganizationMemberProvider } from "./OrganizationMember.ts";
15
+ import { OrganizationSettings, OrganizationSettingsProvider } from "./OrganizationSettings.ts";
16
+
17
+ /**
18
+ * Service tag bundling all Turso providers + auth + credentials. Use
19
+ * `Turso.providers()` to materialize the full layer.
20
+ */
21
+ export class Providers extends Provider.ProviderCollection<Providers>()("Turso") {}
22
+
23
+ export type ProviderRequirements = Layer.Services<ReturnType<typeof providers>>;
24
+
25
+ /**
26
+ * Build the complete Turso providers Layer: every Turso resource, the
27
+ * Turso AuthProvider registration (so `alchemy profile edit` can configure
28
+ * it), and credential resolution.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * Alchemy.Stack("App", { providers: Turso.providers() }, ...)
33
+ * ```
34
+ */
35
+ export const providers = () =>
36
+ Layer.effect(
37
+ Providers,
38
+ Provider.collection([
39
+ ApiToken,
40
+ Database,
41
+ DatabaseToken,
42
+ Group,
43
+ GroupToken,
44
+ OrganizationInvite,
45
+ OrganizationMember,
46
+ OrganizationSettings,
47
+ ]),
48
+ ).pipe(
49
+ Layer.provide(
50
+ Layer.mergeAll(
51
+ ApiTokenProvider(),
52
+ DatabaseProvider(),
53
+ DatabaseTokenProvider(),
54
+ GroupProvider(),
55
+ GroupTokenProvider(),
56
+ OrganizationInviteProvider(),
57
+ OrganizationMemberProvider(),
58
+ OrganizationSettingsProvider(),
59
+ ),
60
+ ),
61
+ Layer.provideMerge(Credentials.fromAuthProvider()),
62
+ Layer.provideMerge(FetchHttpClient.layer),
63
+ Layer.provideMerge(TursoAuth),
64
+ Layer.provideMerge(ProfileStoreLive),
65
+ Layer.provideMerge(CredentialsStoreLive),
66
+ Layer.orDie,
67
+ );
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ export * from "./ApiToken.ts";
2
+ export * from "./AuthProvider.ts";
3
+ export * from "./Connect.ts";
4
+ export {
5
+ Credentials,
6
+ CredentialsFromEnv,
7
+ DEFAULT_API_BASE_URL,
8
+ fromAuthProvider,
9
+ fromToken,
10
+ Organization,
11
+ } from "./Credentials.ts";
12
+ export * from "./Database.ts";
13
+ export * from "./DatabaseToken.ts";
14
+ export * from "./Group.ts";
15
+ export * from "./GroupToken.ts";
16
+ export * from "./ManageDatabases.ts";
17
+ export * from "./OrganizationInvite.ts";
18
+ export * from "./OrganizationMember.ts";
19
+ export * from "./OrganizationSettings.ts";
20
+ export * from "./Providers.ts";