@geenius/adapters 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -42
- package/package.json +23 -4
- package/packages/convex/README.md +1 -1
- package/packages/convex/dist/index.cjs +300 -0
- package/packages/convex/dist/index.cjs.map +1 -0
- package/packages/convex/dist/index.d.cts +231 -0
- package/packages/convex/dist/index.d.ts +231 -0
- package/packages/convex/dist/index.js +263 -0
- package/packages/convex/dist/index.js.map +1 -0
- package/packages/react/README.md +1 -1
- package/packages/react/dist/index.d.mts +106 -0
- package/packages/react/dist/index.d.ts +106 -0
- package/packages/react/dist/index.js +611 -0
- package/packages/react/dist/index.js.map +1 -0
- package/packages/react/dist/index.mjs +570 -0
- package/packages/react/dist/index.mjs.map +1 -0
- package/packages/react-css/README.md +1 -1
- package/packages/react-css/dist/index.cjs +515 -0
- package/packages/react-css/dist/index.cjs.map +1 -0
- package/packages/react-css/dist/index.d.cts +105 -0
- package/packages/react-css/dist/index.d.ts +105 -0
- package/packages/react-css/dist/index.js +467 -0
- package/packages/react-css/dist/index.js.map +1 -0
- package/packages/shared/README.md +1 -1
- package/packages/shared/dist/index.d.mts +625 -0
- package/packages/shared/dist/index.d.ts +625 -0
- package/packages/shared/dist/index.js +1567 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/index.mjs +1489 -0
- package/packages/shared/dist/index.mjs.map +1 -0
- package/packages/solidjs/README.md +1 -1
- package/packages/solidjs/dist/index.d.mts +97 -0
- package/packages/solidjs/dist/index.d.ts +97 -0
- package/packages/solidjs/dist/index.js +250 -0
- package/packages/solidjs/dist/index.js.map +1 -0
- package/packages/solidjs/dist/index.mjs +202 -0
- package/packages/solidjs/dist/index.mjs.map +1 -0
- package/packages/solidjs-css/README.md +1 -1
- package/packages/solidjs-css/dist/index.cjs +343 -0
- package/packages/solidjs-css/dist/index.cjs.map +1 -0
- package/packages/solidjs-css/dist/index.d.cts +67 -0
- package/packages/solidjs-css/dist/index.d.ts +67 -0
- package/packages/solidjs-css/dist/index.js +326 -0
- package/packages/solidjs-css/dist/index.js.map +1 -0
- package/.changeset/config.json +0 -11
- package/.github/CODEOWNERS +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -29
- package/.nvmrc +0 -1
- package/.project/ACCOUNT.yaml +0 -4
- package/.project/IDEAS.yaml +0 -7
- package/.project/PROJECT.yaml +0 -11
- package/.project/ROADMAP.yaml +0 -15
- package/CODE_OF_CONDUCT.md +0 -16
- package/CONTRIBUTING.md +0 -26
- package/SECURITY.md +0 -15
- package/SUPPORT.md +0 -8
- package/packages/convex/package.json +0 -42
- package/packages/convex/src/adapter.ts +0 -39
- package/packages/convex/src/index.ts +0 -19
- package/packages/convex/src/mutations.ts +0 -142
- package/packages/convex/src/queries.ts +0 -106
- package/packages/convex/src/schema.ts +0 -54
- package/packages/convex/src/types.ts +0 -20
- package/packages/convex/tsconfig.json +0 -11
- package/packages/convex/tsup.config.ts +0 -10
- package/packages/react/package.json +0 -45
- package/packages/react/src/components/AdapterCard.tsx +0 -49
- package/packages/react/src/components/AdapterConfigForm.tsx +0 -118
- package/packages/react/src/components/AdapterList.tsx +0 -84
- package/packages/react/src/components/AdapterStatusBadge.tsx +0 -30
- package/packages/react/src/components/index.ts +0 -4
- package/packages/react/src/hooks/index.ts +0 -75
- package/packages/react/src/index.tsx +0 -44
- package/packages/react/src/pages/AdapterDetailPage.tsx +0 -133
- package/packages/react/src/pages/AdaptersPage.tsx +0 -111
- package/packages/react/src/pages/index.ts +0 -2
- package/packages/react/src/provider/AdapterProvider.tsx +0 -115
- package/packages/react/src/provider/index.ts +0 -2
- package/packages/react/tsconfig.json +0 -18
- package/packages/react/tsup.config.ts +0 -10
- package/packages/react-css/package.json +0 -44
- package/packages/react-css/src/adapters.css +0 -1576
- package/packages/react-css/src/components/AdapterCard.tsx +0 -34
- package/packages/react-css/src/components/AdapterConfigForm.tsx +0 -63
- package/packages/react-css/src/components/AdapterList.tsx +0 -40
- package/packages/react-css/src/components/AdapterStatusBadge.tsx +0 -21
- package/packages/react-css/src/components/index.ts +0 -4
- package/packages/react-css/src/hooks/index.ts +0 -75
- package/packages/react-css/src/index.tsx +0 -25
- package/packages/react-css/src/pages/AdapterDetailPage.tsx +0 -133
- package/packages/react-css/src/pages/AdaptersPage.tsx +0 -111
- package/packages/react-css/src/pages/index.ts +0 -2
- package/packages/react-css/src/provider/AdapterProvider.tsx +0 -115
- package/packages/react-css/src/provider/index.ts +0 -2
- package/packages/react-css/src/styles.css +0 -494
- package/packages/react-css/tsconfig.json +0 -19
- package/packages/react-css/tsup.config.ts +0 -2
- package/packages/shared/package.json +0 -39
- package/packages/shared/src/__tests__/adapters.test.ts +0 -545
- package/packages/shared/src/admin/index.ts +0 -2
- package/packages/shared/src/admin/interface.ts +0 -34
- package/packages/shared/src/admin/localStorage.ts +0 -109
- package/packages/shared/src/ai/anthropic.ts +0 -123
- package/packages/shared/src/ai/cloudflare-gateway.ts +0 -130
- package/packages/shared/src/ai/gemini.ts +0 -181
- package/packages/shared/src/ai/index.ts +0 -14
- package/packages/shared/src/ai/interface.ts +0 -11
- package/packages/shared/src/ai/localStorage.ts +0 -78
- package/packages/shared/src/ai/ollama.ts +0 -143
- package/packages/shared/src/ai/openai.ts +0 -120
- package/packages/shared/src/ai/vercel-ai.ts +0 -101
- package/packages/shared/src/auth/better-auth.ts +0 -118
- package/packages/shared/src/auth/clerk.ts +0 -151
- package/packages/shared/src/auth/convex-auth.ts +0 -125
- package/packages/shared/src/auth/index.ts +0 -10
- package/packages/shared/src/auth/interface.ts +0 -17
- package/packages/shared/src/auth/localStorage.ts +0 -125
- package/packages/shared/src/auth/supabase-auth.ts +0 -136
- package/packages/shared/src/config.ts +0 -57
- package/packages/shared/src/constants.ts +0 -122
- package/packages/shared/src/db/convex.ts +0 -146
- package/packages/shared/src/db/index.ts +0 -10
- package/packages/shared/src/db/interface.ts +0 -13
- package/packages/shared/src/db/localStorage.ts +0 -91
- package/packages/shared/src/db/mongodb.ts +0 -125
- package/packages/shared/src/db/neon.ts +0 -171
- package/packages/shared/src/db/supabase.ts +0 -158
- package/packages/shared/src/index.ts +0 -117
- package/packages/shared/src/payments/index.ts +0 -4
- package/packages/shared/src/payments/interface.ts +0 -11
- package/packages/shared/src/payments/localStorage.ts +0 -81
- package/packages/shared/src/payments/stripe.ts +0 -177
- package/packages/shared/src/storage/convex.ts +0 -113
- package/packages/shared/src/storage/index.ts +0 -14
- package/packages/shared/src/storage/interface.ts +0 -11
- package/packages/shared/src/storage/localStorage.ts +0 -95
- package/packages/shared/src/storage/minio.ts +0 -47
- package/packages/shared/src/storage/r2.ts +0 -123
- package/packages/shared/src/storage/s3.ts +0 -128
- package/packages/shared/src/storage/supabase-storage.ts +0 -116
- package/packages/shared/src/storage/uploadthing.ts +0 -126
- package/packages/shared/src/styles/adapters.css +0 -494
- package/packages/shared/src/tier-gate.ts +0 -119
- package/packages/shared/src/types.ts +0 -162
- package/packages/shared/tsconfig.json +0 -18
- package/packages/shared/tsup.config.ts +0 -9
- package/packages/shared/vitest.config.ts +0 -14
- package/packages/solidjs/package.json +0 -44
- package/packages/solidjs/src/components/AdapterCard.tsx +0 -24
- package/packages/solidjs/src/components/AdapterConfigForm.tsx +0 -54
- package/packages/solidjs/src/components/AdapterList.tsx +0 -28
- package/packages/solidjs/src/components/AdapterStatusBadge.tsx +0 -20
- package/packages/solidjs/src/components/index.ts +0 -4
- package/packages/solidjs/src/index.tsx +0 -17
- package/packages/solidjs/src/pages/AdapterDetailPage.tsx +0 -38
- package/packages/solidjs/src/pages/AdaptersPage.tsx +0 -39
- package/packages/solidjs/src/pages/index.ts +0 -2
- package/packages/solidjs/src/primitives/index.ts +0 -78
- package/packages/solidjs/src/provider/AdapterProvider.tsx +0 -62
- package/packages/solidjs/src/provider/index.ts +0 -2
- package/packages/solidjs/tsconfig.json +0 -20
- package/packages/solidjs/tsup.config.ts +0 -10
- package/packages/solidjs-css/package.json +0 -43
- package/packages/solidjs-css/src/adapters.css +0 -1576
- package/packages/solidjs-css/src/components/AdapterCard.tsx +0 -43
- package/packages/solidjs-css/src/components/AdapterConfigForm.tsx +0 -119
- package/packages/solidjs-css/src/components/AdapterList.tsx +0 -68
- package/packages/solidjs-css/src/components/AdapterStatusBadge.tsx +0 -24
- package/packages/solidjs-css/src/components/index.ts +0 -8
- package/packages/solidjs-css/src/index.tsx +0 -30
- package/packages/solidjs-css/src/pages/AdapterDetailPage.tsx +0 -107
- package/packages/solidjs-css/src/pages/AdaptersPage.tsx +0 -94
- package/packages/solidjs-css/src/pages/index.ts +0 -4
- package/packages/solidjs-css/src/primitives/index.ts +0 -1
- package/packages/solidjs-css/src/provider/AdapterProvider.tsx +0 -61
- package/packages/solidjs-css/src/provider/index.ts +0 -2
- package/packages/solidjs-css/tsconfig.json +0 -20
- package/packages/solidjs-css/tsup.config.ts +0 -2
- package/pnpm-workspace.yaml +0 -2
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,1567 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ADAPTER_DOMAINS: () => ADAPTER_DOMAINS,
|
|
24
|
+
ADAPTER_STATUSES: () => ADAPTER_STATUSES,
|
|
25
|
+
ADMIN_PROVIDERS: () => ADMIN_PROVIDERS,
|
|
26
|
+
AI_PROVIDERS: () => AI_PROVIDERS,
|
|
27
|
+
AUTH_PROVIDERS: () => AUTH_PROVIDERS,
|
|
28
|
+
AdapterError: () => AdapterError,
|
|
29
|
+
AdminError: () => AdminError,
|
|
30
|
+
AiError: () => AiError,
|
|
31
|
+
AuthError: () => AuthError,
|
|
32
|
+
DB_PROVIDERS: () => DB_PROVIDERS,
|
|
33
|
+
DEFAULT_TIER_GATE: () => DEFAULT_TIER_GATE,
|
|
34
|
+
DOMAIN_DESCRIPTIONS: () => DOMAIN_DESCRIPTIONS,
|
|
35
|
+
DOMAIN_ICONS: () => DOMAIN_ICONS,
|
|
36
|
+
DOMAIN_LABELS: () => DOMAIN_LABELS,
|
|
37
|
+
DbError: () => DbError,
|
|
38
|
+
PAYMENT_PROVIDERS: () => PAYMENT_PROVIDERS,
|
|
39
|
+
PROVIDER_REGISTRY: () => PROVIDER_REGISTRY,
|
|
40
|
+
PaymentsError: () => PaymentsError,
|
|
41
|
+
STORAGE_PROVIDERS: () => STORAGE_PROVIDERS,
|
|
42
|
+
StorageError: () => StorageError,
|
|
43
|
+
clearResolvers: () => clearResolvers,
|
|
44
|
+
configureAdapters: () => configureAdapters,
|
|
45
|
+
createCloudflareKVDbAdapter: () => createCloudflareKVDbAdapter,
|
|
46
|
+
createConvexDbAdapter: () => createConvexDbAdapter,
|
|
47
|
+
createLocalStorageAdminAdapter: () => createLocalStorageAdminAdapter,
|
|
48
|
+
createLocalStorageAiAdapter: () => createLocalStorageAiAdapter,
|
|
49
|
+
createLocalStorageAuthAdapter: () => createLocalStorageAuthAdapter,
|
|
50
|
+
createLocalStorageDbAdapter: () => createLocalStorageDbAdapter,
|
|
51
|
+
createLocalStorageFileAdapter: () => createLocalStorageFileAdapter,
|
|
52
|
+
createLocalStoragePaymentsAdapter: () => createLocalStoragePaymentsAdapter,
|
|
53
|
+
createMemoryDbAdapter: () => createMemoryDbAdapter,
|
|
54
|
+
createMongoDbAdapter: () => createMongoDbAdapter,
|
|
55
|
+
createNeonDbAdapter: () => createNeonDbAdapter,
|
|
56
|
+
createNoopPaymentsAdapter: () => createNoopPaymentsAdapter,
|
|
57
|
+
createSupabaseDbAdapter: () => createSupabaseDbAdapter,
|
|
58
|
+
getAdapterConfig: () => getAdapterConfig,
|
|
59
|
+
getAvailableFeatures: () => getAvailableFeatures,
|
|
60
|
+
getAvailablePackages: () => getAvailablePackages,
|
|
61
|
+
getDomainConfig: () => getDomainConfig,
|
|
62
|
+
getProviderMeta: () => getProviderMeta,
|
|
63
|
+
getProvidersForDomain: () => getProvidersForDomain,
|
|
64
|
+
getUpgradeFeatures: () => getUpgradeFeatures,
|
|
65
|
+
hasResolver: () => hasResolver,
|
|
66
|
+
isAdapterError: () => isAdapterError,
|
|
67
|
+
isAdaptersConfigured: () => isAdaptersConfigured,
|
|
68
|
+
isFeatureAvailable: () => isFeatureAvailable,
|
|
69
|
+
isPackageAvailable: () => isPackageAvailable,
|
|
70
|
+
isRetryable: () => isRetryable,
|
|
71
|
+
registerResolver: () => registerResolver,
|
|
72
|
+
resetAdapterConfig: () => resetAdapterConfig,
|
|
73
|
+
resolveAdapter: () => resolveAdapter,
|
|
74
|
+
withRetry: () => withRetry
|
|
75
|
+
});
|
|
76
|
+
module.exports = __toCommonJS(index_exports);
|
|
77
|
+
|
|
78
|
+
// src/errors.ts
|
|
79
|
+
var AdapterError = class extends Error {
|
|
80
|
+
constructor(message, domain, code, cause) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.domain = domain;
|
|
83
|
+
this.code = code;
|
|
84
|
+
this.cause = cause;
|
|
85
|
+
this.name = "AdapterError";
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var DbError = class extends AdapterError {
|
|
89
|
+
constructor(message, code, cause) {
|
|
90
|
+
super(message, "db", code, cause);
|
|
91
|
+
this.name = "DbError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var AuthError = class extends AdapterError {
|
|
95
|
+
constructor(message, code, cause) {
|
|
96
|
+
super(message, "auth", code, cause);
|
|
97
|
+
this.name = "AuthError";
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var AiError = class extends AdapterError {
|
|
101
|
+
constructor(message, code, cause) {
|
|
102
|
+
super(message, "ai", code, cause);
|
|
103
|
+
this.name = "AiError";
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var StorageError = class extends AdapterError {
|
|
107
|
+
constructor(message, code, cause) {
|
|
108
|
+
super(message, "storage", code, cause);
|
|
109
|
+
this.name = "StorageError";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var PaymentsError = class extends AdapterError {
|
|
113
|
+
constructor(message, code, cause) {
|
|
114
|
+
super(message, "payments", code, cause);
|
|
115
|
+
this.name = "PaymentsError";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var AdminError = class extends AdapterError {
|
|
119
|
+
constructor(message, code, cause) {
|
|
120
|
+
super(message, "admin", code, cause);
|
|
121
|
+
this.name = "AdminError";
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
function isAdapterError(error) {
|
|
125
|
+
return error instanceof AdapterError;
|
|
126
|
+
}
|
|
127
|
+
function isRetryable(error) {
|
|
128
|
+
if (!isAdapterError(error)) return false;
|
|
129
|
+
const retryableCodes = /* @__PURE__ */ new Set(["RATE_LIMIT", "CONNECTION_ERROR", "SERVICE_ERROR"]);
|
|
130
|
+
return retryableCodes.has(error.code);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/retry.ts
|
|
134
|
+
async function withRetry(fn, options = {}) {
|
|
135
|
+
const {
|
|
136
|
+
maxAttempts = 3,
|
|
137
|
+
delayMs = 500,
|
|
138
|
+
backoffMultiplier = 2,
|
|
139
|
+
shouldRetry = isRetryable
|
|
140
|
+
} = options;
|
|
141
|
+
let lastError;
|
|
142
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
143
|
+
try {
|
|
144
|
+
return await fn();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
lastError = error;
|
|
147
|
+
if (attempt === maxAttempts || !shouldRetry(error)) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
const delay = delayMs * Math.pow(backoffMultiplier, attempt - 1);
|
|
151
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
throw lastError;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/config.ts
|
|
158
|
+
var _config = null;
|
|
159
|
+
function configureAdapters(config) {
|
|
160
|
+
_config = config;
|
|
161
|
+
}
|
|
162
|
+
function getAdapterConfig() {
|
|
163
|
+
if (!_config) {
|
|
164
|
+
throw new Error("Adapters not configured. Call configureAdapters() first.");
|
|
165
|
+
}
|
|
166
|
+
return _config;
|
|
167
|
+
}
|
|
168
|
+
function isAdaptersConfigured() {
|
|
169
|
+
return _config !== null;
|
|
170
|
+
}
|
|
171
|
+
function resetAdapterConfig() {
|
|
172
|
+
_config = null;
|
|
173
|
+
}
|
|
174
|
+
function getDomainConfig(domain) {
|
|
175
|
+
const config = getAdapterConfig();
|
|
176
|
+
return config[domain] ?? null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/resolve.ts
|
|
180
|
+
var resolvers = /* @__PURE__ */ new Map();
|
|
181
|
+
function registerResolver(domain, provider, resolver) {
|
|
182
|
+
resolvers.set(`${domain}:${provider}`, resolver);
|
|
183
|
+
}
|
|
184
|
+
function resolveAdapter(domain) {
|
|
185
|
+
const config = getDomainConfig(domain);
|
|
186
|
+
if (!config) {
|
|
187
|
+
throw new Error(`No configuration found for adapter domain: ${domain}`);
|
|
188
|
+
}
|
|
189
|
+
const key = `${domain}:${config.provider}`;
|
|
190
|
+
const resolver = resolvers.get(key);
|
|
191
|
+
if (!resolver) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`No resolver registered for ${domain}:${config.provider}. Call registerResolver('${domain}', '${config.provider}', factory) first.`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return resolver(config);
|
|
197
|
+
}
|
|
198
|
+
function hasResolver(domain, provider) {
|
|
199
|
+
return resolvers.has(`${domain}:${provider}`);
|
|
200
|
+
}
|
|
201
|
+
function clearResolvers() {
|
|
202
|
+
resolvers.clear();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/constants.ts
|
|
206
|
+
var ADAPTER_DOMAINS = [
|
|
207
|
+
"db",
|
|
208
|
+
"auth",
|
|
209
|
+
"payments",
|
|
210
|
+
"ai",
|
|
211
|
+
"storage",
|
|
212
|
+
"admin"
|
|
213
|
+
];
|
|
214
|
+
var DB_PROVIDERS = ["localStorage", "convex", "supabase", "neon", "mongodb"];
|
|
215
|
+
var AUTH_PROVIDERS = ["localStorage", "better-auth", "convex-auth", "clerk", "supabase-auth"];
|
|
216
|
+
var AI_PROVIDERS = ["localStorage", "openai", "anthropic", "gemini", "ollama", "cloudflare-ai-gateway", "vercel-ai-sdk"];
|
|
217
|
+
var STORAGE_PROVIDERS = ["localStorage", "r2", "s3", "uploadthing", "supabase-storage", "convex-storage", "minio"];
|
|
218
|
+
var PAYMENT_PROVIDERS = ["localStorage", "stripe", "noop"];
|
|
219
|
+
var ADMIN_PROVIDERS = ["localStorage"];
|
|
220
|
+
var ADAPTER_STATUSES = ["connected", "disconnected", "error", "initializing"];
|
|
221
|
+
var DOMAIN_LABELS = {
|
|
222
|
+
db: "Database",
|
|
223
|
+
auth: "Authentication",
|
|
224
|
+
payments: "Payments",
|
|
225
|
+
ai: "AI & LLM",
|
|
226
|
+
storage: "File Storage",
|
|
227
|
+
admin: "Admin Panel"
|
|
228
|
+
};
|
|
229
|
+
var DOMAIN_ICONS = {
|
|
230
|
+
db: "\u{1F5C4}\uFE0F",
|
|
231
|
+
auth: "\u{1F510}",
|
|
232
|
+
payments: "\u{1F4B3}",
|
|
233
|
+
ai: "\u{1F916}",
|
|
234
|
+
storage: "\u{1F4C1}",
|
|
235
|
+
admin: "\u2699\uFE0F"
|
|
236
|
+
};
|
|
237
|
+
var DOMAIN_DESCRIPTIONS = {
|
|
238
|
+
db: "Connect to your preferred database backend for data persistence.",
|
|
239
|
+
auth: "User authentication, sessions, and identity management.",
|
|
240
|
+
payments: "Subscriptions, checkout, and billing management.",
|
|
241
|
+
ai: "AI completions, chat, and embeddings via any LLM provider.",
|
|
242
|
+
storage: "Upload, download, and manage files with any storage provider.",
|
|
243
|
+
admin: "Admin dashboard metrics and user management."
|
|
244
|
+
};
|
|
245
|
+
var PROVIDER_REGISTRY = [
|
|
246
|
+
// DB
|
|
247
|
+
{ id: "localStorage", name: "localStorage", domain: "db", description: "In-browser mock storage for prototyping", tier: "pronto" },
|
|
248
|
+
{ id: "convex", name: "Convex", domain: "db", description: "Real-time cloud database with sub-50ms reactivity", tier: "lancio" },
|
|
249
|
+
{ id: "supabase", name: "Supabase", domain: "db", description: "PostgreSQL + Auth + Storage", tier: "lancio" },
|
|
250
|
+
{ id: "neon", name: "Neon", domain: "db", description: "Serverless PostgreSQL", tier: "lancio" },
|
|
251
|
+
{ id: "mongodb", name: "MongoDB", domain: "db", description: "Document database via Prisma ORM", tier: "lancio" },
|
|
252
|
+
// Auth
|
|
253
|
+
{ id: "localStorage", name: "localStorage", domain: "auth", description: "Mock auth for prototyping", tier: "pronto" },
|
|
254
|
+
{ id: "better-auth", name: "Better Auth", domain: "auth", description: "Self-hosted auth with OAuth + MFA", tier: "lancio" },
|
|
255
|
+
{ id: "convex-auth", name: "Convex Auth", domain: "auth", description: "Built-in Convex sessions", tier: "lancio" },
|
|
256
|
+
{ id: "clerk", name: "Clerk", domain: "auth", description: "SaaS auth with pre-built UI", tier: "lancio" },
|
|
257
|
+
{ id: "supabase-auth", name: "Supabase Auth", domain: "auth", description: "Built-in Supabase auth", tier: "lancio" },
|
|
258
|
+
// AI
|
|
259
|
+
{ id: "localStorage", name: "localStorage", domain: "ai", description: "Mock AI for prototyping", tier: "pronto" },
|
|
260
|
+
{ id: "openai", name: "OpenAI", domain: "ai", description: "GPT models with streaming + embeddings", tier: "lancio" },
|
|
261
|
+
{ id: "anthropic", name: "Anthropic", domain: "ai", description: "Claude models with streaming", tier: "lancio" },
|
|
262
|
+
{ id: "gemini", name: "Google Gemini", domain: "ai", description: "Gemini models, zero npm deps", tier: "lancio" },
|
|
263
|
+
{ id: "ollama", name: "Ollama", domain: "ai", description: "Local LLMs, zero npm deps", tier: "lancio" },
|
|
264
|
+
{ id: "cloudflare-ai-gateway", name: "CF AI Gateway", domain: "ai", description: "Caching/rate-limiting proxy", tier: "studio" },
|
|
265
|
+
{ id: "vercel-ai-sdk", name: "Vercel AI SDK", domain: "ai", description: "generateText/embed wrappers", tier: "studio" },
|
|
266
|
+
// Storage
|
|
267
|
+
{ id: "localStorage", name: "localStorage", domain: "storage", description: "Base64 in-browser storage", tier: "pronto" },
|
|
268
|
+
{ id: "r2", name: "Cloudflare R2", domain: "storage", description: "S3-compatible, zero egress", tier: "lancio" },
|
|
269
|
+
{ id: "s3", name: "AWS S3", domain: "storage", description: "IAM roles + CloudFront CDN", tier: "lancio" },
|
|
270
|
+
{ id: "uploadthing", name: "Uploadthing", domain: "storage", description: "REST API file upload SaaS", tier: "lancio" },
|
|
271
|
+
{ id: "supabase-storage", name: "Supabase Storage", domain: "storage", description: "Native Supabase storage", tier: "lancio" },
|
|
272
|
+
{ id: "convex-storage", name: "Convex Storage", domain: "storage", description: "Convex built-in file storage", tier: "lancio" },
|
|
273
|
+
{ id: "minio", name: "Minio", domain: "storage", description: "Self-hosted S3-compatible", tier: "studio" },
|
|
274
|
+
// Payments
|
|
275
|
+
{ id: "localStorage", name: "localStorage", domain: "payments", description: "Mock billing for prototyping", tier: "pronto" },
|
|
276
|
+
{ id: "stripe", name: "Stripe", domain: "payments", description: "Full billing, subscriptions, checkout", tier: "lancio" },
|
|
277
|
+
{ id: "noop", name: "Noop", domain: "payments", description: "No-op adapter \u2014 always returns success", tier: "pronto" },
|
|
278
|
+
// Admin
|
|
279
|
+
{ id: "localStorage", name: "localStorage", domain: "admin", description: "Mock admin for prototyping", tier: "pronto" }
|
|
280
|
+
];
|
|
281
|
+
function getProvidersForDomain(domain) {
|
|
282
|
+
return PROVIDER_REGISTRY.filter((p) => p.domain === domain);
|
|
283
|
+
}
|
|
284
|
+
function getProviderMeta(domain, providerId) {
|
|
285
|
+
return PROVIDER_REGISTRY.find((p) => p.domain === domain && p.id === providerId);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/auth/localStorage.ts
|
|
289
|
+
var USERS_KEY = "geenius_users";
|
|
290
|
+
var SESSION_KEY = "geenius_session";
|
|
291
|
+
function getUsers() {
|
|
292
|
+
try {
|
|
293
|
+
return JSON.parse(localStorage.getItem(USERS_KEY) || "[]");
|
|
294
|
+
} catch {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function saveUsers(users) {
|
|
299
|
+
localStorage.setItem(USERS_KEY, JSON.stringify(users));
|
|
300
|
+
}
|
|
301
|
+
function simpleHash(str) {
|
|
302
|
+
let hash = 0;
|
|
303
|
+
for (let i = 0; i < str.length; i++) {
|
|
304
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
305
|
+
hash |= 0;
|
|
306
|
+
}
|
|
307
|
+
return Math.abs(hash).toString(36);
|
|
308
|
+
}
|
|
309
|
+
function createSession(userId) {
|
|
310
|
+
const session = {
|
|
311
|
+
userId,
|
|
312
|
+
token: crypto.randomUUID(),
|
|
313
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3).toISOString()
|
|
314
|
+
};
|
|
315
|
+
localStorage.setItem(SESSION_KEY, JSON.stringify(session));
|
|
316
|
+
return session;
|
|
317
|
+
}
|
|
318
|
+
function createLocalStorageAuthAdapter() {
|
|
319
|
+
return {
|
|
320
|
+
async signInWithOAuth(provider, options) {
|
|
321
|
+
const mockEmail = `oauth-${provider}-user@example.com`;
|
|
322
|
+
const users = getUsers();
|
|
323
|
+
let user = users.find((u) => u.email === mockEmail);
|
|
324
|
+
if (!user) {
|
|
325
|
+
user = {
|
|
326
|
+
id: crypto.randomUUID(),
|
|
327
|
+
email: mockEmail,
|
|
328
|
+
name: `${provider.charAt(0).toUpperCase() + provider.slice(1)} User`,
|
|
329
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
330
|
+
passwordHash: ""
|
|
331
|
+
};
|
|
332
|
+
users.push(user);
|
|
333
|
+
saveUsers(users);
|
|
334
|
+
}
|
|
335
|
+
createSession(user.id);
|
|
336
|
+
const redirectUrl = options?.redirectUrl || "/";
|
|
337
|
+
return { url: redirectUrl };
|
|
338
|
+
},
|
|
339
|
+
async signUp(email, password, name) {
|
|
340
|
+
const users = getUsers();
|
|
341
|
+
if (users.find((u) => u.email === email)) throw new AuthError("User already exists", "USER_EXISTS");
|
|
342
|
+
const user = {
|
|
343
|
+
id: crypto.randomUUID(),
|
|
344
|
+
email,
|
|
345
|
+
name: name || email.split("@")[0],
|
|
346
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
347
|
+
passwordHash: simpleHash(password)
|
|
348
|
+
};
|
|
349
|
+
users.push(user);
|
|
350
|
+
saveUsers(users);
|
|
351
|
+
return createSession(user.id);
|
|
352
|
+
},
|
|
353
|
+
async signIn(email, password) {
|
|
354
|
+
const user = getUsers().find((u) => u.email === email);
|
|
355
|
+
if (!user || user.passwordHash !== simpleHash(password)) {
|
|
356
|
+
throw new AuthError("Invalid email or password", "INVALID_CREDENTIALS");
|
|
357
|
+
}
|
|
358
|
+
return createSession(user.id);
|
|
359
|
+
},
|
|
360
|
+
async signOut() {
|
|
361
|
+
localStorage.removeItem(SESSION_KEY);
|
|
362
|
+
},
|
|
363
|
+
async getSession() {
|
|
364
|
+
try {
|
|
365
|
+
const raw = localStorage.getItem(SESSION_KEY);
|
|
366
|
+
if (!raw) return null;
|
|
367
|
+
const s = JSON.parse(raw);
|
|
368
|
+
if (!s || !s.expiresAt) return null;
|
|
369
|
+
if (new Date(s.expiresAt) < /* @__PURE__ */ new Date()) {
|
|
370
|
+
localStorage.removeItem(SESSION_KEY);
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
return s;
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
async getUser() {
|
|
379
|
+
const session = await this.getSession();
|
|
380
|
+
if (!session) return null;
|
|
381
|
+
const stored = getUsers().find((u) => u.id === session.userId);
|
|
382
|
+
if (!stored) return null;
|
|
383
|
+
const { passwordHash: _, ...user } = stored;
|
|
384
|
+
return user;
|
|
385
|
+
},
|
|
386
|
+
async updateUser(updates) {
|
|
387
|
+
const session = await this.getSession();
|
|
388
|
+
if (!session) return null;
|
|
389
|
+
const users = getUsers();
|
|
390
|
+
const idx = users.findIndex((u) => u.id === session.userId);
|
|
391
|
+
if (idx === -1) return null;
|
|
392
|
+
Object.assign(users[idx], updates);
|
|
393
|
+
saveUsers(users);
|
|
394
|
+
const { passwordHash: _, ...user } = users[idx];
|
|
395
|
+
return user;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/db/memory.ts
|
|
401
|
+
function matchesCondition(item, cond) {
|
|
402
|
+
const val = item[cond.field];
|
|
403
|
+
switch (cond.operator) {
|
|
404
|
+
case "eq":
|
|
405
|
+
return val === cond.value;
|
|
406
|
+
case "neq":
|
|
407
|
+
return val !== cond.value;
|
|
408
|
+
case "gt":
|
|
409
|
+
return val > cond.value;
|
|
410
|
+
case "gte":
|
|
411
|
+
return val >= cond.value;
|
|
412
|
+
case "lt":
|
|
413
|
+
return val < cond.value;
|
|
414
|
+
case "lte":
|
|
415
|
+
return val <= cond.value;
|
|
416
|
+
case "in":
|
|
417
|
+
return Array.isArray(cond.value) && cond.value.includes(val);
|
|
418
|
+
case "contains":
|
|
419
|
+
return typeof val === "string" && val.includes(cond.value);
|
|
420
|
+
default:
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function matchesFilter(item, filter) {
|
|
425
|
+
return filter.every((cond) => matchesCondition(item, cond));
|
|
426
|
+
}
|
|
427
|
+
function createMemoryDbAdapter() {
|
|
428
|
+
const store = /* @__PURE__ */ new Map();
|
|
429
|
+
function getCollection2(collection) {
|
|
430
|
+
return store.get(collection) || [];
|
|
431
|
+
}
|
|
432
|
+
function saveCollection2(collection, data) {
|
|
433
|
+
store.set(collection, data);
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
async create(collection, data) {
|
|
437
|
+
const items = getCollection2(collection);
|
|
438
|
+
const item = { ...data, id: crypto.randomUUID() };
|
|
439
|
+
items.push(item);
|
|
440
|
+
saveCollection2(collection, items);
|
|
441
|
+
return item;
|
|
442
|
+
},
|
|
443
|
+
async get(collection, id) {
|
|
444
|
+
const found = getCollection2(collection).find((item) => item.id === id);
|
|
445
|
+
return found ?? null;
|
|
446
|
+
},
|
|
447
|
+
async update(collection, id, data) {
|
|
448
|
+
const items = getCollection2(collection);
|
|
449
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
450
|
+
if (idx === -1) return null;
|
|
451
|
+
Object.assign(items[idx], data);
|
|
452
|
+
saveCollection2(collection, items);
|
|
453
|
+
return items[idx];
|
|
454
|
+
},
|
|
455
|
+
async delete(collection, id) {
|
|
456
|
+
const items = getCollection2(collection);
|
|
457
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
458
|
+
if (idx === -1) return false;
|
|
459
|
+
items.splice(idx, 1);
|
|
460
|
+
saveCollection2(collection, items);
|
|
461
|
+
return true;
|
|
462
|
+
},
|
|
463
|
+
async list(collection, options) {
|
|
464
|
+
let items = getCollection2(collection);
|
|
465
|
+
if (options?.orderBy) {
|
|
466
|
+
const dir = options.order === "desc" ? -1 : 1;
|
|
467
|
+
items.sort((a, b) => {
|
|
468
|
+
const av = a[options.orderBy], bv = b[options.orderBy];
|
|
469
|
+
return av < bv ? -dir : av > bv ? dir : 0;
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
if (options?.offset) items = items.slice(options.offset);
|
|
473
|
+
if (options?.limit) items = items.slice(0, options.limit);
|
|
474
|
+
return items;
|
|
475
|
+
},
|
|
476
|
+
async query(collection, filter) {
|
|
477
|
+
return getCollection2(collection).filter((item) => matchesFilter(item, filter));
|
|
478
|
+
},
|
|
479
|
+
async count(collection, filter) {
|
|
480
|
+
const items = getCollection2(collection);
|
|
481
|
+
if (!filter || filter.length === 0) return items.length;
|
|
482
|
+
return items.filter((item) => matchesFilter(item, filter)).length;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/db/localStorage.ts
|
|
488
|
+
var DB_PREFIX = "geenius_db_";
|
|
489
|
+
function getCollection(collection) {
|
|
490
|
+
try {
|
|
491
|
+
return JSON.parse(localStorage.getItem(DB_PREFIX + collection) || "[]");
|
|
492
|
+
} catch {
|
|
493
|
+
return [];
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function saveCollection(collection, data) {
|
|
497
|
+
localStorage.setItem(DB_PREFIX + collection, JSON.stringify(data));
|
|
498
|
+
}
|
|
499
|
+
function matchesCondition2(item, cond) {
|
|
500
|
+
const val = item[cond.field];
|
|
501
|
+
switch (cond.operator) {
|
|
502
|
+
case "eq":
|
|
503
|
+
return val === cond.value;
|
|
504
|
+
case "neq":
|
|
505
|
+
return val !== cond.value;
|
|
506
|
+
case "gt":
|
|
507
|
+
return val > cond.value;
|
|
508
|
+
case "gte":
|
|
509
|
+
return val >= cond.value;
|
|
510
|
+
case "lt":
|
|
511
|
+
return val < cond.value;
|
|
512
|
+
case "lte":
|
|
513
|
+
return val <= cond.value;
|
|
514
|
+
case "in":
|
|
515
|
+
return Array.isArray(cond.value) && cond.value.includes(val);
|
|
516
|
+
case "contains":
|
|
517
|
+
return typeof val === "string" && val.includes(cond.value);
|
|
518
|
+
default:
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function matchesFilter2(item, filter) {
|
|
523
|
+
return filter.every((cond) => matchesCondition2(item, cond));
|
|
524
|
+
}
|
|
525
|
+
function createLocalStorageDbAdapter() {
|
|
526
|
+
if (typeof window === "undefined") {
|
|
527
|
+
return createMemoryDbAdapter();
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
async create(collection, data) {
|
|
531
|
+
const items = getCollection(collection);
|
|
532
|
+
const item = { ...data, id: crypto.randomUUID() };
|
|
533
|
+
items.push(item);
|
|
534
|
+
saveCollection(collection, items);
|
|
535
|
+
return item;
|
|
536
|
+
},
|
|
537
|
+
async get(collection, id) {
|
|
538
|
+
const found = getCollection(collection).find((item) => item.id === id);
|
|
539
|
+
return found ?? null;
|
|
540
|
+
},
|
|
541
|
+
async update(collection, id, data) {
|
|
542
|
+
const items = getCollection(collection);
|
|
543
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
544
|
+
if (idx === -1) return null;
|
|
545
|
+
Object.assign(items[idx], data);
|
|
546
|
+
saveCollection(collection, items);
|
|
547
|
+
return items[idx];
|
|
548
|
+
},
|
|
549
|
+
async delete(collection, id) {
|
|
550
|
+
const items = getCollection(collection);
|
|
551
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
552
|
+
if (idx === -1) return false;
|
|
553
|
+
items.splice(idx, 1);
|
|
554
|
+
saveCollection(collection, items);
|
|
555
|
+
return true;
|
|
556
|
+
},
|
|
557
|
+
async list(collection, options) {
|
|
558
|
+
let items = getCollection(collection);
|
|
559
|
+
if (options?.orderBy) {
|
|
560
|
+
const dir = options.order === "desc" ? -1 : 1;
|
|
561
|
+
items.sort((a, b) => {
|
|
562
|
+
const av = a[options.orderBy], bv = b[options.orderBy];
|
|
563
|
+
return av < bv ? -dir : av > bv ? dir : 0;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
if (options?.offset) items = items.slice(options.offset);
|
|
567
|
+
if (options?.limit) items = items.slice(0, options.limit);
|
|
568
|
+
return items;
|
|
569
|
+
},
|
|
570
|
+
async query(collection, filter) {
|
|
571
|
+
return getCollection(collection).filter((item) => matchesFilter2(item, filter));
|
|
572
|
+
},
|
|
573
|
+
async count(collection, filter) {
|
|
574
|
+
const items = getCollection(collection);
|
|
575
|
+
if (!filter || filter.length === 0) return items.length;
|
|
576
|
+
return items.filter((item) => matchesFilter2(item, filter)).length;
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/db/convex.ts
|
|
582
|
+
function createConvexDbAdapter(options) {
|
|
583
|
+
const { client, functions } = options;
|
|
584
|
+
function getFns(collection) {
|
|
585
|
+
const fns = functions[collection];
|
|
586
|
+
if (!fns) throw new DbError(`No Convex functions configured for collection: ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
587
|
+
return fns;
|
|
588
|
+
}
|
|
589
|
+
function matchesFilter4(item, filter) {
|
|
590
|
+
return filter.every((cond) => {
|
|
591
|
+
const val = item[cond.field];
|
|
592
|
+
switch (cond.operator) {
|
|
593
|
+
case "eq":
|
|
594
|
+
return val === cond.value;
|
|
595
|
+
case "neq":
|
|
596
|
+
return val !== cond.value;
|
|
597
|
+
case "gt":
|
|
598
|
+
return val > cond.value;
|
|
599
|
+
case "gte":
|
|
600
|
+
return val >= cond.value;
|
|
601
|
+
case "lt":
|
|
602
|
+
return val < cond.value;
|
|
603
|
+
case "lte":
|
|
604
|
+
return val <= cond.value;
|
|
605
|
+
case "in":
|
|
606
|
+
return Array.isArray(cond.value) && cond.value.includes(val);
|
|
607
|
+
case "contains":
|
|
608
|
+
return typeof val === "string" && val.includes(cond.value);
|
|
609
|
+
default:
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
async create(collection, data) {
|
|
616
|
+
const fns = getFns(collection);
|
|
617
|
+
if (!fns.create) throw new DbError(`No create function for ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
618
|
+
const id = await client.mutation(fns.create, data);
|
|
619
|
+
return { ...data, id };
|
|
620
|
+
},
|
|
621
|
+
async get(collection, id) {
|
|
622
|
+
const fns = getFns(collection);
|
|
623
|
+
if (!fns.get) throw new DbError(`No get function for ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
624
|
+
const doc = await client.query(fns.get, { id });
|
|
625
|
+
if (!doc) return null;
|
|
626
|
+
return { ...doc, id: doc._id || id };
|
|
627
|
+
},
|
|
628
|
+
async update(collection, id, data) {
|
|
629
|
+
const fns = getFns(collection);
|
|
630
|
+
if (!fns.update) throw new DbError(`No update function for ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
631
|
+
await client.mutation(fns.update, { id, ...data });
|
|
632
|
+
return this.get(collection, id);
|
|
633
|
+
},
|
|
634
|
+
async delete(collection, id) {
|
|
635
|
+
const fns = getFns(collection);
|
|
636
|
+
if (!fns.delete) throw new DbError(`No delete function for ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
637
|
+
try {
|
|
638
|
+
await client.mutation(fns.delete, { id });
|
|
639
|
+
return true;
|
|
640
|
+
} catch (err) {
|
|
641
|
+
throw new DbError(`Delete from "${collection}" failed`, "QUERY_ERROR", err);
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
async list(collection, options2) {
|
|
645
|
+
const fns = getFns(collection);
|
|
646
|
+
if (!fns.list) throw new DbError(`No list function for ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
647
|
+
const docs = await client.query(fns.list, {
|
|
648
|
+
limit: options2?.limit,
|
|
649
|
+
offset: options2?.offset,
|
|
650
|
+
orderBy: options2?.orderBy,
|
|
651
|
+
order: options2?.order
|
|
652
|
+
});
|
|
653
|
+
return (docs || []).map((d) => ({ ...d, id: d._id || d.id }));
|
|
654
|
+
},
|
|
655
|
+
async query(collection, filter) {
|
|
656
|
+
const fns = getFns(collection);
|
|
657
|
+
if (!fns.query) {
|
|
658
|
+
const all = await this.list(collection);
|
|
659
|
+
return all.filter((item) => matchesFilter4(item, filter));
|
|
660
|
+
}
|
|
661
|
+
const docs = await client.query(fns.query, { filter });
|
|
662
|
+
return (docs || []).map((d) => ({ ...d, id: d._id || d.id }));
|
|
663
|
+
},
|
|
664
|
+
async count(collection, filter) {
|
|
665
|
+
const fns = getFns(collection);
|
|
666
|
+
if (fns.count) {
|
|
667
|
+
return client.query(fns.count, filter ? { filter } : void 0);
|
|
668
|
+
}
|
|
669
|
+
const items = filter ? await this.query(collection, filter) : await this.list(collection);
|
|
670
|
+
return items.length;
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// src/db/neon.ts
|
|
676
|
+
function createNeonDbAdapter(options) {
|
|
677
|
+
const { client, tables, operators: ops } = options;
|
|
678
|
+
function getTable(collection) {
|
|
679
|
+
const table = tables[collection];
|
|
680
|
+
if (!table) throw new DbError(`No table configured for collection: ${collection}`, "COLLECTION_NOT_CONFIGURED");
|
|
681
|
+
return table;
|
|
682
|
+
}
|
|
683
|
+
function buildConditions(table, filter) {
|
|
684
|
+
return filter.map((cond) => {
|
|
685
|
+
const col = table[cond.field];
|
|
686
|
+
if (!col) throw new DbError(`Column ${cond.field} not found in table`, "QUERY_ERROR");
|
|
687
|
+
switch (cond.operator) {
|
|
688
|
+
case "eq":
|
|
689
|
+
return ops.eq(col, cond.value);
|
|
690
|
+
case "neq":
|
|
691
|
+
return ops.ne(col, cond.value);
|
|
692
|
+
case "gt":
|
|
693
|
+
return ops.gt(col, cond.value);
|
|
694
|
+
case "gte":
|
|
695
|
+
return ops.gte(col, cond.value);
|
|
696
|
+
case "lt":
|
|
697
|
+
return ops.lt(col, cond.value);
|
|
698
|
+
case "lte":
|
|
699
|
+
return ops.lte(col, cond.value);
|
|
700
|
+
case "in":
|
|
701
|
+
return ops.inArray(col, cond.value);
|
|
702
|
+
case "contains":
|
|
703
|
+
return ops.like(col, `%${cond.value}%`);
|
|
704
|
+
default:
|
|
705
|
+
throw new DbError(`Unsupported operator: ${cond.operator}`, "QUERY_ERROR");
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
return {
|
|
710
|
+
async create(collection, data) {
|
|
711
|
+
const table = getTable(collection);
|
|
712
|
+
try {
|
|
713
|
+
const [result] = await client.insert(table).values(data).returning();
|
|
714
|
+
return result;
|
|
715
|
+
} catch (err) {
|
|
716
|
+
throw new DbError(`Insert into "${collection}" failed`, "QUERY_ERROR", err);
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
async get(collection, id) {
|
|
720
|
+
const table = getTable(collection);
|
|
721
|
+
try {
|
|
722
|
+
const [result] = await client.select().from(table).where(ops.eq(table.id, id)).limit(1);
|
|
723
|
+
return result ?? null;
|
|
724
|
+
} catch (err) {
|
|
725
|
+
throw new DbError(`Get from "${collection}" failed`, "QUERY_ERROR", err);
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
async update(collection, id, data) {
|
|
729
|
+
const table = getTable(collection);
|
|
730
|
+
try {
|
|
731
|
+
const [result] = await client.update(table).set(data).where(ops.eq(table.id, id)).returning();
|
|
732
|
+
return result ?? null;
|
|
733
|
+
} catch (err) {
|
|
734
|
+
throw new DbError(`Update in "${collection}" failed`, "QUERY_ERROR", err);
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
async delete(collection, id) {
|
|
738
|
+
const table = getTable(collection);
|
|
739
|
+
try {
|
|
740
|
+
const result = await client.delete(table).where(ops.eq(table.id, id)).returning();
|
|
741
|
+
return Array.isArray(result) && result.length > 0;
|
|
742
|
+
} catch (err) {
|
|
743
|
+
throw new DbError(`Delete from "${collection}" failed`, "QUERY_ERROR", err);
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
async list(collection, options2) {
|
|
747
|
+
const table = getTable(collection);
|
|
748
|
+
let query = client.select().from(table);
|
|
749
|
+
if (options2?.orderBy) {
|
|
750
|
+
const col = table[options2.orderBy];
|
|
751
|
+
if (col) {
|
|
752
|
+
query = query.orderBy(options2.order === "desc" ? ops.desc(col) : ops.asc(col));
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if (options2?.limit) query = query.limit(options2.limit);
|
|
756
|
+
if (options2?.offset) query = query.offset(options2.offset);
|
|
757
|
+
return query;
|
|
758
|
+
},
|
|
759
|
+
async query(collection, filter) {
|
|
760
|
+
const table = getTable(collection);
|
|
761
|
+
if (filter.length === 0) {
|
|
762
|
+
return client.select().from(table);
|
|
763
|
+
}
|
|
764
|
+
const conditions = buildConditions(table, filter);
|
|
765
|
+
return client.select().from(table).where(ops.and(...conditions));
|
|
766
|
+
},
|
|
767
|
+
async count(collection, filter) {
|
|
768
|
+
const table = getTable(collection);
|
|
769
|
+
if (!filter || filter.length === 0) {
|
|
770
|
+
const [result2] = await client.select({ count: ops.count() }).from(table);
|
|
771
|
+
return Number(result2?.count ?? 0);
|
|
772
|
+
}
|
|
773
|
+
const conditions = buildConditions(table, filter);
|
|
774
|
+
const [result] = await client.select({ count: ops.count() }).from(table).where(ops.and(...conditions));
|
|
775
|
+
return Number(result?.count ?? 0);
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/db/supabase.ts
|
|
781
|
+
function createSupabaseDbAdapter(options) {
|
|
782
|
+
const { client, tableNames = {} } = options;
|
|
783
|
+
function tableName(collection) {
|
|
784
|
+
return tableNames[collection] || collection;
|
|
785
|
+
}
|
|
786
|
+
return {
|
|
787
|
+
async create(collection, data) {
|
|
788
|
+
const { data: result, error } = await client.from(tableName(collection)).insert(data).select().single();
|
|
789
|
+
if (error) throw new DbError(`Insert into "${collection}" failed: ${error.message}`, "QUERY_ERROR", error);
|
|
790
|
+
return result;
|
|
791
|
+
},
|
|
792
|
+
async get(collection, id) {
|
|
793
|
+
const { data, error } = await client.from(tableName(collection)).select().eq("id", id).single();
|
|
794
|
+
if (error) return null;
|
|
795
|
+
return data;
|
|
796
|
+
},
|
|
797
|
+
async update(collection, id, data) {
|
|
798
|
+
const { data: result, error } = await client.from(tableName(collection)).update(data).eq("id", id).select().single();
|
|
799
|
+
if (error) return null;
|
|
800
|
+
return result;
|
|
801
|
+
},
|
|
802
|
+
async delete(collection, id) {
|
|
803
|
+
const { error } = await client.from(tableName(collection)).delete().eq("id", id);
|
|
804
|
+
return !error;
|
|
805
|
+
},
|
|
806
|
+
async list(collection, options2) {
|
|
807
|
+
let query = client.from(tableName(collection)).select();
|
|
808
|
+
if (options2?.orderBy) {
|
|
809
|
+
query = query.order(options2.orderBy, {
|
|
810
|
+
ascending: options2.order !== "desc"
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
if (options2?.offset !== void 0 && options2?.limit !== void 0) {
|
|
814
|
+
query = query.range(options2.offset, options2.offset + options2.limit - 1);
|
|
815
|
+
} else if (options2?.limit) {
|
|
816
|
+
query = query.limit(options2.limit);
|
|
817
|
+
}
|
|
818
|
+
const { data, error } = await query;
|
|
819
|
+
if (error) throw new DbError(`List "${collection}" failed: ${error.message}`, "QUERY_ERROR", error);
|
|
820
|
+
return data || [];
|
|
821
|
+
},
|
|
822
|
+
async query(collection, filter) {
|
|
823
|
+
let query = client.from(tableName(collection)).select();
|
|
824
|
+
for (const cond of filter) {
|
|
825
|
+
switch (cond.operator) {
|
|
826
|
+
case "eq":
|
|
827
|
+
query = query.eq(cond.field, cond.value);
|
|
828
|
+
break;
|
|
829
|
+
case "neq":
|
|
830
|
+
query = query.neq(cond.field, cond.value);
|
|
831
|
+
break;
|
|
832
|
+
case "gt":
|
|
833
|
+
query = query.gt(cond.field, cond.value);
|
|
834
|
+
break;
|
|
835
|
+
case "gte":
|
|
836
|
+
query = query.gte(cond.field, cond.value);
|
|
837
|
+
break;
|
|
838
|
+
case "lt":
|
|
839
|
+
query = query.lt(cond.field, cond.value);
|
|
840
|
+
break;
|
|
841
|
+
case "lte":
|
|
842
|
+
query = query.lte(cond.field, cond.value);
|
|
843
|
+
break;
|
|
844
|
+
case "in":
|
|
845
|
+
query = query.in(cond.field, cond.value);
|
|
846
|
+
break;
|
|
847
|
+
case "contains":
|
|
848
|
+
query = query.ilike(cond.field, `%${cond.value}%`);
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
const { data, error } = await query;
|
|
853
|
+
if (error) throw new DbError(`Query "${collection}" failed: ${error.message}`, "QUERY_ERROR", error);
|
|
854
|
+
return data || [];
|
|
855
|
+
},
|
|
856
|
+
async count(collection, filter) {
|
|
857
|
+
if (!filter || filter.length === 0) {
|
|
858
|
+
const { data } = await client.from(tableName(collection)).select("id");
|
|
859
|
+
return data?.length ?? 0;
|
|
860
|
+
}
|
|
861
|
+
const items = await this.query(collection, filter);
|
|
862
|
+
return items.length;
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// src/db/mongodb.ts
|
|
868
|
+
function createMongoDbAdapter(options) {
|
|
869
|
+
const { db, collectionNames = {} } = options;
|
|
870
|
+
function col(collection) {
|
|
871
|
+
return db.collection(collectionNames[collection] || collection);
|
|
872
|
+
}
|
|
873
|
+
function buildMongoFilter(filter) {
|
|
874
|
+
const mongoFilter = {};
|
|
875
|
+
for (const cond of filter) {
|
|
876
|
+
switch (cond.operator) {
|
|
877
|
+
case "eq":
|
|
878
|
+
mongoFilter[cond.field] = cond.value;
|
|
879
|
+
break;
|
|
880
|
+
case "neq":
|
|
881
|
+
mongoFilter[cond.field] = { $ne: cond.value };
|
|
882
|
+
break;
|
|
883
|
+
case "gt":
|
|
884
|
+
mongoFilter[cond.field] = { $gt: cond.value };
|
|
885
|
+
break;
|
|
886
|
+
case "gte":
|
|
887
|
+
mongoFilter[cond.field] = { $gte: cond.value };
|
|
888
|
+
break;
|
|
889
|
+
case "lt":
|
|
890
|
+
mongoFilter[cond.field] = { $lt: cond.value };
|
|
891
|
+
break;
|
|
892
|
+
case "lte":
|
|
893
|
+
mongoFilter[cond.field] = { $lte: cond.value };
|
|
894
|
+
break;
|
|
895
|
+
case "in":
|
|
896
|
+
mongoFilter[cond.field] = { $in: cond.value };
|
|
897
|
+
break;
|
|
898
|
+
case "contains":
|
|
899
|
+
mongoFilter[cond.field] = { $regex: cond.value, $options: "i" };
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return mongoFilter;
|
|
904
|
+
}
|
|
905
|
+
function stripMongoId(doc) {
|
|
906
|
+
const { _id, ...rest } = doc;
|
|
907
|
+
return rest;
|
|
908
|
+
}
|
|
909
|
+
return {
|
|
910
|
+
async create(collection, data) {
|
|
911
|
+
const id = crypto.randomUUID();
|
|
912
|
+
const doc = { ...data, id };
|
|
913
|
+
try {
|
|
914
|
+
await col(collection).insertOne(doc);
|
|
915
|
+
} catch (err) {
|
|
916
|
+
throw new DbError(`Insert into "${collection}" failed`, "QUERY_ERROR", err);
|
|
917
|
+
}
|
|
918
|
+
return doc;
|
|
919
|
+
},
|
|
920
|
+
async get(collection, id) {
|
|
921
|
+
const doc = await col(collection).findOne({ id });
|
|
922
|
+
if (!doc) return null;
|
|
923
|
+
return stripMongoId(doc);
|
|
924
|
+
},
|
|
925
|
+
async update(collection, id, data) {
|
|
926
|
+
try {
|
|
927
|
+
await col(collection).updateOne({ id }, { $set: data });
|
|
928
|
+
} catch (err) {
|
|
929
|
+
throw new DbError(`Update in "${collection}" failed`, "QUERY_ERROR", err);
|
|
930
|
+
}
|
|
931
|
+
return this.get(collection, id);
|
|
932
|
+
},
|
|
933
|
+
async delete(collection, id) {
|
|
934
|
+
const result = await col(collection).deleteOne({ id });
|
|
935
|
+
return result.deletedCount > 0;
|
|
936
|
+
},
|
|
937
|
+
async list(collection, options2) {
|
|
938
|
+
let cursor = col(collection).find();
|
|
939
|
+
if (options2?.orderBy) {
|
|
940
|
+
cursor = cursor.sort({ [options2.orderBy]: options2.order === "desc" ? -1 : 1 });
|
|
941
|
+
}
|
|
942
|
+
if (options2?.offset) cursor = cursor.skip(options2.offset);
|
|
943
|
+
if (options2?.limit) cursor = cursor.limit(options2.limit);
|
|
944
|
+
const docs = await cursor.toArray();
|
|
945
|
+
return docs.map(stripMongoId);
|
|
946
|
+
},
|
|
947
|
+
async query(collection, filter) {
|
|
948
|
+
const mongoFilter = buildMongoFilter(filter);
|
|
949
|
+
const docs = await col(collection).find(mongoFilter).toArray();
|
|
950
|
+
return docs.map(stripMongoId);
|
|
951
|
+
},
|
|
952
|
+
async count(collection, filter) {
|
|
953
|
+
const mongoFilter = filter ? buildMongoFilter(filter) : {};
|
|
954
|
+
return col(collection).countDocuments(mongoFilter);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// src/db/cloudflareKV.ts
|
|
960
|
+
var DB_PREFIX2 = "geenius_db_";
|
|
961
|
+
function matchesCondition3(item, cond) {
|
|
962
|
+
const val = item[cond.field];
|
|
963
|
+
switch (cond.operator) {
|
|
964
|
+
case "eq":
|
|
965
|
+
return val === cond.value;
|
|
966
|
+
case "neq":
|
|
967
|
+
return val !== cond.value;
|
|
968
|
+
case "gt":
|
|
969
|
+
return val > cond.value;
|
|
970
|
+
case "gte":
|
|
971
|
+
return val >= cond.value;
|
|
972
|
+
case "lt":
|
|
973
|
+
return val < cond.value;
|
|
974
|
+
case "lte":
|
|
975
|
+
return val <= cond.value;
|
|
976
|
+
case "in":
|
|
977
|
+
return Array.isArray(cond.value) && cond.value.includes(val);
|
|
978
|
+
case "contains":
|
|
979
|
+
return typeof val === "string" && val.includes(cond.value);
|
|
980
|
+
default:
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function matchesFilter3(item, filter) {
|
|
985
|
+
return filter.every((cond) => matchesCondition3(item, cond));
|
|
986
|
+
}
|
|
987
|
+
function createCloudflareKVDbAdapter(kv) {
|
|
988
|
+
async function getCollection2(collection) {
|
|
989
|
+
try {
|
|
990
|
+
const data = await kv.get(DB_PREFIX2 + collection, "json");
|
|
991
|
+
return data || [];
|
|
992
|
+
} catch (err) {
|
|
993
|
+
throw new DbError(`Failed to read collection "${collection}" from KV`, "CONNECTION_ERROR", err);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
async function saveCollection2(collection, data) {
|
|
997
|
+
try {
|
|
998
|
+
await kv.put(DB_PREFIX2 + collection, JSON.stringify(data));
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
throw new DbError(`Failed to write collection "${collection}" to KV`, "CONNECTION_ERROR", err);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
async create(collection, data) {
|
|
1005
|
+
const items = await getCollection2(collection);
|
|
1006
|
+
const item = { ...data, id: crypto.randomUUID() };
|
|
1007
|
+
items.push(item);
|
|
1008
|
+
await saveCollection2(collection, items);
|
|
1009
|
+
return item;
|
|
1010
|
+
},
|
|
1011
|
+
async get(collection, id) {
|
|
1012
|
+
const items = await getCollection2(collection);
|
|
1013
|
+
const found = items.find((item) => item.id === id);
|
|
1014
|
+
return found ?? null;
|
|
1015
|
+
},
|
|
1016
|
+
async update(collection, id, data) {
|
|
1017
|
+
const items = await getCollection2(collection);
|
|
1018
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
1019
|
+
if (idx === -1) return null;
|
|
1020
|
+
Object.assign(items[idx], data);
|
|
1021
|
+
await saveCollection2(collection, items);
|
|
1022
|
+
return items[idx];
|
|
1023
|
+
},
|
|
1024
|
+
async delete(collection, id) {
|
|
1025
|
+
const items = await getCollection2(collection);
|
|
1026
|
+
const idx = items.findIndex((item) => item.id === id);
|
|
1027
|
+
if (idx === -1) return false;
|
|
1028
|
+
items.splice(idx, 1);
|
|
1029
|
+
await saveCollection2(collection, items);
|
|
1030
|
+
return true;
|
|
1031
|
+
},
|
|
1032
|
+
async list(collection, options) {
|
|
1033
|
+
let items = await getCollection2(collection);
|
|
1034
|
+
if (options?.orderBy) {
|
|
1035
|
+
const dir = options.order === "desc" ? -1 : 1;
|
|
1036
|
+
items.sort((a, b) => {
|
|
1037
|
+
const av = a[options.orderBy], bv = b[options.orderBy];
|
|
1038
|
+
return av < bv ? -dir : av > bv ? dir : 0;
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
if (options?.offset) items = items.slice(options.offset);
|
|
1042
|
+
if (options?.limit) items = items.slice(0, options.limit);
|
|
1043
|
+
return items;
|
|
1044
|
+
},
|
|
1045
|
+
async query(collection, filter) {
|
|
1046
|
+
const items = await getCollection2(collection);
|
|
1047
|
+
return items.filter((item) => matchesFilter3(item, filter));
|
|
1048
|
+
},
|
|
1049
|
+
async count(collection, filter) {
|
|
1050
|
+
const items = await getCollection2(collection);
|
|
1051
|
+
if (!filter || filter.length === 0) return items.length;
|
|
1052
|
+
return items.filter((item) => matchesFilter3(item, filter)).length;
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// src/payments/localStorage.ts
|
|
1058
|
+
var SUBS_KEY = "geenius_subscriptions";
|
|
1059
|
+
var PLANS_KEY = "geenius_plans";
|
|
1060
|
+
var DEFAULT_PLANS = [
|
|
1061
|
+
{ id: "free", name: "Free", price: 0, currency: "USD", interval: "month", features: ["Basic features", "1 project", "Community support"] },
|
|
1062
|
+
{ id: "pro", name: "Pro", price: 29, currency: "USD", interval: "month", features: ["All Free features", "Unlimited projects", "Priority support", "AI features"] },
|
|
1063
|
+
{ id: "team", name: "Team", price: 79, currency: "USD", interval: "month", features: ["All Pro features", "Team management", "Admin dashboard", "Custom integrations"] }
|
|
1064
|
+
];
|
|
1065
|
+
function getSubs() {
|
|
1066
|
+
try {
|
|
1067
|
+
return JSON.parse(localStorage.getItem(SUBS_KEY) || "[]");
|
|
1068
|
+
} catch {
|
|
1069
|
+
return [];
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
function saveSubs(subs) {
|
|
1073
|
+
localStorage.setItem(SUBS_KEY, JSON.stringify(subs));
|
|
1074
|
+
}
|
|
1075
|
+
function createLocalStoragePaymentsAdapter() {
|
|
1076
|
+
if (!localStorage.getItem(PLANS_KEY)) {
|
|
1077
|
+
localStorage.setItem(PLANS_KEY, JSON.stringify(DEFAULT_PLANS));
|
|
1078
|
+
}
|
|
1079
|
+
return {
|
|
1080
|
+
async createCheckout(params) {
|
|
1081
|
+
const subs = getSubs();
|
|
1082
|
+
const sub = {
|
|
1083
|
+
id: crypto.randomUUID(),
|
|
1084
|
+
userId: params.userId,
|
|
1085
|
+
planId: params.planId,
|
|
1086
|
+
status: "active",
|
|
1087
|
+
currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3).toISOString(),
|
|
1088
|
+
cancelAtPeriodEnd: false
|
|
1089
|
+
};
|
|
1090
|
+
subs.push(sub);
|
|
1091
|
+
saveSubs(subs);
|
|
1092
|
+
return { url: params.successUrl || "/", sessionId: sub.id };
|
|
1093
|
+
},
|
|
1094
|
+
async getSubscription(userId) {
|
|
1095
|
+
const sub = getSubs().find((s) => s.userId === userId && s.status === "active");
|
|
1096
|
+
return sub ?? null;
|
|
1097
|
+
},
|
|
1098
|
+
async cancelSubscription(subscriptionId) {
|
|
1099
|
+
const subs = getSubs();
|
|
1100
|
+
const idx = subs.findIndex((s) => s.id === subscriptionId);
|
|
1101
|
+
if (idx !== -1) {
|
|
1102
|
+
subs[idx].cancelAtPeriodEnd = true;
|
|
1103
|
+
subs[idx].status = "cancelled";
|
|
1104
|
+
saveSubs(subs);
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
async getPlans() {
|
|
1108
|
+
try {
|
|
1109
|
+
return JSON.parse(localStorage.getItem(PLANS_KEY) || "[]");
|
|
1110
|
+
} catch {
|
|
1111
|
+
return DEFAULT_PLANS;
|
|
1112
|
+
}
|
|
1113
|
+
},
|
|
1114
|
+
async isFeatureEnabled(userId, feature) {
|
|
1115
|
+
const sub = await this.getSubscription(userId);
|
|
1116
|
+
if (!sub) return false;
|
|
1117
|
+
const plans = await this.getPlans();
|
|
1118
|
+
const plan = plans.find((p) => p.id === sub.planId);
|
|
1119
|
+
return plan?.features.includes(feature) ?? false;
|
|
1120
|
+
}
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
function createNoopPaymentsAdapter() {
|
|
1124
|
+
return {
|
|
1125
|
+
async createCheckout() {
|
|
1126
|
+
throw new Error("Payments not available in Pronto tier. Upgrade to Lancio.");
|
|
1127
|
+
},
|
|
1128
|
+
async getSubscription() {
|
|
1129
|
+
return null;
|
|
1130
|
+
},
|
|
1131
|
+
async cancelSubscription() {
|
|
1132
|
+
},
|
|
1133
|
+
async getPlans() {
|
|
1134
|
+
return [];
|
|
1135
|
+
},
|
|
1136
|
+
async isFeatureEnabled() {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// src/ai/localStorage.ts
|
|
1143
|
+
var HISTORY_KEY = "geenius_ai_history";
|
|
1144
|
+
var CANNED_RESPONSES = [
|
|
1145
|
+
"That's an interesting question! In the Pronto tier, AI responses are simulated. Upgrade to MVP for real AI.",
|
|
1146
|
+
"I'm a mock AI assistant. I can demonstrate the chat interface, but for real responses you'll need the MVP tier.",
|
|
1147
|
+
"Great question! This is a localStorage-based AI mock. The real AI adapter connects to OpenAI/Anthropic APIs.",
|
|
1148
|
+
"I appreciate your input! This demo shows how the AI interface works. Upgrade for actual AI capabilities.",
|
|
1149
|
+
"Interesting! While I can't provide real AI analysis in Pronto, this shows the adapter pattern in action."
|
|
1150
|
+
];
|
|
1151
|
+
function getCannedResponse(messages) {
|
|
1152
|
+
const lastMsg = messages[messages.length - 1]?.content || "";
|
|
1153
|
+
let hash = 0;
|
|
1154
|
+
for (let i = 0; i < lastMsg.length; i++) {
|
|
1155
|
+
hash = (hash << 5) - hash + lastMsg.charCodeAt(i);
|
|
1156
|
+
hash |= 0;
|
|
1157
|
+
}
|
|
1158
|
+
return CANNED_RESPONSES[Math.abs(hash) % CANNED_RESPONSES.length];
|
|
1159
|
+
}
|
|
1160
|
+
function saveToHistory(messages, response) {
|
|
1161
|
+
try {
|
|
1162
|
+
const history = JSON.parse(localStorage.getItem(HISTORY_KEY) || "[]");
|
|
1163
|
+
history.push({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), messages, response });
|
|
1164
|
+
if (history.length > 50) history.splice(0, history.length - 50);
|
|
1165
|
+
localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
|
|
1166
|
+
} catch {
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
function createLocalStorageAiAdapter() {
|
|
1170
|
+
return {
|
|
1171
|
+
async chat(messages, _options) {
|
|
1172
|
+
await new Promise((r) => setTimeout(r, 300 + Math.random() * 700));
|
|
1173
|
+
const content = getCannedResponse(messages);
|
|
1174
|
+
saveToHistory(messages, content);
|
|
1175
|
+
return {
|
|
1176
|
+
content,
|
|
1177
|
+
finishReason: "stop",
|
|
1178
|
+
usage: { promptTokens: 10, completionTokens: 20, totalTokens: 30 }
|
|
1179
|
+
};
|
|
1180
|
+
},
|
|
1181
|
+
async complete(prompt, options) {
|
|
1182
|
+
const response = await this.chat([{ role: "user", content: prompt }], options);
|
|
1183
|
+
return response.content;
|
|
1184
|
+
},
|
|
1185
|
+
async embed(text) {
|
|
1186
|
+
const inputs = Array.isArray(text) ? text : [text];
|
|
1187
|
+
return inputs.map((t) => {
|
|
1188
|
+
const vec = [];
|
|
1189
|
+
for (let i = 0; i < 8; i++) {
|
|
1190
|
+
let h = i * 31;
|
|
1191
|
+
for (let j = 0; j < t.length; j++) {
|
|
1192
|
+
h = (h << 5) - h + t.charCodeAt(j);
|
|
1193
|
+
h |= 0;
|
|
1194
|
+
}
|
|
1195
|
+
vec.push(Math.sin(h) * 0.5 + 0.5);
|
|
1196
|
+
}
|
|
1197
|
+
return vec;
|
|
1198
|
+
});
|
|
1199
|
+
},
|
|
1200
|
+
async *stream(messages, _options) {
|
|
1201
|
+
const content = getCannedResponse(messages);
|
|
1202
|
+
saveToHistory(messages, content);
|
|
1203
|
+
const words = content.split(" ");
|
|
1204
|
+
for (const word of words) {
|
|
1205
|
+
await new Promise((r) => setTimeout(r, 40 + Math.random() * 60));
|
|
1206
|
+
yield word + " ";
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// src/storage/localStorage.ts
|
|
1213
|
+
var FILES_KEY = "geenius_files";
|
|
1214
|
+
var BLOBS_PREFIX = "geenius_blob_";
|
|
1215
|
+
function getFiles() {
|
|
1216
|
+
try {
|
|
1217
|
+
return JSON.parse(localStorage.getItem(FILES_KEY) || "[]");
|
|
1218
|
+
} catch {
|
|
1219
|
+
return [];
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function saveFiles(files) {
|
|
1223
|
+
localStorage.setItem(FILES_KEY, JSON.stringify(files));
|
|
1224
|
+
}
|
|
1225
|
+
function blobToBase64(blob) {
|
|
1226
|
+
return new Promise((resolve, reject) => {
|
|
1227
|
+
const reader = new FileReader();
|
|
1228
|
+
reader.onload = () => resolve(reader.result);
|
|
1229
|
+
reader.onerror = reject;
|
|
1230
|
+
reader.readAsDataURL(blob);
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
function base64ToBlob(dataUrl) {
|
|
1234
|
+
const [meta, data] = dataUrl.split(",");
|
|
1235
|
+
const mime = meta.match(/:(.*?);/)?.[1] || "application/octet-stream";
|
|
1236
|
+
const bytes = atob(data);
|
|
1237
|
+
const buffer = new Uint8Array(bytes.length);
|
|
1238
|
+
for (let i = 0; i < bytes.length; i++) buffer[i] = bytes.charCodeAt(i);
|
|
1239
|
+
return new Blob([buffer], { type: mime });
|
|
1240
|
+
}
|
|
1241
|
+
function createLocalStorageFileAdapter() {
|
|
1242
|
+
return {
|
|
1243
|
+
async upload(file, path, name) {
|
|
1244
|
+
const base64 = await blobToBase64(file);
|
|
1245
|
+
const id = crypto.randomUUID();
|
|
1246
|
+
const blobKey = BLOBS_PREFIX + id;
|
|
1247
|
+
localStorage.setItem(blobKey, base64);
|
|
1248
|
+
const entry = {
|
|
1249
|
+
id,
|
|
1250
|
+
name: name || (file instanceof File ? file.name : `file-${id.slice(0, 8)}`),
|
|
1251
|
+
path,
|
|
1252
|
+
size: file.size,
|
|
1253
|
+
mimeType: file.type || "application/octet-stream",
|
|
1254
|
+
url: `local://${id}`,
|
|
1255
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1256
|
+
blobKey
|
|
1257
|
+
};
|
|
1258
|
+
const files = getFiles();
|
|
1259
|
+
files.push(entry);
|
|
1260
|
+
saveFiles(files);
|
|
1261
|
+
const { blobKey: _, ...storedFile } = entry;
|
|
1262
|
+
return storedFile;
|
|
1263
|
+
},
|
|
1264
|
+
async download(fileId) {
|
|
1265
|
+
const entry = getFiles().find((f) => f.id === fileId);
|
|
1266
|
+
if (!entry) throw new Error(`File not found: ${fileId}`);
|
|
1267
|
+
const base64 = localStorage.getItem(entry.blobKey);
|
|
1268
|
+
if (!base64) throw new Error(`Blob data missing for file: ${fileId}`);
|
|
1269
|
+
return base64ToBlob(base64);
|
|
1270
|
+
},
|
|
1271
|
+
async delete(fileId) {
|
|
1272
|
+
const files = getFiles();
|
|
1273
|
+
const idx = files.findIndex((f) => f.id === fileId);
|
|
1274
|
+
if (idx === -1) return false;
|
|
1275
|
+
localStorage.removeItem(files[idx].blobKey);
|
|
1276
|
+
files.splice(idx, 1);
|
|
1277
|
+
saveFiles(files);
|
|
1278
|
+
return true;
|
|
1279
|
+
},
|
|
1280
|
+
async list(prefix) {
|
|
1281
|
+
let files = getFiles();
|
|
1282
|
+
if (prefix) files = files.filter((f) => f.path.startsWith(prefix));
|
|
1283
|
+
return files.map(({ blobKey: _, ...f }) => f);
|
|
1284
|
+
},
|
|
1285
|
+
async getUrl(fileId) {
|
|
1286
|
+
const entry = getFiles().find((f) => f.id === fileId);
|
|
1287
|
+
if (!entry) throw new Error(`File not found: ${fileId}`);
|
|
1288
|
+
const base64 = localStorage.getItem(entry.blobKey);
|
|
1289
|
+
return base64 || entry.url;
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// src/admin/localStorage.ts
|
|
1295
|
+
var USERS_KEY2 = "geenius_auth_users";
|
|
1296
|
+
function createLocalStorageAdminAdapter() {
|
|
1297
|
+
function getUsers2() {
|
|
1298
|
+
try {
|
|
1299
|
+
const data = localStorage.getItem(USERS_KEY2);
|
|
1300
|
+
if (!data) return [];
|
|
1301
|
+
const raw = JSON.parse(data);
|
|
1302
|
+
return Object.values(raw).map((u) => ({
|
|
1303
|
+
id: u.id,
|
|
1304
|
+
email: u.email,
|
|
1305
|
+
name: u.name,
|
|
1306
|
+
image: u.image,
|
|
1307
|
+
role: u.role || "user",
|
|
1308
|
+
isActive: true,
|
|
1309
|
+
isBanned: u.isBanned || false,
|
|
1310
|
+
plan: u.plan || "free",
|
|
1311
|
+
createdAt: u.createdAt,
|
|
1312
|
+
lastLoginAt: u.lastLoginAt
|
|
1313
|
+
}));
|
|
1314
|
+
} catch {
|
|
1315
|
+
return [];
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return {
|
|
1319
|
+
async listUsers(options) {
|
|
1320
|
+
let users = getUsers2();
|
|
1321
|
+
if (options?.search) {
|
|
1322
|
+
const q = options.search.toLowerCase();
|
|
1323
|
+
users = users.filter(
|
|
1324
|
+
(u) => u.email?.toLowerCase().includes(q) || u.name?.toLowerCase().includes(q)
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
const offset = options?.offset || 0;
|
|
1328
|
+
const limit = options?.limit || 50;
|
|
1329
|
+
return users.slice(offset, offset + limit);
|
|
1330
|
+
},
|
|
1331
|
+
async getUser(id) {
|
|
1332
|
+
const users = getUsers2();
|
|
1333
|
+
return users.find((u) => u.id === id) || null;
|
|
1334
|
+
},
|
|
1335
|
+
async banUser(id) {
|
|
1336
|
+
try {
|
|
1337
|
+
const data = JSON.parse(localStorage.getItem(USERS_KEY2) || "{}");
|
|
1338
|
+
if (data[id]) {
|
|
1339
|
+
data[id].isBanned = true;
|
|
1340
|
+
localStorage.setItem(USERS_KEY2, JSON.stringify(data));
|
|
1341
|
+
return true;
|
|
1342
|
+
}
|
|
1343
|
+
return false;
|
|
1344
|
+
} catch {
|
|
1345
|
+
return false;
|
|
1346
|
+
}
|
|
1347
|
+
},
|
|
1348
|
+
async unbanUser(id) {
|
|
1349
|
+
try {
|
|
1350
|
+
const data = JSON.parse(localStorage.getItem(USERS_KEY2) || "{}");
|
|
1351
|
+
if (data[id]) {
|
|
1352
|
+
data[id].isBanned = false;
|
|
1353
|
+
localStorage.setItem(USERS_KEY2, JSON.stringify(data));
|
|
1354
|
+
return true;
|
|
1355
|
+
}
|
|
1356
|
+
return false;
|
|
1357
|
+
} catch {
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
1360
|
+
},
|
|
1361
|
+
async deleteUser(id) {
|
|
1362
|
+
try {
|
|
1363
|
+
const data = JSON.parse(localStorage.getItem(USERS_KEY2) || "{}");
|
|
1364
|
+
if (data[id]) {
|
|
1365
|
+
delete data[id];
|
|
1366
|
+
localStorage.setItem(USERS_KEY2, JSON.stringify(data));
|
|
1367
|
+
return true;
|
|
1368
|
+
}
|
|
1369
|
+
return false;
|
|
1370
|
+
} catch {
|
|
1371
|
+
return false;
|
|
1372
|
+
}
|
|
1373
|
+
},
|
|
1374
|
+
async getMetrics() {
|
|
1375
|
+
const users = getUsers2();
|
|
1376
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1377
|
+
const newToday = users.filter(
|
|
1378
|
+
(u) => u.createdAt && u.createdAt.startsWith(today)
|
|
1379
|
+
).length;
|
|
1380
|
+
return {
|
|
1381
|
+
totalUsers: users.length,
|
|
1382
|
+
activeUsers: users.filter((u) => u.isActive && !u.isBanned).length,
|
|
1383
|
+
newUsersToday: newToday
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// src/tier-gate.ts
|
|
1390
|
+
var DEFAULT_TIER_GATE = {
|
|
1391
|
+
features: {
|
|
1392
|
+
pronto: [
|
|
1393
|
+
"auth",
|
|
1394
|
+
"i18n",
|
|
1395
|
+
"ai-chat"
|
|
1396
|
+
],
|
|
1397
|
+
lancio: [
|
|
1398
|
+
"auth",
|
|
1399
|
+
"i18n",
|
|
1400
|
+
"ai-chat",
|
|
1401
|
+
"admin",
|
|
1402
|
+
"payments",
|
|
1403
|
+
"blog",
|
|
1404
|
+
"file-storage",
|
|
1405
|
+
"ai-workflow",
|
|
1406
|
+
"ai-embeddings"
|
|
1407
|
+
],
|
|
1408
|
+
studio: [
|
|
1409
|
+
"auth",
|
|
1410
|
+
"i18n",
|
|
1411
|
+
"ai-chat",
|
|
1412
|
+
"admin",
|
|
1413
|
+
"payments",
|
|
1414
|
+
"blog",
|
|
1415
|
+
"file-storage",
|
|
1416
|
+
"ai-workflow",
|
|
1417
|
+
"ai-embeddings",
|
|
1418
|
+
"ai-magic",
|
|
1419
|
+
"analytics",
|
|
1420
|
+
"emails",
|
|
1421
|
+
"teams",
|
|
1422
|
+
"feature-flags",
|
|
1423
|
+
"docs",
|
|
1424
|
+
"monitoring",
|
|
1425
|
+
"notifications",
|
|
1426
|
+
"jobs",
|
|
1427
|
+
"changelog",
|
|
1428
|
+
"roadmap",
|
|
1429
|
+
"waitlist",
|
|
1430
|
+
"seo",
|
|
1431
|
+
"onboarding",
|
|
1432
|
+
"feedback",
|
|
1433
|
+
"pricing",
|
|
1434
|
+
"search"
|
|
1435
|
+
]
|
|
1436
|
+
},
|
|
1437
|
+
packages: {
|
|
1438
|
+
pronto: [
|
|
1439
|
+
"@geenius/adapters",
|
|
1440
|
+
"@geenius/auth",
|
|
1441
|
+
"@geenius/i18n",
|
|
1442
|
+
"@geenius/config",
|
|
1443
|
+
"@geenius/tools",
|
|
1444
|
+
"@geenius/ui"
|
|
1445
|
+
],
|
|
1446
|
+
lancio: [
|
|
1447
|
+
"@geenius/adapters",
|
|
1448
|
+
"@geenius/auth",
|
|
1449
|
+
"@geenius/i18n",
|
|
1450
|
+
"@geenius/config",
|
|
1451
|
+
"@geenius/tools",
|
|
1452
|
+
"@geenius/ui",
|
|
1453
|
+
"@geenius/admin",
|
|
1454
|
+
"@geenius/payments",
|
|
1455
|
+
"@geenius/stripe",
|
|
1456
|
+
"@geenius/blog",
|
|
1457
|
+
"@geenius/file-storage",
|
|
1458
|
+
"@geenius/ai"
|
|
1459
|
+
],
|
|
1460
|
+
studio: [
|
|
1461
|
+
"@geenius/adapters",
|
|
1462
|
+
"@geenius/auth",
|
|
1463
|
+
"@geenius/i18n",
|
|
1464
|
+
"@geenius/config",
|
|
1465
|
+
"@geenius/tools",
|
|
1466
|
+
"@geenius/ui",
|
|
1467
|
+
"@geenius/admin",
|
|
1468
|
+
"@geenius/payments",
|
|
1469
|
+
"@geenius/stripe",
|
|
1470
|
+
"@geenius/blog",
|
|
1471
|
+
"@geenius/file-storage",
|
|
1472
|
+
"@geenius/ai",
|
|
1473
|
+
"@geenius/ai-magic",
|
|
1474
|
+
"@geenius/ai-workflow",
|
|
1475
|
+
"@geenius/analytics",
|
|
1476
|
+
"@geenius/emails",
|
|
1477
|
+
"@geenius/teams",
|
|
1478
|
+
"@geenius/feature-flags",
|
|
1479
|
+
"@geenius/docs",
|
|
1480
|
+
"@geenius/monitoring",
|
|
1481
|
+
"@geenius/notifications",
|
|
1482
|
+
"@geenius/jobs",
|
|
1483
|
+
"@geenius/changelog",
|
|
1484
|
+
"@geenius/roadmap",
|
|
1485
|
+
"@geenius/waitlist",
|
|
1486
|
+
"@geenius/seo",
|
|
1487
|
+
"@geenius/onboarding",
|
|
1488
|
+
"@geenius/feedback",
|
|
1489
|
+
"@geenius/pricing",
|
|
1490
|
+
"@geenius/search",
|
|
1491
|
+
"@geenius/agent"
|
|
1492
|
+
]
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
function isFeatureAvailable(feature, tier) {
|
|
1496
|
+
return DEFAULT_TIER_GATE.features[tier]?.includes(feature) ?? false;
|
|
1497
|
+
}
|
|
1498
|
+
function isPackageAvailable(pkg, tier) {
|
|
1499
|
+
return DEFAULT_TIER_GATE.packages[tier]?.includes(pkg) ?? false;
|
|
1500
|
+
}
|
|
1501
|
+
function getAvailableFeatures(tier) {
|
|
1502
|
+
return DEFAULT_TIER_GATE.features[tier] || [];
|
|
1503
|
+
}
|
|
1504
|
+
function getAvailablePackages(tier) {
|
|
1505
|
+
return DEFAULT_TIER_GATE.packages[tier] || [];
|
|
1506
|
+
}
|
|
1507
|
+
function getUpgradeFeatures(currentTier, targetTier) {
|
|
1508
|
+
const current = new Set(DEFAULT_TIER_GATE.features[currentTier] || []);
|
|
1509
|
+
const target = DEFAULT_TIER_GATE.features[targetTier] || [];
|
|
1510
|
+
return target.filter((f) => !current.has(f));
|
|
1511
|
+
}
|
|
1512
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1513
|
+
0 && (module.exports = {
|
|
1514
|
+
ADAPTER_DOMAINS,
|
|
1515
|
+
ADAPTER_STATUSES,
|
|
1516
|
+
ADMIN_PROVIDERS,
|
|
1517
|
+
AI_PROVIDERS,
|
|
1518
|
+
AUTH_PROVIDERS,
|
|
1519
|
+
AdapterError,
|
|
1520
|
+
AdminError,
|
|
1521
|
+
AiError,
|
|
1522
|
+
AuthError,
|
|
1523
|
+
DB_PROVIDERS,
|
|
1524
|
+
DEFAULT_TIER_GATE,
|
|
1525
|
+
DOMAIN_DESCRIPTIONS,
|
|
1526
|
+
DOMAIN_ICONS,
|
|
1527
|
+
DOMAIN_LABELS,
|
|
1528
|
+
DbError,
|
|
1529
|
+
PAYMENT_PROVIDERS,
|
|
1530
|
+
PROVIDER_REGISTRY,
|
|
1531
|
+
PaymentsError,
|
|
1532
|
+
STORAGE_PROVIDERS,
|
|
1533
|
+
StorageError,
|
|
1534
|
+
clearResolvers,
|
|
1535
|
+
configureAdapters,
|
|
1536
|
+
createCloudflareKVDbAdapter,
|
|
1537
|
+
createConvexDbAdapter,
|
|
1538
|
+
createLocalStorageAdminAdapter,
|
|
1539
|
+
createLocalStorageAiAdapter,
|
|
1540
|
+
createLocalStorageAuthAdapter,
|
|
1541
|
+
createLocalStorageDbAdapter,
|
|
1542
|
+
createLocalStorageFileAdapter,
|
|
1543
|
+
createLocalStoragePaymentsAdapter,
|
|
1544
|
+
createMemoryDbAdapter,
|
|
1545
|
+
createMongoDbAdapter,
|
|
1546
|
+
createNeonDbAdapter,
|
|
1547
|
+
createNoopPaymentsAdapter,
|
|
1548
|
+
createSupabaseDbAdapter,
|
|
1549
|
+
getAdapterConfig,
|
|
1550
|
+
getAvailableFeatures,
|
|
1551
|
+
getAvailablePackages,
|
|
1552
|
+
getDomainConfig,
|
|
1553
|
+
getProviderMeta,
|
|
1554
|
+
getProvidersForDomain,
|
|
1555
|
+
getUpgradeFeatures,
|
|
1556
|
+
hasResolver,
|
|
1557
|
+
isAdapterError,
|
|
1558
|
+
isAdaptersConfigured,
|
|
1559
|
+
isFeatureAvailable,
|
|
1560
|
+
isPackageAvailable,
|
|
1561
|
+
isRetryable,
|
|
1562
|
+
registerResolver,
|
|
1563
|
+
resetAdapterConfig,
|
|
1564
|
+
resolveAdapter,
|
|
1565
|
+
withRetry
|
|
1566
|
+
});
|
|
1567
|
+
//# sourceMappingURL=index.js.map
|