@codelitdev/billing 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +339 -0
- package/dist/adapters/drizzle/index.d.ts +28 -0
- package/dist/adapters/drizzle/index.d.ts.map +1 -0
- package/dist/adapters/drizzle/index.js +75 -0
- package/dist/adapters/drizzle/index.js.map +1 -0
- package/dist/adapters/drizzle/store.d.ts +37 -0
- package/dist/adapters/drizzle/store.d.ts.map +1 -0
- package/dist/adapters/drizzle/store.js +889 -0
- package/dist/adapters/drizzle/store.js.map +1 -0
- package/dist/catalog/index.d.ts +5 -0
- package/dist/catalog/index.d.ts.map +1 -0
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/public-view.d.ts +7 -0
- package/dist/catalog/public-view.d.ts.map +1 -0
- package/dist/catalog/public-view.js +22 -0
- package/dist/catalog/public-view.js.map +1 -0
- package/dist/catalog/revisions.d.ts +8 -0
- package/dist/catalog/revisions.d.ts.map +1 -0
- package/dist/catalog/revisions.js +12 -0
- package/dist/catalog/revisions.js.map +1 -0
- package/dist/catalog/types.d.ts +28 -0
- package/dist/catalog/types.d.ts.map +1 -0
- package/dist/catalog/types.js +2 -0
- package/dist/catalog/types.js.map +1 -0
- package/dist/catalog/validate.d.ts +16 -0
- package/dist/catalog/validate.d.ts.map +1 -0
- package/dist/catalog/validate.js +66 -0
- package/dist/catalog/validate.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +35 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/generate.d.ts +15 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +68 -0
- package/dist/cli/generate.js.map +1 -0
- package/dist/config/define.d.ts +3 -0
- package/dist/config/define.d.ts.map +1 -0
- package/dist/config/define.js +5 -0
- package/dist/config/define.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/validate.d.ts +32 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +227 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/checkout-attempt.d.ts +29 -0
- package/dist/core/checkout-attempt.d.ts.map +1 -0
- package/dist/core/checkout-attempt.js +10 -0
- package/dist/core/checkout-attempt.js.map +1 -0
- package/dist/core/clock.d.ts +10 -0
- package/dist/core/clock.d.ts.map +1 -0
- package/dist/core/clock.js +26 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/customer.d.ts +13 -0
- package/dist/core/customer.d.ts.map +1 -0
- package/dist/core/customer.js +2 -0
- package/dist/core/customer.js.map +1 -0
- package/dist/core/errors.d.ts +28 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +43 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +15 -0
- package/dist/core/ids.d.ts.map +1 -0
- package/dist/core/ids.js +29 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +14 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/money.d.ts +8 -0
- package/dist/core/money.d.ts.map +1 -0
- package/dist/core/money.js +23 -0
- package/dist/core/money.js.map +1 -0
- package/dist/core/plan-change-attempt.d.ts +30 -0
- package/dist/core/plan-change-attempt.d.ts.map +1 -0
- package/dist/core/plan-change-attempt.js +9 -0
- package/dist/core/plan-change-attempt.js.map +1 -0
- package/dist/core/projection-diff.d.ts +32 -0
- package/dist/core/projection-diff.d.ts.map +1 -0
- package/dist/core/projection-diff.js +32 -0
- package/dist/core/projection-diff.js.map +1 -0
- package/dist/core/reconciliation-job.d.ts +21 -0
- package/dist/core/reconciliation-job.d.ts.map +1 -0
- package/dist/core/reconciliation-job.js +26 -0
- package/dist/core/reconciliation-job.js.map +1 -0
- package/dist/core/subscription.d.ts +62 -0
- package/dist/core/subscription.d.ts.map +1 -0
- package/dist/core/subscription.js +14 -0
- package/dist/core/subscription.js.map +1 -0
- package/dist/core/transitions.d.ts +25 -0
- package/dist/core/transitions.d.ts.map +1 -0
- package/dist/core/transitions.js +161 -0
- package/dist/core/transitions.js.map +1 -0
- package/dist/core/webhook-inbox.d.ts +23 -0
- package/dist/core/webhook-inbox.d.ts.map +1 -0
- package/dist/core/webhook-inbox.js +9 -0
- package/dist/core/webhook-inbox.js.map +1 -0
- package/dist/maintenance/batches.d.ts +3 -0
- package/dist/maintenance/batches.d.ts.map +1 -0
- package/dist/maintenance/batches.js +3 -0
- package/dist/maintenance/batches.js.map +1 -0
- package/dist/maintenance/claims.d.ts +2 -0
- package/dist/maintenance/claims.d.ts.map +1 -0
- package/dist/maintenance/claims.js +2 -0
- package/dist/maintenance/claims.js.map +1 -0
- package/dist/maintenance/health.d.ts +13 -0
- package/dist/maintenance/health.d.ts.map +1 -0
- package/dist/maintenance/health.js +19 -0
- package/dist/maintenance/health.js.map +1 -0
- package/dist/maintenance/retry.d.ts +9 -0
- package/dist/maintenance/retry.d.ts.map +1 -0
- package/dist/maintenance/retry.js +19 -0
- package/dist/maintenance/retry.js.map +1 -0
- package/dist/operations/index.d.ts +28 -0
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +106 -0
- package/dist/operations/index.js.map +1 -0
- package/dist/persistence/memory.d.ts +104 -0
- package/dist/persistence/memory.d.ts.map +1 -0
- package/dist/persistence/memory.js +657 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/persistence/store.d.ts +126 -0
- package/dist/persistence/store.d.ts.map +1 -0
- package/dist/persistence/store.js +2 -0
- package/dist/persistence/store.js.map +1 -0
- package/dist/ports/audit.d.ts +20 -0
- package/dist/ports/audit.d.ts.map +1 -0
- package/dist/ports/audit.js +9 -0
- package/dist/ports/audit.js.map +1 -0
- package/dist/ports/authorization.d.ts +28 -0
- package/dist/ports/authorization.d.ts.map +1 -0
- package/dist/ports/authorization.js +33 -0
- package/dist/ports/authorization.js.map +1 -0
- package/dist/ports/lifecycle.d.ts +23 -0
- package/dist/ports/lifecycle.d.ts.map +1 -0
- package/dist/ports/lifecycle.js +2 -0
- package/dist/ports/lifecycle.js.map +1 -0
- package/dist/ports/sensitive-values.d.ts +23 -0
- package/dist/ports/sensitive-values.d.ts.map +1 -0
- package/dist/ports/sensitive-values.js +19 -0
- package/dist/ports/sensitive-values.js.map +1 -0
- package/dist/ports/telemetry.d.ts +16 -0
- package/dist/ports/telemetry.d.ts.map +1 -0
- package/dist/ports/telemetry.js +48 -0
- package/dist/ports/telemetry.js.map +1 -0
- package/dist/providers/contract.d.ts +98 -0
- package/dist/providers/contract.d.ts.map +1 -0
- package/dist/providers/contract.js +2 -0
- package/dist/providers/contract.js.map +1 -0
- package/dist/providers/dodo/index.d.ts +25 -0
- package/dist/providers/dodo/index.d.ts.map +1 -0
- package/dist/providers/dodo/index.js +296 -0
- package/dist/providers/dodo/index.js.map +1 -0
- package/dist/providers/dodo/normalize.d.ts +7 -0
- package/dist/providers/dodo/normalize.d.ts.map +1 -0
- package/dist/providers/dodo/normalize.js +77 -0
- package/dist/providers/dodo/normalize.js.map +1 -0
- package/dist/providers/fake/index.d.ts +59 -0
- package/dist/providers/fake/index.d.ts.map +1 -0
- package/dist/providers/fake/index.js +312 -0
- package/dist/providers/fake/index.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +3 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/registry.d.ts +10 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +32 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/schema/canonical.d.ts +7 -0
- package/dist/schema/canonical.d.ts.map +1 -0
- package/dist/schema/canonical.js +35 -0
- package/dist/schema/canonical.js.map +1 -0
- package/dist/schema/generator.d.ts +3 -0
- package/dist/schema/generator.d.ts.map +1 -0
- package/dist/schema/generator.js +496 -0
- package/dist/schema/generator.js.map +1 -0
- package/dist/schema/pglite-sql.d.ts +3 -0
- package/dist/schema/pglite-sql.d.ts.map +1 -0
- package/dist/schema/pglite-sql.js +226 -0
- package/dist/schema/pglite-sql.js.map +1 -0
- package/dist/testing/clocks.d.ts +2 -0
- package/dist/testing/clocks.d.ts.map +1 -0
- package/dist/testing/clocks.js +2 -0
- package/dist/testing/clocks.js.map +1 -0
- package/dist/testing/consumer-conformance.d.ts +12 -0
- package/dist/testing/consumer-conformance.d.ts.map +1 -0
- package/dist/testing/consumer-conformance.js +17 -0
- package/dist/testing/consumer-conformance.js.map +1 -0
- package/dist/testing/fixtures.d.ts +9 -0
- package/dist/testing/fixtures.d.ts.map +1 -0
- package/dist/testing/fixtures.js +69 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/index.d.ts +7 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/provider-contract.d.ts +14 -0
- package/dist/testing/provider-contract.d.ts.map +1 -0
- package/dist/testing/provider-contract.js +238 -0
- package/dist/testing/provider-contract.js.map +1 -0
- package/dist/testing/state-machine.d.ts +2 -0
- package/dist/testing/state-machine.d.ts.map +1 -0
- package/dist/testing/state-machine.js +2 -0
- package/dist/testing/state-machine.js.map +1 -0
- package/dist/testing/workflow-harness.d.ts +224 -0
- package/dist/testing/workflow-harness.d.ts.map +1 -0
- package/dist/testing/workflow-harness.js +65 -0
- package/dist/testing/workflow-harness.js.map +1 -0
- package/dist/workflows/engine.d.ts +157 -0
- package/dist/workflows/engine.d.ts.map +1 -0
- package/dist/workflows/engine.js +2015 -0
- package/dist/workflows/engine.js.map +1 -0
- package/dist/workflows/index.d.ts +10 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +6 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/lifecycle.d.ts +5 -0
- package/dist/workflows/lifecycle.d.ts.map +1 -0
- package/dist/workflows/lifecycle.js +7 -0
- package/dist/workflows/lifecycle.js.map +1 -0
- package/docs/architecture.md +1188 -0
- package/docs/decisions/0001-extraction-discrepancies.md +29 -0
- package/docs/runbooks.md +140 -0
- package/package.json +110 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { PACKAGE_SCHEMA_VERSION } from "../config/validate.js";
|
|
3
|
+
import { CANONICAL_EXPORTS, tableName } from "./canonical.js";
|
|
4
|
+
function sqlStringList(values) {
|
|
5
|
+
return values.map((value) => `'${value.replace(/'/g, "''")}'`).join(", ");
|
|
6
|
+
}
|
|
7
|
+
function relativeImport(_fromFile, toSpecifier) {
|
|
8
|
+
return toSpecifier
|
|
9
|
+
.replace(/\\/g, "/")
|
|
10
|
+
.replace(/\.ts$/, "")
|
|
11
|
+
.replace(/\.js$/, "");
|
|
12
|
+
}
|
|
13
|
+
function idColumn(idType, name) {
|
|
14
|
+
return idType === "uuid" ? `uuid("${name}")` : `text("${name}")`;
|
|
15
|
+
}
|
|
16
|
+
function sqlColumnName(name) {
|
|
17
|
+
return name.replace(/[A-Z]/g, (char) => `_${char.toLowerCase()}`);
|
|
18
|
+
}
|
|
19
|
+
function extraFields(config, key) {
|
|
20
|
+
const fields = config.additionalFields?.[key];
|
|
21
|
+
if (!fields)
|
|
22
|
+
return "";
|
|
23
|
+
const lines = [];
|
|
24
|
+
for (const [name, spec] of Object.entries(fields)) {
|
|
25
|
+
const column = sqlColumnName(name);
|
|
26
|
+
const col = spec.type === "text"
|
|
27
|
+
? `text("${column}")`
|
|
28
|
+
: spec.type === "integer"
|
|
29
|
+
? `integer("${column}")`
|
|
30
|
+
: spec.type === "boolean"
|
|
31
|
+
? `boolean("${column}")`
|
|
32
|
+
: `timestamp("${column}", { withTimezone: true })`;
|
|
33
|
+
const suffix = spec.nullable === false ? ".notNull()" : "";
|
|
34
|
+
lines.push(` ${name}: ${col}${suffix},`);
|
|
35
|
+
}
|
|
36
|
+
return lines.length ? `\n${lines.join("\n")}` : "";
|
|
37
|
+
}
|
|
38
|
+
export function renderGeneratedSchema(config) {
|
|
39
|
+
const outputDir = path.posix.dirname(config.output.replaceAll("\\", "/"));
|
|
40
|
+
const entityImport = relativeImport(outputDir, config.billableEntity.tableImport);
|
|
41
|
+
const payerImport = relativeImport(outputDir, config.payer.tableImport);
|
|
42
|
+
const plans = sqlStringList(config.planIds);
|
|
43
|
+
const entityId = idColumn(config.billableEntity.idType, "billable_entity_id");
|
|
44
|
+
const payerId = idColumn(config.payer.idType, "payer_id");
|
|
45
|
+
const entityOnDelete = config.billableEntity.onDelete;
|
|
46
|
+
const payerOnDelete = config.payer.onDelete;
|
|
47
|
+
return `/**
|
|
48
|
+
* AUTO-GENERATED FILE. DO NOT EDIT.
|
|
49
|
+
* Generated by @codelitdev/billing schema version ${PACKAGE_SCHEMA_VERSION}.
|
|
50
|
+
*/
|
|
51
|
+
import { sql } from "drizzle-orm";
|
|
52
|
+
import {
|
|
53
|
+
boolean,
|
|
54
|
+
check,
|
|
55
|
+
index,
|
|
56
|
+
integer,
|
|
57
|
+
pgTable,
|
|
58
|
+
text,
|
|
59
|
+
timestamp,
|
|
60
|
+
uniqueIndex,
|
|
61
|
+
uuid,
|
|
62
|
+
} from "drizzle-orm/pg-core";
|
|
63
|
+
// The generated artifact is also loaded directly by drizzle-kit, which resolves
|
|
64
|
+
// extensionless application TypeScript imports. Keep those imports portable for
|
|
65
|
+
// the consuming application's module resolver.
|
|
66
|
+
// @ts-ignore drizzle-kit resolves the extensionless TypeScript import.
|
|
67
|
+
import { ${config.billableEntity.tableExport} } from "${entityImport}";
|
|
68
|
+
// @ts-ignore drizzle-kit resolves the extensionless TypeScript import.
|
|
69
|
+
import { ${config.payer.tableExport} } from "${payerImport}";
|
|
70
|
+
|
|
71
|
+
const timestamps = {
|
|
72
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
73
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const ${CANONICAL_EXPORTS.priceEntries} = pgTable(
|
|
77
|
+
"${tableName(config, "priceEntries")}",
|
|
78
|
+
{
|
|
79
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
80
|
+
offerKey: text("offer_key").notNull(),
|
|
81
|
+
plan: text("plan").notNull(),
|
|
82
|
+
billingInterval: text("billing_interval").notNull(),
|
|
83
|
+
currency: text("currency").notNull(),
|
|
84
|
+
amountMinor: integer("amount_minor").notNull(),
|
|
85
|
+
providerTrialDays: integer("provider_trial_days").notNull().default(0),
|
|
86
|
+
provider: text("provider").notNull(),
|
|
87
|
+
providerProductId: text("provider_product_id").notNull(),
|
|
88
|
+
verifiedAt: timestamp("verified_at", { withTimezone: true }),
|
|
89
|
+
...timestamps,${extraFields(config, "priceEntries")}
|
|
90
|
+
},
|
|
91
|
+
(table) => ({
|
|
92
|
+
providerProductUnique: uniqueIndex("billing_price_entries_provider_product_uidx").on(
|
|
93
|
+
table.provider,
|
|
94
|
+
table.providerProductId,
|
|
95
|
+
),
|
|
96
|
+
offerKeyIdx: index("billing_price_entries_offer_key_idx").on(table.offerKey),
|
|
97
|
+
amountCheck: check("billing_price_entries_amount_check", sql\`\${table.amountMinor} > 0\`),
|
|
98
|
+
trialDaysCheck: check("billing_price_entries_trial_days_check", sql\`\${table.providerTrialDays} >= 0\`),
|
|
99
|
+
currencyCheck: check("billing_price_entries_currency_check", sql\`\${table.currency} ~ '^[A-Z]{3}$'\`),
|
|
100
|
+
planCheck: check("billing_price_entries_plan_check", sql\`\${table.plan} IN (${plans})\`),
|
|
101
|
+
intervalCheck: check(
|
|
102
|
+
"billing_price_entries_interval_check",
|
|
103
|
+
sql\`\${table.billingInterval} IN ('month', 'year')\`,
|
|
104
|
+
),
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
export const ${CANONICAL_EXPORTS.catalogRevisions} = pgTable(
|
|
109
|
+
"${tableName(config, "catalogRevisions")}",
|
|
110
|
+
{
|
|
111
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
112
|
+
revision: integer("revision").notNull().unique(),
|
|
113
|
+
checkoutProvider: text("checkout_provider").notNull(),
|
|
114
|
+
status: text("status").notNull().default("pending_verification"),
|
|
115
|
+
verifiedAt: timestamp("verified_at", { withTimezone: true }),
|
|
116
|
+
activatedAt: timestamp("activated_at", { withTimezone: true }),
|
|
117
|
+
retiredAt: timestamp("retired_at", { withTimezone: true }),
|
|
118
|
+
...timestamps,${extraFields(config, "catalogRevisions")}
|
|
119
|
+
},
|
|
120
|
+
(table) => ({
|
|
121
|
+
statusCheck: check(
|
|
122
|
+
"billing_catalog_revisions_status_check",
|
|
123
|
+
sql\`\${table.status} IN ('pending_verification', 'active', 'retired', 'invalid', 'abandoned')\`,
|
|
124
|
+
),
|
|
125
|
+
revisionCheck: check("billing_catalog_revisions_revision_check", sql\`\${table.revision} > 0\`),
|
|
126
|
+
activeProviderUnique: uniqueIndex("billing_catalog_revisions_active_provider_uidx")
|
|
127
|
+
.on(table.checkoutProvider)
|
|
128
|
+
.where(sql\`\${table.status} = 'active'\`),
|
|
129
|
+
}),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
export const ${CANONICAL_EXPORTS.catalogRevisionItems} = pgTable(
|
|
133
|
+
"${tableName(config, "catalogRevisionItems")}",
|
|
134
|
+
{
|
|
135
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
136
|
+
catalogRevisionId: uuid("catalog_revision_id")
|
|
137
|
+
.notNull()
|
|
138
|
+
.references(() => ${CANONICAL_EXPORTS.catalogRevisions}.id, { onDelete: "cascade" }),
|
|
139
|
+
offerKey: text("offer_key").notNull(),
|
|
140
|
+
billingPriceEntryId: uuid("billing_price_entry_id")
|
|
141
|
+
.notNull()
|
|
142
|
+
.references(() => ${CANONICAL_EXPORTS.priceEntries}.id, { onDelete: "restrict" }),
|
|
143
|
+
},
|
|
144
|
+
(table) => ({
|
|
145
|
+
revisionKeyUnique: uniqueIndex("billing_catalog_revision_items_revision_key_uidx").on(
|
|
146
|
+
table.catalogRevisionId,
|
|
147
|
+
table.offerKey,
|
|
148
|
+
),
|
|
149
|
+
revisionPriceUnique: uniqueIndex("billing_catalog_revision_items_revision_price_uidx").on(
|
|
150
|
+
table.catalogRevisionId,
|
|
151
|
+
table.billingPriceEntryId,
|
|
152
|
+
),
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
export const ${CANONICAL_EXPORTS.providerCustomers} = pgTable(
|
|
157
|
+
"${tableName(config, "providerCustomers")}",
|
|
158
|
+
{
|
|
159
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
160
|
+
provider: text("provider").notNull(),
|
|
161
|
+
payerId: ${payerId}
|
|
162
|
+
.notNull()
|
|
163
|
+
.references(() => ${config.payer.tableExport}.${config.payer.idColumn}, { onDelete: "${payerOnDelete}" }),
|
|
164
|
+
payerEmail: text("payer_email").notNull().default(""),
|
|
165
|
+
providerCustomerId: text("provider_customer_id"),
|
|
166
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
167
|
+
status: text("status").notNull().default("creating"),
|
|
168
|
+
lastError: text("last_error"),
|
|
169
|
+
...timestamps,${extraFields(config, "providerCustomers")}
|
|
170
|
+
},
|
|
171
|
+
(table) => ({
|
|
172
|
+
providerPayerUnique: uniqueIndex("billing_provider_customers_provider_payer_uidx").on(
|
|
173
|
+
table.provider,
|
|
174
|
+
table.payerId,
|
|
175
|
+
),
|
|
176
|
+
providerCustomerUnique: uniqueIndex("billing_provider_customers_provider_customer_uidx")
|
|
177
|
+
.on(table.provider, table.providerCustomerId)
|
|
178
|
+
.where(sql\`\${table.providerCustomerId} IS NOT NULL\`),
|
|
179
|
+
idempotencyUnique: uniqueIndex("billing_provider_customers_idempotency_uidx").on(
|
|
180
|
+
table.idempotencyKey,
|
|
181
|
+
),
|
|
182
|
+
statusCheck: check(
|
|
183
|
+
"billing_provider_customers_status_check",
|
|
184
|
+
sql\`\${table.status} IN ('creating', 'active', 'conflicted')\`,
|
|
185
|
+
),
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
export const ${CANONICAL_EXPORTS.checkoutAttempts} = pgTable(
|
|
190
|
+
"${tableName(config, "checkoutAttempts")}",
|
|
191
|
+
{
|
|
192
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
193
|
+
attemptId: text("attempt_id").notNull().unique(),
|
|
194
|
+
billableEntityId: ${entityId}
|
|
195
|
+
.notNull()
|
|
196
|
+
.references(() => ${config.billableEntity.tableExport}.${config.billableEntity.idColumn}, { onDelete: "${entityOnDelete}" }),
|
|
197
|
+
payerId: ${payerId}
|
|
198
|
+
.notNull()
|
|
199
|
+
.references(() => ${config.payer.tableExport}.${config.payer.idColumn}, { onDelete: "${payerOnDelete}" }),
|
|
200
|
+
payerEmail: text("payer_email").notNull().default(""),
|
|
201
|
+
returnUrl: text("return_url").notNull().default(""),
|
|
202
|
+
provider: text("provider").notNull(),
|
|
203
|
+
catalogRevision: integer("catalog_revision").notNull(),
|
|
204
|
+
offerKey: text("offer_key").notNull(),
|
|
205
|
+
requestedPlan: text("requested_plan").notNull(),
|
|
206
|
+
requestedInterval: text("requested_interval").notNull(),
|
|
207
|
+
billingPriceEntryId: uuid("billing_price_entry_id")
|
|
208
|
+
.notNull()
|
|
209
|
+
.references(() => ${CANONICAL_EXPORTS.priceEntries}.id, { onDelete: "restrict" }),
|
|
210
|
+
quotedAmountMinor: integer("quoted_amount_minor").notNull(),
|
|
211
|
+
quotedCurrency: text("quoted_currency").notNull(),
|
|
212
|
+
billingCustomerId: uuid("billing_customer_id").references(
|
|
213
|
+
() => ${CANONICAL_EXPORTS.providerCustomers}.id,
|
|
214
|
+
{ onDelete: "restrict" },
|
|
215
|
+
),
|
|
216
|
+
providerCheckoutSessionId: text("provider_checkout_session_id"),
|
|
217
|
+
checkoutUrlEncrypted: text("checkout_url_encrypted"),
|
|
218
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
219
|
+
status: text("status").notNull().default("creating"),
|
|
220
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
221
|
+
lastError: text("last_error"),
|
|
222
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
223
|
+
...timestamps,${extraFields(config, "checkoutAttempts")}
|
|
224
|
+
},
|
|
225
|
+
(table) => ({
|
|
226
|
+
providerSessionUnique: uniqueIndex("billing_checkout_attempts_provider_session_uidx")
|
|
227
|
+
.on(table.provider, table.providerCheckoutSessionId)
|
|
228
|
+
.where(sql\`\${table.providerCheckoutSessionId} IS NOT NULL\`),
|
|
229
|
+
idempotencyUnique: uniqueIndex("billing_checkout_attempts_idempotency_uidx").on(
|
|
230
|
+
table.idempotencyKey,
|
|
231
|
+
),
|
|
232
|
+
entityNonterminalUnique: uniqueIndex("billing_checkout_attempts_entity_nonterminal_uidx")
|
|
233
|
+
.on(table.billableEntityId)
|
|
234
|
+
.where(sql\`\${table.status} IN ('creating', 'open')\`),
|
|
235
|
+
statusCheck: check(
|
|
236
|
+
"billing_checkout_attempts_status_check",
|
|
237
|
+
sql\`\${table.status} IN ('creating', 'open', 'completed', 'expired', 'abandoned', 'conflicted')\`,
|
|
238
|
+
),
|
|
239
|
+
amountCheck: check(
|
|
240
|
+
"billing_checkout_attempts_amount_check",
|
|
241
|
+
sql\`\${table.quotedAmountMinor} > 0\`,
|
|
242
|
+
),
|
|
243
|
+
planCheck: check(
|
|
244
|
+
"billing_checkout_attempts_plan_check",
|
|
245
|
+
sql\`\${table.requestedPlan} IN (${plans})\`,
|
|
246
|
+
),
|
|
247
|
+
intervalCheck: check(
|
|
248
|
+
"billing_checkout_attempts_interval_check",
|
|
249
|
+
sql\`\${table.requestedInterval} IN ('month', 'year')\`,
|
|
250
|
+
),
|
|
251
|
+
}),
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
export const ${CANONICAL_EXPORTS.subscriptions} = pgTable(
|
|
255
|
+
"${tableName(config, "subscriptions")}",
|
|
256
|
+
{
|
|
257
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
258
|
+
billableEntityId: ${entityId}
|
|
259
|
+
.notNull()
|
|
260
|
+
.references(() => ${config.billableEntity.tableExport}.${config.billableEntity.idColumn}, { onDelete: "${entityOnDelete}" }),
|
|
261
|
+
billingCustomerId: uuid("billing_customer_id")
|
|
262
|
+
.notNull()
|
|
263
|
+
.references(() => ${CANONICAL_EXPORTS.providerCustomers}.id, { onDelete: "restrict" }),
|
|
264
|
+
payerId: ${payerId}
|
|
265
|
+
.notNull()
|
|
266
|
+
.references(() => ${config.payer.tableExport}.${config.payer.idColumn}, { onDelete: "${payerOnDelete}" }),
|
|
267
|
+
originCheckoutAttemptId: uuid("origin_checkout_attempt_id").references(
|
|
268
|
+
() => ${CANONICAL_EXPORTS.checkoutAttempts}.id,
|
|
269
|
+
{ onDelete: "restrict" },
|
|
270
|
+
),
|
|
271
|
+
provider: text("provider").notNull(),
|
|
272
|
+
providerSubscriptionId: text("provider_subscription_id").notNull(),
|
|
273
|
+
providerProductId: text("provider_product_id").notNull(),
|
|
274
|
+
billingPriceEntryId: uuid("billing_price_entry_id")
|
|
275
|
+
.notNull()
|
|
276
|
+
.references(() => ${CANONICAL_EXPORTS.priceEntries}.id, { onDelete: "restrict" }),
|
|
277
|
+
catalogRevision: integer("catalog_revision").notNull(),
|
|
278
|
+
offerKey: text("offer_key").notNull(),
|
|
279
|
+
plan: text("plan").notNull(),
|
|
280
|
+
billingInterval: text("billing_interval").notNull(),
|
|
281
|
+
status: text("status").notNull().default("pending"),
|
|
282
|
+
currentPeriodStartsAt: timestamp("current_period_starts_at", { withTimezone: true }),
|
|
283
|
+
currentPeriodEndsAt: timestamp("current_period_ends_at", { withTimezone: true }),
|
|
284
|
+
paidThroughAt: timestamp("paid_through_at", { withTimezone: true }),
|
|
285
|
+
trialEndsAt: timestamp("trial_ends_at", { withTimezone: true }),
|
|
286
|
+
cancelAtPeriodEnd: boolean("cancel_at_period_end").notNull().default(false),
|
|
287
|
+
isEntitlementSource: boolean("is_entitlement_source").notNull().default(false),
|
|
288
|
+
providerOccurredAt: timestamp("provider_occurred_at", { withTimezone: true }),
|
|
289
|
+
providerVersion: text("provider_version"),
|
|
290
|
+
lastObservedAt: timestamp("last_observed_at", { withTimezone: true }),
|
|
291
|
+
lastReconciledAt: timestamp("last_reconciled_at", { withTimezone: true }),
|
|
292
|
+
...timestamps,${extraFields(config, "subscriptions")}
|
|
293
|
+
},
|
|
294
|
+
(table) => ({
|
|
295
|
+
providerSubscriptionUnique: uniqueIndex("billing_subscriptions_provider_subscription_uidx").on(
|
|
296
|
+
table.provider,
|
|
297
|
+
table.providerSubscriptionId,
|
|
298
|
+
),
|
|
299
|
+
entitySourceUnique: uniqueIndex("billing_subscriptions_entity_source_uidx")
|
|
300
|
+
.on(table.billableEntityId)
|
|
301
|
+
.where(sql\`\${table.isEntitlementSource} = true\`),
|
|
302
|
+
statusCheck: check(
|
|
303
|
+
"billing_subscriptions_status_check",
|
|
304
|
+
sql\`\${table.status} IN ('pending', 'trialing', 'active', 'past_due', 'cancelled', 'expired')\`,
|
|
305
|
+
),
|
|
306
|
+
planCheck: check("billing_subscriptions_plan_check", sql\`\${table.plan} IN (${plans})\`),
|
|
307
|
+
intervalCheck: check(
|
|
308
|
+
"billing_subscriptions_interval_check",
|
|
309
|
+
sql\`\${table.billingInterval} IN ('month', 'year')\`,
|
|
310
|
+
),
|
|
311
|
+
}),
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
export const ${CANONICAL_EXPORTS.planChangeAttempts} = pgTable(
|
|
315
|
+
"${tableName(config, "planChangeAttempts")}",
|
|
316
|
+
{
|
|
317
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
318
|
+
changeId: text("change_id").notNull().unique(),
|
|
319
|
+
billableEntityId: ${entityId}
|
|
320
|
+
.notNull()
|
|
321
|
+
.references(() => ${config.billableEntity.tableExport}.${config.billableEntity.idColumn}, { onDelete: "${entityOnDelete}" }),
|
|
322
|
+
subscriptionId: uuid("subscription_id")
|
|
323
|
+
.notNull()
|
|
324
|
+
.references(() => ${CANONICAL_EXPORTS.subscriptions}.id, { onDelete: "restrict" }),
|
|
325
|
+
actorId: text("actor_id").notNull(),
|
|
326
|
+
payerId: ${payerId}
|
|
327
|
+
.notNull()
|
|
328
|
+
.references(() => ${config.payer.tableExport}.${config.payer.idColumn}, { onDelete: "${payerOnDelete}" }),
|
|
329
|
+
provider: text("provider").notNull(),
|
|
330
|
+
idempotencyKey: text("idempotency_key").notNull(),
|
|
331
|
+
currentCatalogRevision: integer("current_catalog_revision").notNull(),
|
|
332
|
+
currentBillingPriceEntryId: uuid("current_billing_price_entry_id")
|
|
333
|
+
.notNull()
|
|
334
|
+
.references(() => ${CANONICAL_EXPORTS.priceEntries}.id, { onDelete: "restrict" }),
|
|
335
|
+
currentPlan: text("current_plan").notNull(),
|
|
336
|
+
currentInterval: text("current_interval").notNull(),
|
|
337
|
+
targetCatalogRevision: integer("target_catalog_revision").notNull(),
|
|
338
|
+
targetBillingPriceEntryId: uuid("target_billing_price_entry_id")
|
|
339
|
+
.notNull()
|
|
340
|
+
.references(() => ${CANONICAL_EXPORTS.priceEntries}.id, { onDelete: "restrict" }),
|
|
341
|
+
targetPlan: text("target_plan").notNull(),
|
|
342
|
+
targetInterval: text("target_interval").notNull(),
|
|
343
|
+
targetOfferKey: text("target_offer_key").notNull(),
|
|
344
|
+
effectiveAt: text("effective_at").notNull(),
|
|
345
|
+
prorationMode: text("proration_mode").notNull(),
|
|
346
|
+
providerPaymentId: text("provider_payment_id"),
|
|
347
|
+
paymentUrlEncrypted: text("payment_url_encrypted"),
|
|
348
|
+
status: text("status").notNull().default("creating"),
|
|
349
|
+
lastError: text("last_error"),
|
|
350
|
+
completedAt: timestamp("completed_at", { withTimezone: true }),
|
|
351
|
+
...timestamps,${extraFields(config, "planChangeAttempts")}
|
|
352
|
+
},
|
|
353
|
+
(table) => ({
|
|
354
|
+
idempotencyUnique: uniqueIndex("billing_plan_change_attempts_idempotency_uidx").on(
|
|
355
|
+
table.idempotencyKey,
|
|
356
|
+
),
|
|
357
|
+
entityNonterminalUnique: uniqueIndex("billing_plan_change_attempts_entity_nonterminal_uidx")
|
|
358
|
+
.on(table.billableEntityId)
|
|
359
|
+
.where(sql\`\${table.status} IN ('creating', 'pending')\`),
|
|
360
|
+
statusCheck: check(
|
|
361
|
+
"billing_plan_change_attempts_status_check",
|
|
362
|
+
sql\`\${table.status} IN ('creating', 'pending', 'succeeded', 'failed', 'conflicted')\`,
|
|
363
|
+
),
|
|
364
|
+
effectiveAtCheck: check(
|
|
365
|
+
"billing_plan_change_attempts_effective_at_check",
|
|
366
|
+
sql\`\${table.effectiveAt} IN ('immediately', 'next_billing_date')\`,
|
|
367
|
+
),
|
|
368
|
+
prorationModeCheck: check(
|
|
369
|
+
"billing_plan_change_attempts_proration_mode_check",
|
|
370
|
+
sql\`\${table.prorationMode} IN ('prorated_immediately', 'do_not_bill')\`,
|
|
371
|
+
),
|
|
372
|
+
currentPlanCheck: check(
|
|
373
|
+
"billing_plan_change_attempts_current_plan_check",
|
|
374
|
+
sql\`\${table.currentPlan} IN (${plans})\`,
|
|
375
|
+
),
|
|
376
|
+
targetPlanCheck: check(
|
|
377
|
+
"billing_plan_change_attempts_target_plan_check",
|
|
378
|
+
sql\`\${table.targetPlan} IN (${plans})\`,
|
|
379
|
+
),
|
|
380
|
+
}),
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
export const ${CANONICAL_EXPORTS.planStates} = pgTable(
|
|
384
|
+
"${tableName(config, "planStates")}",
|
|
385
|
+
{
|
|
386
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
387
|
+
billableEntityId: ${entityId}
|
|
388
|
+
.notNull()
|
|
389
|
+
.unique()
|
|
390
|
+
.references(() => ${config.billableEntity.tableExport}.${config.billableEntity.idColumn}, { onDelete: "${entityOnDelete}" }),
|
|
391
|
+
activeSubscriptionId: uuid("active_subscription_id").references(
|
|
392
|
+
() => ${CANONICAL_EXPORTS.subscriptions}.id,
|
|
393
|
+
{ onDelete: "restrict" },
|
|
394
|
+
),
|
|
395
|
+
projectionVersion: integer("projection_version").notNull().default(0),
|
|
396
|
+
...timestamps,${extraFields(config, "planStates")}
|
|
397
|
+
},
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
export const ${CANONICAL_EXPORTS.webhookEvents} = pgTable(
|
|
401
|
+
"${tableName(config, "webhookEvents")}",
|
|
402
|
+
{
|
|
403
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
404
|
+
provider: text("provider").notNull(),
|
|
405
|
+
providerEventId: text("provider_event_id").notNull(),
|
|
406
|
+
eventType: text("event_type").notNull(),
|
|
407
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
408
|
+
subscriptionId: text("subscription_id"),
|
|
409
|
+
checkoutAttemptId: text("checkout_attempt_id"),
|
|
410
|
+
payloadEncrypted: text("payload_encrypted"),
|
|
411
|
+
payloadKeyVersion: text("payload_key_version"),
|
|
412
|
+
verifiedKeyVersion: text("verified_key_version"),
|
|
413
|
+
status: text("status").notNull().default("pending"),
|
|
414
|
+
processingAttempts: integer("processing_attempts").notNull().default(0),
|
|
415
|
+
lastError: text("last_error"),
|
|
416
|
+
availableAt: timestamp("available_at", { withTimezone: true }).notNull().defaultNow(),
|
|
417
|
+
lockedAt: timestamp("locked_at", { withTimezone: true }),
|
|
418
|
+
leaseExpiresAt: timestamp("lease_expires_at", { withTimezone: true }),
|
|
419
|
+
workerId: text("worker_id"),
|
|
420
|
+
receivedAt: timestamp("received_at", { withTimezone: true }).notNull().defaultNow(),
|
|
421
|
+
processedAt: timestamp("processed_at", { withTimezone: true }),${extraFields(config, "webhookEvents")}
|
|
422
|
+
},
|
|
423
|
+
(table) => ({
|
|
424
|
+
providerEventUnique: uniqueIndex("billing_webhook_events_provider_event_uidx").on(
|
|
425
|
+
table.provider,
|
|
426
|
+
table.providerEventId,
|
|
427
|
+
),
|
|
428
|
+
queueIdx: index("billing_webhook_events_queue_idx").on(table.status, table.availableAt),
|
|
429
|
+
statusCheck: check(
|
|
430
|
+
"billing_webhook_events_status_check",
|
|
431
|
+
sql\`\${table.status} IN ('pending', 'processing', 'processed', 'ignored', 'quarantined', 'failed')\`,
|
|
432
|
+
),
|
|
433
|
+
}),
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
export const ${CANONICAL_EXPORTS.reconciliationJobs} = pgTable(
|
|
437
|
+
"${tableName(config, "reconciliationJobs")}",
|
|
438
|
+
{
|
|
439
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
440
|
+
provider: text("provider").notNull(),
|
|
441
|
+
checkoutAttemptId: uuid("checkout_attempt_id").references(
|
|
442
|
+
() => ${CANONICAL_EXPORTS.checkoutAttempts}.id,
|
|
443
|
+
{ onDelete: "restrict" },
|
|
444
|
+
),
|
|
445
|
+
planChangeAttemptId: uuid("plan_change_attempt_id").references(
|
|
446
|
+
() => ${CANONICAL_EXPORTS.planChangeAttempts}.id,
|
|
447
|
+
{ onDelete: "restrict" },
|
|
448
|
+
),
|
|
449
|
+
subscriptionId: uuid("subscription_id").references(
|
|
450
|
+
() => ${CANONICAL_EXPORTS.subscriptions}.id,
|
|
451
|
+
{ onDelete: "restrict" },
|
|
452
|
+
),
|
|
453
|
+
providerCustomerId: uuid("provider_customer_id").references(
|
|
454
|
+
() => ${CANONICAL_EXPORTS.providerCustomers}.id,
|
|
455
|
+
{ onDelete: "restrict" },
|
|
456
|
+
),
|
|
457
|
+
operation: text("operation").notNull().default("reconcile"),
|
|
458
|
+
status: text("status").notNull().default("pending"),
|
|
459
|
+
attemptCount: integer("attempt_count").notNull().default(0),
|
|
460
|
+
availableAt: timestamp("available_at", { withTimezone: true }).notNull().defaultNow(),
|
|
461
|
+
lockedAt: timestamp("locked_at", { withTimezone: true }),
|
|
462
|
+
leaseExpiresAt: timestamp("lease_expires_at", { withTimezone: true }),
|
|
463
|
+
workerId: text("worker_id"),
|
|
464
|
+
lastError: text("last_error"),
|
|
465
|
+
...timestamps,${extraFields(config, "reconciliationJobs")}
|
|
466
|
+
},
|
|
467
|
+
(table) => ({
|
|
468
|
+
exactlyOneSubject: check(
|
|
469
|
+
"billing_reconciliation_jobs_exactly_one_subject",
|
|
470
|
+
sql\`((CASE WHEN \${table.checkoutAttemptId} IS NOT NULL THEN 1 ELSE 0 END) + (CASE WHEN \${table.planChangeAttemptId} IS NOT NULL THEN 1 ELSE 0 END) + (CASE WHEN \${table.subscriptionId} IS NOT NULL THEN 1 ELSE 0 END) + (CASE WHEN \${table.providerCustomerId} IS NOT NULL THEN 1 ELSE 0 END)) = 1\`,
|
|
471
|
+
),
|
|
472
|
+
liveCheckoutUnique: uniqueIndex("billing_reconciliation_jobs_live_checkout_uidx")
|
|
473
|
+
.on(table.checkoutAttemptId)
|
|
474
|
+
.where(sql\`\${table.checkoutAttemptId} IS NOT NULL AND \${table.status} IN ('pending', 'processing', 'failed')\`),
|
|
475
|
+
livePlanChangeUnique: uniqueIndex("billing_reconciliation_jobs_live_plan_change_uidx")
|
|
476
|
+
.on(table.planChangeAttemptId)
|
|
477
|
+
.where(sql\`\${table.planChangeAttemptId} IS NOT NULL AND \${table.status} IN ('pending', 'processing', 'failed')\`),
|
|
478
|
+
liveSubscriptionUnique: uniqueIndex("billing_reconciliation_jobs_live_subscription_uidx")
|
|
479
|
+
.on(table.subscriptionId)
|
|
480
|
+
.where(sql\`\${table.subscriptionId} IS NOT NULL AND \${table.status} IN ('pending', 'processing', 'failed')\`),
|
|
481
|
+
liveCustomerUnique: uniqueIndex("billing_reconciliation_jobs_live_customer_uidx")
|
|
482
|
+
.on(table.providerCustomerId)
|
|
483
|
+
.where(sql\`\${table.providerCustomerId} IS NOT NULL AND \${table.status} IN ('pending', 'processing', 'failed')\`),
|
|
484
|
+
statusCheck: check(
|
|
485
|
+
"billing_reconciliation_jobs_status_check",
|
|
486
|
+
sql\`\${table.status} IN ('pending', 'processing', 'failed', 'completed', 'quarantined')\`,
|
|
487
|
+
),
|
|
488
|
+
operationCheck: check(
|
|
489
|
+
"billing_reconciliation_jobs_operation_check",
|
|
490
|
+
sql\`\${table.operation} = 'reconcile' OR (\${table.operation} = 'cancellation' AND \${table.subscriptionId} IS NOT NULL)\`,
|
|
491
|
+
),
|
|
492
|
+
}),
|
|
493
|
+
);
|
|
494
|
+
`;
|
|
495
|
+
}
|
|
496
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/schema/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Canonical DDL used by adapter conformance on PGlite. Mirrors the generator. */
|
|
2
|
+
export declare const CANONICAL_PGLITE_SQL = "\nCREATE TABLE accounts (\n id text PRIMARY KEY,\n email text NOT NULL\n);\nCREATE TABLE workspaces (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n name text NOT NULL\n);\nCREATE TABLE billing_price_entries (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n offer_key text NOT NULL,\n plan text NOT NULL,\n billing_interval text NOT NULL,\n currency text NOT NULL,\n amount_minor integer NOT NULL,\n provider_trial_days integer NOT NULL DEFAULT 0,\n provider text NOT NULL,\n provider_product_id text NOT NULL,\n verified_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT billing_price_entries_amount_check CHECK (amount_minor > 0),\n CONSTRAINT billing_price_entries_trial_days_check CHECK (provider_trial_days >= 0),\n CONSTRAINT billing_price_entries_currency_check CHECK (currency ~ '^[A-Z]{3}$'),\n CONSTRAINT billing_price_entries_plan_check CHECK (plan IN ('pro', 'business')),\n CONSTRAINT billing_price_entries_interval_check CHECK (billing_interval IN ('month', 'year'))\n);\nCREATE UNIQUE INDEX billing_price_entries_provider_product_uidx\n ON billing_price_entries (provider, provider_product_id);\nCREATE TABLE billing_catalog_revisions (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n revision integer NOT NULL UNIQUE,\n checkout_provider text NOT NULL,\n status text NOT NULL DEFAULT 'pending_verification',\n verified_at timestamptz,\n activated_at timestamptz,\n retired_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT billing_catalog_revisions_status_check CHECK (status IN ('pending_verification', 'active', 'retired', 'invalid', 'abandoned')),\n CONSTRAINT billing_catalog_revisions_revision_check CHECK (revision > 0)\n);\nCREATE UNIQUE INDEX billing_catalog_revisions_active_provider_uidx\n ON billing_catalog_revisions (checkout_provider) WHERE status = 'active';\nCREATE TABLE billing_catalog_revision_items (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n catalog_revision_id uuid NOT NULL REFERENCES billing_catalog_revisions(id) ON DELETE CASCADE,\n offer_key text NOT NULL,\n billing_price_entry_id uuid NOT NULL REFERENCES billing_price_entries(id) ON DELETE RESTRICT\n);\nCREATE UNIQUE INDEX billing_catalog_revision_items_revision_key_uidx\n ON billing_catalog_revision_items (catalog_revision_id, offer_key);\nCREATE TABLE billing_provider_customers (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n provider text NOT NULL,\n payer_id text NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,\n payer_email text NOT NULL DEFAULT '',\n provider_customer_id text,\n idempotency_key text NOT NULL,\n status text NOT NULL DEFAULT 'creating',\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT billing_provider_customers_status_check CHECK (status IN ('creating', 'active', 'conflicted'))\n);\nCREATE UNIQUE INDEX billing_provider_customers_provider_payer_uidx\n ON billing_provider_customers (provider, payer_id);\nCREATE UNIQUE INDEX billing_provider_customers_idempotency_uidx\n ON billing_provider_customers (idempotency_key);\nCREATE TABLE billing_checkout_attempts (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n attempt_id text NOT NULL UNIQUE,\n billable_entity_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,\n payer_id text NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,\n payer_email text NOT NULL DEFAULT '',\n return_url text NOT NULL DEFAULT '',\n provider text NOT NULL,\n catalog_revision integer NOT NULL,\n offer_key text NOT NULL,\n requested_plan text NOT NULL,\n requested_interval text NOT NULL,\n billing_price_entry_id uuid NOT NULL REFERENCES billing_price_entries(id) ON DELETE RESTRICT,\n quoted_amount_minor integer NOT NULL,\n quoted_currency text NOT NULL,\n billing_customer_id uuid REFERENCES billing_provider_customers(id) ON DELETE RESTRICT,\n provider_checkout_session_id text,\n checkout_url_encrypted text,\n idempotency_key text NOT NULL,\n status text NOT NULL DEFAULT 'creating',\n expires_at timestamptz NOT NULL,\n last_error text,\n completed_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT billing_checkout_attempts_status_check CHECK (status IN ('creating', 'open', 'completed', 'expired', 'abandoned', 'conflicted')),\n CONSTRAINT billing_checkout_attempts_amount_check CHECK (quoted_amount_minor > 0)\n);\nCREATE UNIQUE INDEX billing_checkout_attempts_idempotency_uidx\n ON billing_checkout_attempts (idempotency_key);\nCREATE UNIQUE INDEX billing_checkout_attempts_entity_nonterminal_uidx\n ON billing_checkout_attempts (billable_entity_id) WHERE status IN ('creating', 'open');\nCREATE TABLE billing_webhook_events (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n provider text NOT NULL,\n provider_event_id text NOT NULL,\n event_type text NOT NULL,\n occurred_at timestamptz NOT NULL,\n subscription_id text,\n checkout_attempt_id text,\n payload_encrypted text,\n payload_key_version text,\n verified_key_version text,\n status text NOT NULL DEFAULT 'pending',\n processing_attempts integer NOT NULL DEFAULT 0,\n last_error text,\n available_at timestamptz NOT NULL DEFAULT now(),\n locked_at timestamptz,\n lease_expires_at timestamptz,\n worker_id text,\n received_at timestamptz NOT NULL DEFAULT now(),\n processed_at timestamptz,\n CONSTRAINT billing_webhook_events_status_check CHECK (status IN ('pending', 'processing', 'processed', 'ignored', 'quarantined', 'failed'))\n);\nCREATE UNIQUE INDEX billing_webhook_events_provider_event_uidx\n ON billing_webhook_events (provider, provider_event_id);\nCREATE TABLE billing_subscriptions (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n billable_entity_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,\n billing_customer_id uuid NOT NULL REFERENCES billing_provider_customers(id) ON DELETE RESTRICT,\n payer_id text NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,\n origin_checkout_attempt_id uuid REFERENCES billing_checkout_attempts(id) ON DELETE RESTRICT,\n provider text NOT NULL,\n provider_subscription_id text NOT NULL,\n provider_product_id text NOT NULL,\n billing_price_entry_id uuid NOT NULL REFERENCES billing_price_entries(id) ON DELETE RESTRICT,\n catalog_revision integer NOT NULL,\n offer_key text NOT NULL,\n plan text NOT NULL,\n billing_interval text NOT NULL,\n status text NOT NULL DEFAULT 'pending',\n current_period_starts_at timestamptz,\n current_period_ends_at timestamptz,\n paid_through_at timestamptz,\n trial_ends_at timestamptz,\n cancel_at_period_end boolean NOT NULL DEFAULT false,\n is_entitlement_source boolean NOT NULL DEFAULT false,\n provider_occurred_at timestamptz,\n provider_version text,\n last_observed_at timestamptz,\n last_reconciled_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nCREATE UNIQUE INDEX billing_subscriptions_provider_subscription_uidx\n ON billing_subscriptions (provider, provider_subscription_id);\nCREATE UNIQUE INDEX billing_subscriptions_entity_source_uidx\n ON billing_subscriptions (billable_entity_id) WHERE is_entitlement_source = true;\nCREATE TABLE billing_plan_states (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n billable_entity_id uuid NOT NULL UNIQUE REFERENCES workspaces(id) ON DELETE RESTRICT,\n active_subscription_id uuid REFERENCES billing_subscriptions(id) ON DELETE RESTRICT,\n projection_version integer NOT NULL DEFAULT 0,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nCREATE TABLE billing_plan_change_attempts (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n change_id text NOT NULL UNIQUE,\n billable_entity_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,\n subscription_id uuid NOT NULL REFERENCES billing_subscriptions(id) ON DELETE RESTRICT,\n actor_id text NOT NULL,\n payer_id text NOT NULL REFERENCES accounts(id) ON DELETE RESTRICT,\n provider text NOT NULL,\n idempotency_key text NOT NULL,\n current_catalog_revision integer NOT NULL,\n current_billing_price_entry_id uuid NOT NULL REFERENCES billing_price_entries(id) ON DELETE RESTRICT,\n current_plan text NOT NULL,\n current_interval text NOT NULL,\n target_catalog_revision integer NOT NULL,\n target_billing_price_entry_id uuid NOT NULL REFERENCES billing_price_entries(id) ON DELETE RESTRICT,\n target_plan text NOT NULL,\n target_interval text NOT NULL,\n target_offer_key text NOT NULL,\n effective_at text NOT NULL,\n proration_mode text NOT NULL,\n provider_payment_id text,\n payment_url_encrypted text,\n status text NOT NULL DEFAULT 'creating',\n last_error text,\n completed_at timestamptz,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now()\n);\nCREATE UNIQUE INDEX billing_plan_change_attempts_idempotency_uidx\n ON billing_plan_change_attempts (idempotency_key);\nCREATE TABLE billing_reconciliation_jobs (\n id uuid PRIMARY KEY DEFAULT gen_random_uuid(),\n provider text NOT NULL,\n checkout_attempt_id uuid REFERENCES billing_checkout_attempts(id) ON DELETE RESTRICT,\n plan_change_attempt_id uuid REFERENCES billing_plan_change_attempts(id) ON DELETE RESTRICT,\n subscription_id uuid REFERENCES billing_subscriptions(id) ON DELETE RESTRICT,\n provider_customer_id uuid REFERENCES billing_provider_customers(id) ON DELETE RESTRICT,\n operation text NOT NULL DEFAULT 'reconcile',\n status text NOT NULL DEFAULT 'pending',\n attempt_count integer NOT NULL DEFAULT 0,\n available_at timestamptz NOT NULL DEFAULT now(),\n locked_at timestamptz,\n lease_expires_at timestamptz,\n worker_id text,\n last_error text,\n created_at timestamptz NOT NULL DEFAULT now(),\n updated_at timestamptz NOT NULL DEFAULT now(),\n CONSTRAINT billing_reconciliation_jobs_exactly_one_subject CHECK (\n ((CASE WHEN checkout_attempt_id IS NOT NULL THEN 1 ELSE 0 END)\n + (CASE WHEN plan_change_attempt_id IS NOT NULL THEN 1 ELSE 0 END)\n + (CASE WHEN subscription_id IS NOT NULL THEN 1 ELSE 0 END)\n + (CASE WHEN provider_customer_id IS NOT NULL THEN 1 ELSE 0 END)) = 1\n ),\n CONSTRAINT billing_reconciliation_jobs_operation_check CHECK (\n operation = 'reconcile' OR (operation = 'cancellation' AND subscription_id IS NOT NULL)\n )\n);\n";
|
|
3
|
+
//# sourceMappingURL=pglite-sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pglite-sql.d.ts","sourceRoot":"","sources":["../../src/schema/pglite-sql.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,u2UA+NhC,CAAC"}
|