@agentsean/hosted 1.0.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 (54) hide show
  1. package/LICENSE +661 -0
  2. package/dist/billing.d.ts +40 -0
  3. package/dist/billing.d.ts.map +1 -0
  4. package/dist/billing.js +142 -0
  5. package/dist/billing.js.map +1 -0
  6. package/dist/connector.d.ts +22 -0
  7. package/dist/connector.d.ts.map +1 -0
  8. package/dist/connector.js +65 -0
  9. package/dist/connector.js.map +1 -0
  10. package/dist/cost.d.ts +15 -0
  11. package/dist/cost.d.ts.map +1 -0
  12. package/dist/cost.js +38 -0
  13. package/dist/cost.js.map +1 -0
  14. package/dist/engine.d.ts +47 -0
  15. package/dist/engine.d.ts.map +1 -0
  16. package/dist/engine.js +62 -0
  17. package/dist/engine.js.map +1 -0
  18. package/dist/entitlements.d.ts +8 -0
  19. package/dist/entitlements.d.ts.map +1 -0
  20. package/dist/entitlements.js +33 -0
  21. package/dist/entitlements.js.map +1 -0
  22. package/dist/envelope.d.ts +9 -0
  23. package/dist/envelope.d.ts.map +1 -0
  24. package/dist/envelope.js +72 -0
  25. package/dist/envelope.js.map +1 -0
  26. package/dist/erasure.d.ts +27 -0
  27. package/dist/erasure.d.ts.map +1 -0
  28. package/dist/erasure.js +54 -0
  29. package/dist/erasure.js.map +1 -0
  30. package/dist/index.d.ts +13 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +13 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/neighbour.d.ts +13 -0
  35. package/dist/neighbour.d.ts.map +1 -0
  36. package/dist/neighbour.js +76 -0
  37. package/dist/neighbour.js.map +1 -0
  38. package/dist/oauth.d.ts +5 -0
  39. package/dist/oauth.d.ts.map +1 -0
  40. package/dist/oauth.js +35 -0
  41. package/dist/oauth.js.map +1 -0
  42. package/dist/plans.d.ts +29 -0
  43. package/dist/plans.d.ts.map +1 -0
  44. package/dist/plans.js +110 -0
  45. package/dist/plans.js.map +1 -0
  46. package/dist/tenants.d.ts +48 -0
  47. package/dist/tenants.d.ts.map +1 -0
  48. package/dist/tenants.js +121 -0
  49. package/dist/tenants.js.map +1 -0
  50. package/dist/tracing.d.ts +11 -0
  51. package/dist/tracing.d.ts.map +1 -0
  52. package/dist/tracing.js +9 -0
  53. package/dist/tracing.js.map +1 -0
  54. package/package.json +52 -0
@@ -0,0 +1,40 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ import { type PlanId } from "./plans.js";
3
+ export type StripeEvent = {
4
+ id: string;
5
+ type: string;
6
+ data: {
7
+ object: Record<string, unknown>;
8
+ };
9
+ };
10
+ export type StripeLike = {
11
+ createCheckoutSession: (opts: {
12
+ tenantId: string;
13
+ plan: PlanId;
14
+ email: string;
15
+ interval: "month" | "year";
16
+ }) => Promise<{
17
+ id: string;
18
+ url: string;
19
+ }>;
20
+ reportMeteredUsage?: ((opts: {
21
+ tenantId: string;
22
+ quantity: number;
23
+ period: string;
24
+ }) => Promise<void>) | undefined;
25
+ };
26
+ export declare function fakeStripe(baseUrl?: string): StripeLike;
27
+ export declare function applyStripeEvent(db: SqliteDatabase, event: StripeEvent, now?: Date): {
28
+ duplicate: boolean;
29
+ tenantId: string | null;
30
+ };
31
+ export declare function activateSubscription(db: SqliteDatabase, opts: {
32
+ tenantId: string;
33
+ plan: PlanId;
34
+ customerId: string | null;
35
+ subscriptionId: string | null;
36
+ now?: Date | undefined;
37
+ }): void;
38
+ export declare function reportArticleUsage(db: SqliteDatabase, tenantId: string, quantity?: number, now?: Date, stripe?: StripeLike | undefined): void;
39
+ export declare function articlesThisMonth(db: SqliteDatabase, tenantId: string, now?: Date): number;
40
+ //# sourceMappingURL=billing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAY,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,qBAAqB,EAAE,CAAC,IAAI,EAAE;QAC5B,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;KAC5B,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3C,kBAAkB,CAAC,EACf,CAAC,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GACjF,SAAS,CAAC;CACf,CAAC;AAEF,wBAAgB,UAAU,CAAC,OAAO,SAAiC,GAAG,UAAU,CAY/E;AAOD,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,WAAW,EAClB,GAAG,OAAa,GACf;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAmEjD;AAWD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CACxB,GACA,IAAI,CA0BN;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,SAAI,EACZ,GAAG,OAAa,EAChB,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,GAC9B,IAAI,CAaN;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,EAChB,GAAG,OAAa,GACf,MAAM,CASR"}
@@ -0,0 +1,142 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { eq } from "drizzle-orm";
3
+ import { meteredUsage, stripeEvents, subscriptions, tenants, } from "@agentsean/db";
4
+ import { isPlanId } from "./plans.js";
5
+ export function fakeStripe(baseUrl = "https://checkout.stripe.test") {
6
+ return {
7
+ async createCheckoutSession(opts) {
8
+ return {
9
+ id: `cs_test_${opts.tenantId}`,
10
+ url: `${baseUrl}/c/pay/${opts.plan}?tenant=${opts.tenantId}`,
11
+ };
12
+ },
13
+ async reportMeteredUsage() {
14
+ return;
15
+ },
16
+ };
17
+ }
18
+ function str(obj, key) {
19
+ const v = obj[key];
20
+ return typeof v === "string" ? v : undefined;
21
+ }
22
+ export function applyStripeEvent(db, event, now = new Date()) {
23
+ const existing = db
24
+ .select()
25
+ .from(stripeEvents)
26
+ .where(eq(stripeEvents.id, event.id))
27
+ .get();
28
+ if (existing)
29
+ return { duplicate: true, tenantId: null };
30
+ db.insert(stripeEvents)
31
+ .values({
32
+ id: event.id,
33
+ type: event.type,
34
+ payload: JSON.stringify(event.data.object),
35
+ processedAt: now.toISOString(),
36
+ })
37
+ .run();
38
+ const obj = event.data.object;
39
+ const tenantId = str(obj, "client_reference_id") ?? str(obj, "tenantId") ?? null;
40
+ const planRaw = str(obj, "plan") ?? metadataPlan(obj);
41
+ const customer = str(obj, "customer");
42
+ const subscription = str(obj, "subscription") ?? str(obj, "id");
43
+ if (event.type === "checkout.session.completed" &&
44
+ tenantId &&
45
+ planRaw &&
46
+ isPlanId(planRaw)) {
47
+ activateSubscription(db, {
48
+ tenantId,
49
+ plan: planRaw,
50
+ customerId: customer ?? null,
51
+ subscriptionId: subscription ?? null,
52
+ now,
53
+ });
54
+ return { duplicate: false, tenantId };
55
+ }
56
+ if (event.type === "customer.subscription.updated" &&
57
+ tenantId &&
58
+ planRaw &&
59
+ isPlanId(planRaw)) {
60
+ activateSubscription(db, {
61
+ tenantId,
62
+ plan: planRaw,
63
+ customerId: customer ?? null,
64
+ subscriptionId: subscription ?? null,
65
+ now,
66
+ });
67
+ return { duplicate: false, tenantId };
68
+ }
69
+ if (event.type === "customer.subscription.deleted" && tenantId) {
70
+ db.update(tenants)
71
+ .set({ status: "canceled", updatedAt: now.toISOString() })
72
+ .where(eq(tenants.id, tenantId))
73
+ .run();
74
+ return { duplicate: false, tenantId };
75
+ }
76
+ if (event.type === "invoice.payment_failed" && tenantId) {
77
+ db.update(tenants)
78
+ .set({ status: "past_due", updatedAt: now.toISOString() })
79
+ .where(eq(tenants.id, tenantId))
80
+ .run();
81
+ return { duplicate: false, tenantId };
82
+ }
83
+ return { duplicate: false, tenantId };
84
+ }
85
+ function metadataPlan(obj) {
86
+ const meta = obj["metadata"];
87
+ if (meta && typeof meta === "object" && !Array.isArray(meta) && "plan" in meta) {
88
+ const p = meta.plan;
89
+ return typeof p === "string" ? p : undefined;
90
+ }
91
+ return undefined;
92
+ }
93
+ export function activateSubscription(db, opts) {
94
+ const now = (opts.now ?? new Date()).toISOString();
95
+ db.update(tenants)
96
+ .set({
97
+ plan: opts.plan,
98
+ status: "active",
99
+ stripeCustomerId: opts.customerId,
100
+ stripeSubscriptionId: opts.subscriptionId,
101
+ updatedAt: now,
102
+ })
103
+ .where(eq(tenants.id, opts.tenantId))
104
+ .run();
105
+ db.insert(subscriptions)
106
+ .values({
107
+ id: randomUUID(),
108
+ tenantId: opts.tenantId,
109
+ plan: opts.plan,
110
+ interval: "month",
111
+ status: "active",
112
+ currentPeriodEnd: new Date((opts.now ?? new Date()).getTime() + 30 * 86400000).toISOString(),
113
+ createdAt: now,
114
+ updatedAt: now,
115
+ })
116
+ .run();
117
+ }
118
+ export function reportArticleUsage(db, tenantId, quantity = 1, now = new Date(), stripe) {
119
+ const period = now.toISOString().slice(0, 7);
120
+ db.insert(meteredUsage)
121
+ .values({
122
+ id: randomUUID(),
123
+ tenantId,
124
+ kind: "article",
125
+ quantity,
126
+ period,
127
+ createdAt: now.toISOString(),
128
+ })
129
+ .run();
130
+ void stripe?.reportMeteredUsage?.({ tenantId, quantity, period });
131
+ }
132
+ export function articlesThisMonth(db, tenantId, now = new Date()) {
133
+ const period = now.toISOString().slice(0, 7);
134
+ return db
135
+ .select()
136
+ .from(meteredUsage)
137
+ .where(eq(meteredUsage.tenantId, tenantId))
138
+ .all()
139
+ .filter((r) => r.period === period && r.kind === "article")
140
+ .reduce((s, r) => s + r.quantity, 0);
141
+ }
142
+ //# sourceMappingURL=billing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing.js","sourceRoot":"","sources":["../src/billing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ /** CMS write kinds the hosted control plane must never store. */
3
+ export declare const CMS_WRITE_KINDS: readonly ["wordpress", "shopify", "webflow", "ghost", "wix", "bigcommerce", "contentful", "sanity", "strapi", "payload", "cloudflare", "git"];
4
+ export declare class HostedCredentialError extends Error {
5
+ readonly name = "HostedCredentialError";
6
+ }
7
+ export declare function isCmsWriteKind(kind: string): boolean;
8
+ export declare function refuseHostedCmsCredential(kind: string): never;
9
+ export declare function createConnectorPairing(db: SqliteDatabase, tenantId: string, siteId: string | null, now?: Date): {
10
+ id: string;
11
+ token: string;
12
+ };
13
+ export declare function activateConnector(db: SqliteDatabase, token: string): boolean;
14
+ export declare function listConnectors(db: SqliteDatabase, tenantId: string): {
15
+ id: string;
16
+ tenantId: string;
17
+ siteId: string | null;
18
+ tokenHash: string;
19
+ status: string;
20
+ createdAt: string;
21
+ }[];
22
+ //# sourceMappingURL=connector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAEvE,iEAAiE;AACjE,eAAO,MAAM,eAAe,+IAalB,CAAC;AAEX,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,SAAkB,IAAI,2BAA2B;CAClD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAI7D;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,GAAG,OAAa,GACf;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAc/B;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAa5E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM;;;;;;;IAMlE"}
@@ -0,0 +1,65 @@
1
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
2
+ import { eq } from "drizzle-orm";
3
+ import { connectorPairings } from "@agentsean/db";
4
+ /** CMS write kinds the hosted control plane must never store. */
5
+ export const CMS_WRITE_KINDS = [
6
+ "wordpress",
7
+ "shopify",
8
+ "webflow",
9
+ "ghost",
10
+ "wix",
11
+ "bigcommerce",
12
+ "contentful",
13
+ "sanity",
14
+ "strapi",
15
+ "payload",
16
+ "cloudflare",
17
+ "git",
18
+ ];
19
+ export class HostedCredentialError extends Error {
20
+ name = "HostedCredentialError";
21
+ }
22
+ export function isCmsWriteKind(kind) {
23
+ return CMS_WRITE_KINDS.includes(kind);
24
+ }
25
+ export function refuseHostedCmsCredential(kind) {
26
+ throw new HostedCredentialError(`Hosted Sean will not store ${kind} write credentials. Pair a customer-side connector; the customer's own daemon holds the key.`);
27
+ }
28
+ export function createConnectorPairing(db, tenantId, siteId, now = new Date()) {
29
+ const token = randomBytes(24).toString("base64url");
30
+ const id = randomUUID();
31
+ db.insert(connectorPairings)
32
+ .values({
33
+ id,
34
+ tenantId,
35
+ siteId,
36
+ tokenHash: createHash("sha256").update(token).digest("hex"),
37
+ status: "pending",
38
+ createdAt: now.toISOString(),
39
+ })
40
+ .run();
41
+ return { id, token };
42
+ }
43
+ export function activateConnector(db, token) {
44
+ const hash = createHash("sha256").update(token).digest("hex");
45
+ const row = db
46
+ .select()
47
+ .from(connectorPairings)
48
+ .all()
49
+ .find((r) => r.tokenHash === hash);
50
+ if (!row)
51
+ return false;
52
+ db.update(connectorPairings)
53
+ .set({ status: "active" })
54
+ .where(eq(connectorPairings.id, row.id))
55
+ .run();
56
+ return true;
57
+ }
58
+ export function listConnectors(db, tenantId) {
59
+ return db
60
+ .select()
61
+ .from(connectorPairings)
62
+ .where(eq(connectorPairings.tenantId, tenantId))
63
+ .all();
64
+ }
65
+ //# sourceMappingURL=connector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connector.js","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAuB,MAAM,eAAe,CAAC;AAEvE,iEAAiE;AACjE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,WAAW;IACX,SAAS;IACT,SAAS;IACT,OAAO;IACP,KAAK;IACL,aAAa;IACb,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,KAAK;CACG,CAAC;AAEX,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5B,IAAI,GAAG,uBAAuB,CAAC;CAClD;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAQ,eAAqC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,MAAM,IAAI,qBAAqB,CAC7B,8BAA8B,IAAI,8FAA8F,CACjI,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,EAAkB,EAClB,QAAgB,EAChB,MAAqB,EACrB,GAAG,GAAG,IAAI,IAAI,EAAE;IAEhB,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IACxB,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC;SACzB,MAAM,CAAC;QACN,EAAE;QACF,QAAQ;QACR,MAAM;QACN,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAC3D,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;KAC7B,CAAC;SACD,GAAG,EAAE,CAAC;IACT,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAkB,EAAE,KAAa;IACjE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,EAAE;SACX,MAAM,EAAE;SACR,IAAI,CAAC,iBAAiB,CAAC;SACvB,GAAG,EAAE;SACL,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC;SACzB,GAAG,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;SACzB,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;SACvC,GAAG,EAAE,CAAC;IACT,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,QAAgB;IACjE,OAAO,EAAE;SACN,MAAM,EAAE;SACR,IAAI,CAAC,iBAAiB,CAAC;SACvB,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SAC/C,GAAG,EAAE,CAAC;AACX,CAAC"}
package/dist/cost.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ export type TenantCost = {
3
+ tenantId: string;
4
+ plan: string;
5
+ sites: number;
6
+ siteCap: number;
7
+ ledgerUsd: number;
8
+ cogsUsd: number;
9
+ revenueUsd: number;
10
+ margin: number;
11
+ articles: number;
12
+ byok: boolean;
13
+ };
14
+ export declare function tenantCostVisibility(db: SqliteDatabase, tenantId: string, now?: Date): TenantCost;
15
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAK7E,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,EAChB,GAAG,OAAa,GACf,UAAU,CA6BZ"}
package/dist/cost.js ADDED
@@ -0,0 +1,38 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { costLedger, tenantSites } from "@agentsean/db";
3
+ import { NON_LLM_COGS_USD, planOf } from "./plans.js";
4
+ import { getTenant, tenantSiteCount } from "./tenants.js";
5
+ import { articlesThisMonth } from "./billing.js";
6
+ export function tenantCostVisibility(db, tenantId, now = new Date()) {
7
+ const tenant = getTenant(db, tenantId);
8
+ if (!tenant)
9
+ throw new Error("unknown_tenant");
10
+ const plan = planOf(tenant.plan);
11
+ const links = db
12
+ .select()
13
+ .from(tenantSites)
14
+ .where(eq(tenantSites.tenantId, tenantId))
15
+ .all();
16
+ const siteIds = new Set(links.map((l) => l.siteId));
17
+ let ledgerUsd = 0;
18
+ for (const row of db.select().from(costLedger).all()) {
19
+ if (row.siteId && siteIds.has(row.siteId))
20
+ ledgerUsd += row.costUsd;
21
+ }
22
+ const sites = tenantSiteCount(db, tenantId);
23
+ const revenueUsd = plan.priceUsdMonth;
24
+ const cogsUsd = NON_LLM_COGS_USD + ledgerUsd;
25
+ return {
26
+ tenantId,
27
+ plan: plan.id,
28
+ sites,
29
+ siteCap: plan.sites,
30
+ ledgerUsd,
31
+ cogsUsd,
32
+ revenueUsd,
33
+ margin: revenueUsd <= 0 ? 1 : (revenueUsd - cogsUsd) / revenueUsd,
34
+ articles: articlesThisMonth(db, tenantId, now),
35
+ byok: Boolean(tenant.byok),
36
+ };
37
+ }
38
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAuB,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAejD,MAAM,UAAU,oBAAoB,CAClC,EAAkB,EAClB,QAAgB,EAChB,GAAG,GAAG,IAAI,IAAI,EAAE;IAEhB,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,EAAE;SACb,MAAM,EAAE;SACR,IAAI,CAAC,WAAW,CAAC;SACjB,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;SACzC,GAAG,EAAE,CAAC;IACT,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,GAAG,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QACrD,IAAI,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC;IACtE,CAAC;IACD,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC;IACtC,MAAM,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC7C,OAAO;QACL,QAAQ;QACR,IAAI,EAAE,IAAI,CAAC,EAAE;QACb,KAAK;QACL,OAAO,EAAE,IAAI,CAAC,KAAK;QACnB,SAAS;QACT,OAAO;QACP,UAAU;QACV,MAAM,EAAE,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,UAAU;QACjE,QAAQ,EAAE,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,CAAC;QAC9C,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;KAC3B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { type PlanId } from "./plans.js";
2
+ import { addTenantSite } from "./tenants.js";
3
+ import { type StripeLike } from "./billing.js";
4
+ import type { SqliteDatabase } from "@agentsean/db";
5
+ export type SignupResult = {
6
+ tenantId: string;
7
+ plan: PlanId;
8
+ checkoutUrl: string;
9
+ };
10
+ export declare function signupTenant(db: SqliteDatabase, opts: {
11
+ name: string;
12
+ email: string;
13
+ plan: PlanId;
14
+ stripe?: StripeLike | undefined;
15
+ now?: Date | undefined;
16
+ }): Promise<SignupResult>;
17
+ /** Simulate (or apply) the paid webhook so the tenant can add sites. */
18
+ export declare function completeCheckout(db: SqliteDatabase, opts: {
19
+ tenantId: string;
20
+ plan: PlanId;
21
+ eventId?: string | undefined;
22
+ now?: Date | undefined;
23
+ }): void;
24
+ export declare function hostedStatus(db: SqliteDatabase, tenantId: string): {
25
+ tenant: {
26
+ id: string;
27
+ name: string;
28
+ email: string;
29
+ plan: string;
30
+ status: string;
31
+ stripeCustomerId: string | null;
32
+ stripeSubscriptionId: string | null;
33
+ byok: number;
34
+ createdAt: string;
35
+ updatedAt: string;
36
+ };
37
+ plan: import("./plans.js").Plan;
38
+ sites: {
39
+ id: string;
40
+ origin: string;
41
+ name: string | null;
42
+ }[];
43
+ cost: import("./cost.js").TenantCost;
44
+ googleRedirect: string | null;
45
+ } | null;
46
+ export { addTenantSite };
47
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAA4C,MAAM,cAAc,CAAC;AACvF,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,wBAAsB,YAAY,CAChC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CACxB,GACA,OAAO,CAAC,YAAY,CAAC,CAwBvB;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CACxB,GACA,IAAI,CAeN;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;SAWhE;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
package/dist/engine.js ADDED
@@ -0,0 +1,62 @@
1
+ import { isPlanId, PLANS } from "./plans.js";
2
+ import { addTenantSite, createTenant, getTenant, listTenantSites } from "./tenants.js";
3
+ import { applyStripeEvent, fakeStripe, } from "./billing.js";
4
+ import { tenantCostVisibility } from "./cost.js";
5
+ import { hostedOauthRedirectUri } from "./oauth.js";
6
+ export async function signupTenant(db, opts) {
7
+ if (opts.plan === "self_host") {
8
+ const tenant = createTenant(db, {
9
+ name: opts.name,
10
+ email: opts.email,
11
+ plan: "self_host",
12
+ now: opts.now,
13
+ });
14
+ return { tenantId: tenant.id, plan: "self_host", checkoutUrl: "" };
15
+ }
16
+ const tenant = createTenant(db, {
17
+ name: opts.name,
18
+ email: opts.email,
19
+ plan: opts.plan,
20
+ now: opts.now,
21
+ });
22
+ const stripe = opts.stripe ?? fakeStripe();
23
+ const session = await stripe.createCheckoutSession({
24
+ tenantId: tenant.id,
25
+ plan: opts.plan,
26
+ email: opts.email,
27
+ interval: "month",
28
+ });
29
+ return { tenantId: tenant.id, plan: opts.plan, checkoutUrl: session.url };
30
+ }
31
+ /** Simulate (or apply) the paid webhook so the tenant can add sites. */
32
+ export function completeCheckout(db, opts) {
33
+ const event = {
34
+ id: opts.eventId ?? `evt_${opts.tenantId}`,
35
+ type: "checkout.session.completed",
36
+ data: {
37
+ object: {
38
+ client_reference_id: opts.tenantId,
39
+ tenantId: opts.tenantId,
40
+ plan: opts.plan,
41
+ customer: `cus_${opts.tenantId}`,
42
+ subscription: `sub_${opts.tenantId}`,
43
+ },
44
+ },
45
+ };
46
+ applyStripeEvent(db, event, opts.now ?? new Date());
47
+ }
48
+ export function hostedStatus(db, tenantId) {
49
+ const tenant = getTenant(db, tenantId);
50
+ if (!tenant)
51
+ return null;
52
+ const plan = PLANS[isPlanId(tenant.plan) ? tenant.plan : "cloud_starter"];
53
+ return {
54
+ tenant,
55
+ plan,
56
+ sites: listTenantSites(db, tenantId),
57
+ cost: tenantCostVisibility(db, tenantId),
58
+ googleRedirect: hostedOauthRedirectUri(),
59
+ };
60
+ }
61
+ export { addTenantSite };
62
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type Plan, type PlanId } from "./plans.js";
2
+ export type EntitlementFeature = "aiVisibility" | "hostedOauth" | "whiteLabel" | "apiAccess" | "priorityQueue" | "clientSeats" | "bulkOps" | "dailyRanks";
3
+ export declare class EntitlementError extends Error {
4
+ readonly name = "EntitlementError";
5
+ }
6
+ export declare function hasFeature(plan: Plan, feature: EntitlementFeature): boolean;
7
+ export declare function assertEntitlement(planId: PlanId | string, feature: EntitlementFeature): void;
8
+ //# sourceMappingURL=entitlements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.d.ts","sourceRoot":"","sources":["../src/entitlements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,aAAa,GACb,YAAY,GACZ,WAAW,GACX,eAAe,GACf,aAAa,GACb,SAAS,GACT,YAAY,CAAC;AAEjB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;CAC7C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAmB3E;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,EAAE,kBAAkB,GAC1B,IAAI,CAKN"}
@@ -0,0 +1,33 @@
1
+ import { isHostedMode, planOf } from "./plans.js";
2
+ export class EntitlementError extends Error {
3
+ name = "EntitlementError";
4
+ }
5
+ export function hasFeature(plan, feature) {
6
+ switch (feature) {
7
+ case "aiVisibility":
8
+ return plan.aiVisibility;
9
+ case "hostedOauth":
10
+ return plan.hostedOauth;
11
+ case "whiteLabel":
12
+ return plan.whiteLabel;
13
+ case "apiAccess":
14
+ return plan.apiAccess;
15
+ case "priorityQueue":
16
+ return plan.priorityQueue;
17
+ case "clientSeats":
18
+ return plan.clientSeats;
19
+ case "bulkOps":
20
+ return plan.bulkOps;
21
+ case "dailyRanks":
22
+ return plan.ranks === "daily";
23
+ }
24
+ }
25
+ export function assertEntitlement(planId, feature) {
26
+ if (!isHostedMode())
27
+ return;
28
+ const plan = planOf(planId);
29
+ if (hasFeature(plan, feature))
30
+ return;
31
+ throw new EntitlementError(`${plan.name} does not include ${feature}.`);
32
+ }
33
+ //# sourceMappingURL=entitlements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entitlements.js","sourceRoot":"","sources":["../src/entitlements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAA0B,MAAM,YAAY,CAAC;AAY1E,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACvB,IAAI,GAAG,kBAAkB,CAAC;CAC7C;AAED,MAAM,UAAU,UAAU,CAAC,IAAU,EAAE,OAA2B;IAChE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,cAAc;YACjB,OAAO,IAAI,CAAC,YAAY,CAAC;QAC3B,KAAK,aAAa;YAChB,OAAO,IAAI,CAAC,WAAW,CAAC;QAC1B,KAAK,YAAY;YACf,OAAO,IAAI,CAAC,UAAU,CAAC;QACzB,KAAK,WAAW;YACd,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,KAAK,eAAe;YAClB,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,KAAK,aAAa;YAChB,OAAO,IAAI,CAAC,WAAW,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC,OAAO,CAAC;QACtB,KAAK,YAAY;YACf,OAAO,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAuB,EACvB,OAA2B;IAE3B,IAAI,CAAC,YAAY,EAAE;QAAE,OAAO;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;QAAE,OAAO;IACtC,MAAM,IAAI,gBAAgB,CAAC,GAAG,IAAI,CAAC,IAAI,qBAAqB,OAAO,GAAG,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ export declare class EnvelopeError extends Error {
3
+ readonly name = "EnvelopeError";
4
+ }
5
+ export declare function masterKeyFromEnv(env?: NodeJS.ProcessEnv): Buffer;
6
+ export declare function encryptSecret(dek: Buffer, plaintext: string): string;
7
+ export declare function decryptSecret(dek: Buffer, blob: string): string;
8
+ export declare function loadOrCreateDek(db: SqliteDatabase, tenantId: string, master: Buffer, now?: Date): Buffer;
9
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAIlE,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAkB,IAAI,mBAAmB;CAC1C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAS7E;AAoBD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/D;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,GAAG,OAAa,GACf,MAAM,CAiBR"}
@@ -0,0 +1,72 @@
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
2
+ import { randomUUID } from "node:crypto";
3
+ import { eq } from "drizzle-orm";
4
+ import { envelopeKeys } from "@agentsean/db";
5
+ const ALGO = "aes-256-gcm";
6
+ export class EnvelopeError extends Error {
7
+ name = "EnvelopeError";
8
+ }
9
+ export function masterKeyFromEnv(env = process.env) {
10
+ const raw = env["SEAN_KMS_KEY"]?.trim();
11
+ if (!raw) {
12
+ throw new EnvelopeError("SEAN_KMS_KEY is required to wrap per-tenant data keys.");
13
+ }
14
+ if (/^[0-9a-f]+$/i.test(raw) && raw.length === 64)
15
+ return Buffer.from(raw, "hex");
16
+ const buf = Buffer.from(raw, "base64");
17
+ if (buf.length === 32)
18
+ return buf;
19
+ return createHash("sha256").update(raw).digest();
20
+ }
21
+ function wrapDek(master, dek) {
22
+ const iv = randomBytes(12);
23
+ const cipher = createCipheriv(ALGO, master, iv);
24
+ const enc = Buffer.concat([cipher.update(dek), cipher.final()]);
25
+ const tag = cipher.getAuthTag();
26
+ return Buffer.concat([iv, tag, enc]).toString("base64url");
27
+ }
28
+ function unwrapDek(master, wrapped) {
29
+ const buf = Buffer.from(wrapped, "base64url");
30
+ const iv = buf.subarray(0, 12);
31
+ const tag = buf.subarray(12, 28);
32
+ const enc = buf.subarray(28);
33
+ const decipher = createDecipheriv(ALGO, master, iv);
34
+ decipher.setAuthTag(tag);
35
+ return Buffer.concat([decipher.update(enc), decipher.final()]);
36
+ }
37
+ export function encryptSecret(dek, plaintext) {
38
+ const iv = randomBytes(12);
39
+ const cipher = createCipheriv(ALGO, dek, iv);
40
+ const enc = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
41
+ const tag = cipher.getAuthTag();
42
+ return Buffer.concat([iv, tag, enc]).toString("base64url");
43
+ }
44
+ export function decryptSecret(dek, blob) {
45
+ const buf = Buffer.from(blob, "base64url");
46
+ const iv = buf.subarray(0, 12);
47
+ const tag = buf.subarray(12, 28);
48
+ const enc = buf.subarray(28);
49
+ const decipher = createDecipheriv(ALGO, dek, iv);
50
+ decipher.setAuthTag(tag);
51
+ return Buffer.concat([decipher.update(enc), decipher.final()]).toString("utf8");
52
+ }
53
+ export function loadOrCreateDek(db, tenantId, master, now = new Date()) {
54
+ const existing = db
55
+ .select()
56
+ .from(envelopeKeys)
57
+ .where(eq(envelopeKeys.tenantId, tenantId))
58
+ .get();
59
+ if (existing)
60
+ return unwrapDek(master, existing.wrappedDek);
61
+ const dek = randomBytes(32);
62
+ db.insert(envelopeKeys)
63
+ .values({
64
+ id: randomUUID(),
65
+ tenantId,
66
+ wrappedDek: wrapDek(master, dek),
67
+ createdAt: now.toISOString(),
68
+ })
69
+ .run();
70
+ return dek;
71
+ }
72
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}