@arcenpay/node 0.0.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.
@@ -0,0 +1,46 @@
1
+ import { TablelandEntitlement, PlanTier } from '@arcenpay/sdk';
2
+
3
+ interface TablelandConfig {
4
+ /** Tableland table name (e.g., meap_feature_flags_84532_123) */
5
+ tableName: string;
6
+ /** Tableland controller wallet private key (required for writes) */
7
+ privateKey?: string;
8
+ /** Chain ID used for metadata and defaults */
9
+ chainId: number;
10
+ /** RPC URL for signer/provider connectivity */
11
+ rpcUrl?: string;
12
+ /** Gateway URL override (used for read HTTP fallback paths) */
13
+ gatewayUrl?: string;
14
+ }
15
+ type TierFlagsMatrix = Record<string, Record<string, boolean | string | number>>;
16
+ declare class TablelandService {
17
+ private config;
18
+ private initialized;
19
+ private dbRead;
20
+ private dbWrite;
21
+ constructor(config: TablelandConfig);
22
+ initialize(): Promise<void>;
23
+ getFeatureFlags(walletAddress: string): Promise<Record<string, boolean | string | number>>;
24
+ setFeatureFlags(walletAddress: string, flags: Record<string, boolean | string | number>, metadata: Partial<TablelandEntitlement>): Promise<boolean>;
25
+ revokeEntitlement(walletAddress: string): Promise<boolean>;
26
+ revokeEntitlementByTokenId(tokenId: number): Promise<boolean>;
27
+ updateEntitlementByTokenId(tokenId: number, updates: Partial<Pick<TablelandEntitlement, 'feature_flags' | 'plan_tier' | 'expires_at' | 'last_renewed' | 'api_rate_limit' | 'billing_interval'>>): Promise<boolean>;
28
+ listEntitlements(limit?: number): Promise<TablelandEntitlement[]>;
29
+ syncSubscription(data: {
30
+ walletAddress: string;
31
+ tokenId: number;
32
+ planTier: PlanTier;
33
+ expiresAt: number;
34
+ billingInterval: number;
35
+ features: Record<string, boolean | string | number>;
36
+ }): Promise<void>;
37
+ listTierFeatureFlags(providerAddress: string, tiers?: string[]): Promise<TierFlagsMatrix>;
38
+ setTierFeatureFlags(providerAddress: string, tier: string, flags: Record<string, boolean | string | number>): Promise<boolean>;
39
+ private buildTierMatrixKey;
40
+ private defaultRateLimitForTier;
41
+ private ensureInitialized;
42
+ private ensureWritable;
43
+ private ensureSafeTableName;
44
+ }
45
+
46
+ export { type TablelandConfig, TablelandService };
@@ -0,0 +1,46 @@
1
+ import { TablelandEntitlement, PlanTier } from '@arcenpay/sdk';
2
+
3
+ interface TablelandConfig {
4
+ /** Tableland table name (e.g., meap_feature_flags_84532_123) */
5
+ tableName: string;
6
+ /** Tableland controller wallet private key (required for writes) */
7
+ privateKey?: string;
8
+ /** Chain ID used for metadata and defaults */
9
+ chainId: number;
10
+ /** RPC URL for signer/provider connectivity */
11
+ rpcUrl?: string;
12
+ /** Gateway URL override (used for read HTTP fallback paths) */
13
+ gatewayUrl?: string;
14
+ }
15
+ type TierFlagsMatrix = Record<string, Record<string, boolean | string | number>>;
16
+ declare class TablelandService {
17
+ private config;
18
+ private initialized;
19
+ private dbRead;
20
+ private dbWrite;
21
+ constructor(config: TablelandConfig);
22
+ initialize(): Promise<void>;
23
+ getFeatureFlags(walletAddress: string): Promise<Record<string, boolean | string | number>>;
24
+ setFeatureFlags(walletAddress: string, flags: Record<string, boolean | string | number>, metadata: Partial<TablelandEntitlement>): Promise<boolean>;
25
+ revokeEntitlement(walletAddress: string): Promise<boolean>;
26
+ revokeEntitlementByTokenId(tokenId: number): Promise<boolean>;
27
+ updateEntitlementByTokenId(tokenId: number, updates: Partial<Pick<TablelandEntitlement, 'feature_flags' | 'plan_tier' | 'expires_at' | 'last_renewed' | 'api_rate_limit' | 'billing_interval'>>): Promise<boolean>;
28
+ listEntitlements(limit?: number): Promise<TablelandEntitlement[]>;
29
+ syncSubscription(data: {
30
+ walletAddress: string;
31
+ tokenId: number;
32
+ planTier: PlanTier;
33
+ expiresAt: number;
34
+ billingInterval: number;
35
+ features: Record<string, boolean | string | number>;
36
+ }): Promise<void>;
37
+ listTierFeatureFlags(providerAddress: string, tiers?: string[]): Promise<TierFlagsMatrix>;
38
+ setTierFeatureFlags(providerAddress: string, tier: string, flags: Record<string, boolean | string | number>): Promise<boolean>;
39
+ private buildTierMatrixKey;
40
+ private defaultRateLimitForTier;
41
+ private ensureInitialized;
42
+ private ensureWritable;
43
+ private ensureSafeTableName;
44
+ }
45
+
46
+ export { type TablelandConfig, TablelandService };
@@ -0,0 +1,268 @@
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/tableland.ts
21
+ var tableland_exports = {};
22
+ __export(tableland_exports, {
23
+ TablelandService: () => TablelandService
24
+ });
25
+ module.exports = __toCommonJS(tableland_exports);
26
+
27
+ // src/services/tableland.ts
28
+ var import_sdk = require("@tableland/sdk");
29
+ var import_ethers = require("ethers");
30
+ var TablelandService = class {
31
+ config;
32
+ initialized = false;
33
+ dbRead = null;
34
+ dbWrite = null;
35
+ constructor(config) {
36
+ this.config = config;
37
+ }
38
+ async initialize() {
39
+ this.ensureSafeTableName();
40
+ this.dbRead = new import_sdk.Database({
41
+ ...this.config.gatewayUrl ? { baseUrl: this.config.gatewayUrl } : {}
42
+ });
43
+ if (this.config.privateKey && this.config.rpcUrl) {
44
+ const provider = new import_ethers.JsonRpcProvider(this.config.rpcUrl);
45
+ const signer = new import_ethers.Wallet(this.config.privateKey, provider);
46
+ this.dbWrite = new import_sdk.Database({
47
+ signer,
48
+ ...this.config.gatewayUrl ? { baseUrl: this.config.gatewayUrl } : {}
49
+ });
50
+ }
51
+ this.initialized = true;
52
+ console.log(
53
+ `[Tableland] Initialized table=${this.config.tableName} mode=${this.dbWrite ? "read-write" : "read-only"}`
54
+ );
55
+ }
56
+ async getFeatureFlags(walletAddress) {
57
+ this.ensureInitialized();
58
+ const normalized = walletAddress.toLowerCase();
59
+ try {
60
+ const statement = `SELECT feature_flags FROM ${this.config.tableName} WHERE wallet_address = ? LIMIT 1`;
61
+ const response = await this.dbRead.prepare(statement).bind(normalized).all();
62
+ const row = response.results[0];
63
+ if (!row?.feature_flags) return {};
64
+ const parsed = JSON.parse(row.feature_flags);
65
+ return parsed ?? {};
66
+ } catch (err) {
67
+ console.error("[Tableland] getFeatureFlags error:", err);
68
+ return {};
69
+ }
70
+ }
71
+ async setFeatureFlags(walletAddress, flags, metadata) {
72
+ this.ensureInitialized();
73
+ this.ensureWritable();
74
+ const normalized = walletAddress.toLowerCase();
75
+ const now = Math.floor(Date.now() / 1e3);
76
+ const nftTokenId = metadata.nft_token_id ?? 0;
77
+ const planTier = metadata.plan_tier ?? "starter";
78
+ const apiRateLimit = metadata.api_rate_limit ?? this.defaultRateLimitForTier(planTier);
79
+ const billingInterval = metadata.billing_interval ?? 2592e3;
80
+ const lastRenewed = metadata.last_renewed ?? now;
81
+ const expiresAt = metadata.expires_at ?? 0;
82
+ const chainId = metadata.chain_id ?? this.config.chainId;
83
+ try {
84
+ const statement = `
85
+ INSERT INTO ${this.config.tableName}
86
+ (wallet_address, nft_token_id, plan_tier, feature_flags, api_rate_limit, billing_interval, last_renewed, expires_at, chain_id)
87
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
88
+ ON CONFLICT (wallet_address) DO UPDATE SET
89
+ nft_token_id = excluded.nft_token_id,
90
+ plan_tier = excluded.plan_tier,
91
+ feature_flags = excluded.feature_flags,
92
+ api_rate_limit = excluded.api_rate_limit,
93
+ billing_interval = excluded.billing_interval,
94
+ last_renewed = excluded.last_renewed,
95
+ expires_at = excluded.expires_at,
96
+ chain_id = excluded.chain_id
97
+ `;
98
+ await this.dbWrite.prepare(statement).bind(
99
+ normalized,
100
+ nftTokenId,
101
+ planTier,
102
+ JSON.stringify(flags),
103
+ apiRateLimit,
104
+ billingInterval,
105
+ lastRenewed,
106
+ expiresAt,
107
+ chainId
108
+ ).run();
109
+ return true;
110
+ } catch (err) {
111
+ console.error("[Tableland] setFeatureFlags error:", err);
112
+ return false;
113
+ }
114
+ }
115
+ async revokeEntitlement(walletAddress) {
116
+ this.ensureInitialized();
117
+ this.ensureWritable();
118
+ try {
119
+ const statement = `DELETE FROM ${this.config.tableName} WHERE wallet_address = ?`;
120
+ await this.dbWrite.prepare(statement).bind(walletAddress.toLowerCase()).run();
121
+ return true;
122
+ } catch (err) {
123
+ console.error("[Tableland] revokeEntitlement error:", err);
124
+ return false;
125
+ }
126
+ }
127
+ async revokeEntitlementByTokenId(tokenId) {
128
+ this.ensureInitialized();
129
+ this.ensureWritable();
130
+ try {
131
+ const statement = `DELETE FROM ${this.config.tableName} WHERE nft_token_id = ?`;
132
+ await this.dbWrite.prepare(statement).bind(tokenId).run();
133
+ return true;
134
+ } catch (err) {
135
+ console.error("[Tableland] revokeEntitlementByTokenId error:", err);
136
+ return false;
137
+ }
138
+ }
139
+ async updateEntitlementByTokenId(tokenId, updates) {
140
+ this.ensureInitialized();
141
+ this.ensureWritable();
142
+ const assignments = [];
143
+ const values = [];
144
+ if (updates.feature_flags) {
145
+ assignments.push("feature_flags = ?");
146
+ values.push(JSON.stringify(updates.feature_flags));
147
+ }
148
+ if (updates.plan_tier) {
149
+ assignments.push("plan_tier = ?");
150
+ values.push(updates.plan_tier);
151
+ }
152
+ if (updates.expires_at !== void 0) {
153
+ assignments.push("expires_at = ?");
154
+ values.push(updates.expires_at);
155
+ }
156
+ if (updates.last_renewed !== void 0) {
157
+ assignments.push("last_renewed = ?");
158
+ values.push(updates.last_renewed);
159
+ }
160
+ if (updates.api_rate_limit !== void 0) {
161
+ assignments.push("api_rate_limit = ?");
162
+ values.push(updates.api_rate_limit);
163
+ }
164
+ if (updates.billing_interval !== void 0) {
165
+ assignments.push("billing_interval = ?");
166
+ values.push(updates.billing_interval);
167
+ }
168
+ if (assignments.length === 0) return true;
169
+ try {
170
+ const statement = `UPDATE ${this.config.tableName} SET ${assignments.join(", ")} WHERE nft_token_id = ?`;
171
+ values.push(tokenId);
172
+ await this.dbWrite.prepare(statement).bind(...values).run();
173
+ return true;
174
+ } catch (err) {
175
+ console.error("[Tableland] updateEntitlementByTokenId error:", err);
176
+ return false;
177
+ }
178
+ }
179
+ async listEntitlements(limit = 100) {
180
+ this.ensureInitialized();
181
+ const safeLimit = Math.max(1, Math.min(limit, 1e3));
182
+ try {
183
+ const statement = `SELECT * FROM ${this.config.tableName} LIMIT ?`;
184
+ const response = await this.dbRead.prepare(statement).bind(safeLimit).all();
185
+ const rows = response.results || [];
186
+ return rows.map((row) => ({
187
+ wallet_address: String(row.wallet_address || ""),
188
+ nft_token_id: Number(row.nft_token_id || 0),
189
+ plan_tier: String(row.plan_tier || "starter"),
190
+ feature_flags: typeof row.feature_flags === "string" ? JSON.parse(row.feature_flags) : row.feature_flags || {},
191
+ api_rate_limit: Number(row.api_rate_limit || 0),
192
+ billing_interval: Number(row.billing_interval || 0),
193
+ last_renewed: Number(row.last_renewed || 0),
194
+ expires_at: Number(row.expires_at || 0),
195
+ chain_id: Number(row.chain_id || this.config.chainId)
196
+ }));
197
+ } catch (err) {
198
+ console.error("[Tableland] listEntitlements error:", err);
199
+ return [];
200
+ }
201
+ }
202
+ async syncSubscription(data) {
203
+ await this.setFeatureFlags(data.walletAddress, data.features, {
204
+ wallet_address: data.walletAddress,
205
+ nft_token_id: data.tokenId,
206
+ plan_tier: data.planTier,
207
+ expires_at: data.expiresAt,
208
+ billing_interval: data.billingInterval,
209
+ last_renewed: Math.floor(Date.now() / 1e3),
210
+ chain_id: this.config.chainId,
211
+ api_rate_limit: this.defaultRateLimitForTier(data.planTier),
212
+ feature_flags: data.features
213
+ });
214
+ }
215
+ async listTierFeatureFlags(providerAddress, tiers = ["starter", "pro", "enterprise"]) {
216
+ const matrix = {};
217
+ for (const tier of tiers) {
218
+ const key = this.buildTierMatrixKey(providerAddress, tier);
219
+ matrix[tier] = await this.getFeatureFlags(key);
220
+ }
221
+ return matrix;
222
+ }
223
+ async setTierFeatureFlags(providerAddress, tier, flags) {
224
+ const key = this.buildTierMatrixKey(providerAddress, tier);
225
+ return this.setFeatureFlags(key, flags, {
226
+ wallet_address: key,
227
+ nft_token_id: 0,
228
+ plan_tier: tier,
229
+ expires_at: 0,
230
+ billing_interval: 0,
231
+ last_renewed: Math.floor(Date.now() / 1e3),
232
+ chain_id: this.config.chainId,
233
+ api_rate_limit: this.defaultRateLimitForTier(tier),
234
+ feature_flags: flags
235
+ });
236
+ }
237
+ buildTierMatrixKey(providerAddress, tier) {
238
+ return `matrix:${providerAddress.toLowerCase()}:${tier.toLowerCase()}`;
239
+ }
240
+ defaultRateLimitForTier(tier) {
241
+ if (tier === "enterprise") return 1e4;
242
+ if (tier === "pro") return 5e3;
243
+ return 1e3;
244
+ }
245
+ ensureInitialized() {
246
+ if (!this.initialized || !this.dbRead) {
247
+ throw new Error("[Tableland] Service not initialized. Call initialize() first.");
248
+ }
249
+ }
250
+ ensureWritable() {
251
+ if (!this.dbWrite) {
252
+ throw new Error(
253
+ "[Tableland] Write requested without signer. Set TABLELAND_PRIVATE_KEY + TABLELAND_RPC_URL."
254
+ );
255
+ }
256
+ }
257
+ ensureSafeTableName() {
258
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(this.config.tableName)) {
259
+ throw new Error(
260
+ `[Tableland] Unsafe table name "${this.config.tableName}". Expected alphanumeric/underscore only.`
261
+ );
262
+ }
263
+ }
264
+ };
265
+ // Annotate the CommonJS export names for ESM import in node:
266
+ 0 && (module.exports = {
267
+ TablelandService
268
+ });
@@ -0,0 +1,6 @@
1
+ import {
2
+ TablelandService
3
+ } from "./chunk-SKFD6TSD.mjs";
4
+ export {
5
+ TablelandService
6
+ };
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@arcenpay/node",
3
+ "version": "0.0.1",
4
+ "description": "ArcenPay SDK — Node.js middleware and billing services",
5
+ "license": "UNLICENSED",
6
+ "homepage": "https://app.arcenpay.com",
7
+ "keywords": [
8
+ "arcenpay",
9
+ "web3",
10
+ "subscriptions",
11
+ "billing",
12
+ "node",
13
+ "x402"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.mjs",
17
+ "types": "./dist/index.d.ts",
18
+ "typings": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.mjs",
23
+ "require": "./dist/index.js",
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "./tableland": {
27
+ "types": "./dist/tableland.d.ts",
28
+ "import": "./dist/tableland.mjs",
29
+ "require": "./dist/tableland.js",
30
+ "default": "./dist/tableland.mjs"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup src/index.ts src/tableland.ts --clean --format cjs,esm --dts --dts-resolve",
41
+ "dev": "tsup src/index.ts src/tableland.ts --clean --format cjs,esm --dts --watch",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "typecheck": "tsc --noEmit",
45
+ "clean": "rm -rf dist"
46
+ },
47
+ "dependencies": {
48
+ "@lit-protocol/constants": "^7.4.0",
49
+ "@lit-protocol/encryption": "^7.4.0",
50
+ "@lit-protocol/lit-node-client": "^7.4.0",
51
+ "@arcenpay/sdk": "0.0.1",
52
+ "@tableland/sdk": "^7.2.1",
53
+ "ethers": "^6.13.5",
54
+ "redis": "^4.7.1",
55
+ "viem": "^2.21.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/express": "^5.0.0",
59
+ "tsup": "^8.3.0",
60
+ "typescript": "^5.7.0",
61
+ "vitest": "^4.0.18"
62
+ },
63
+ "peerDependencies": {
64
+ "express": "^4.0.0 || ^5.0.0"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "express": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "engines": {
72
+ "node": ">=20.0.0"
73
+ }
74
+ }