@djangocfg/ext-payments 1.0.9 → 1.0.10
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/dist/config.cjs +1 -1
- package/dist/config.js +1 -1
- package/dist/hooks.cjs +43 -8
- package/dist/hooks.js +44 -9
- package/dist/index.cjs +43 -8
- package/dist/index.d.cts +36 -13
- package/dist/index.d.ts +36 -13
- package/dist/index.js +44 -9
- package/package.json +7 -7
- package/src/api/generated/ext_payments/CLAUDE.md +1 -8
- package/src/api/generated/ext_payments/_utils/schemas/PaymentDetail.schema.ts +1 -1
- package/src/api/generated/ext_payments/api-instance.ts +61 -13
- package/src/api/generated/ext_payments/client.ts +23 -2
- package/src/api/generated/ext_payments/http.ts +8 -2
- package/src/api/generated/ext_payments/index.ts +3 -1
- package/src/api/index.ts +6 -1
package/dist/config.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var import_ext_base = require("@djangocfg/ext-base");
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@djangocfg/ext-payments",
|
|
30
|
-
version: "1.0.
|
|
30
|
+
version: "1.0.10",
|
|
31
31
|
description: "Payments system extension for DjangoCFG",
|
|
32
32
|
keywords: [
|
|
33
33
|
"django",
|
package/dist/config.js
CHANGED
package/dist/hooks.cjs
CHANGED
|
@@ -129,7 +129,7 @@ var models_exports = {};
|
|
|
129
129
|
// src/api/generated/ext_payments/http.ts
|
|
130
130
|
var FetchAdapter = class {
|
|
131
131
|
async request(request) {
|
|
132
|
-
const { method, url, headers, body, params, formData } = request;
|
|
132
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
133
133
|
let finalUrl = url;
|
|
134
134
|
if (params) {
|
|
135
135
|
const searchParams = new URLSearchParams();
|
|
@@ -147,6 +147,9 @@ var FetchAdapter = class {
|
|
|
147
147
|
let requestBody;
|
|
148
148
|
if (formData) {
|
|
149
149
|
requestBody = formData;
|
|
150
|
+
} else if (binaryBody) {
|
|
151
|
+
finalHeaders["Content-Type"] = "application/octet-stream";
|
|
152
|
+
requestBody = binaryBody;
|
|
150
153
|
} else if (body) {
|
|
151
154
|
finalHeaders["Content-Type"] = "application/json";
|
|
152
155
|
requestBody = JSON.stringify(body);
|
|
@@ -471,11 +474,13 @@ var APIClient = class {
|
|
|
471
474
|
httpClient;
|
|
472
475
|
logger = null;
|
|
473
476
|
retryConfig = null;
|
|
477
|
+
tokenGetter = null;
|
|
474
478
|
// Sub-clients
|
|
475
479
|
ext_payments_payments;
|
|
476
480
|
constructor(baseUrl, options) {
|
|
477
481
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
478
482
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
483
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
479
484
|
if (options?.loggerConfig !== void 0) {
|
|
480
485
|
this.logger = new APILogger(options.loggerConfig);
|
|
481
486
|
}
|
|
@@ -498,6 +503,19 @@ var APIClient = class {
|
|
|
498
503
|
}
|
|
499
504
|
return null;
|
|
500
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Get the base URL for building streaming/download URLs.
|
|
508
|
+
*/
|
|
509
|
+
getBaseUrl() {
|
|
510
|
+
return this.baseUrl;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
514
|
+
* Returns null if no token getter is configured or no token is available.
|
|
515
|
+
*/
|
|
516
|
+
getToken() {
|
|
517
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
518
|
+
}
|
|
501
519
|
/**
|
|
502
520
|
* Make HTTP request with Django CSRF and session handling.
|
|
503
521
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -528,7 +546,7 @@ var APIClient = class {
|
|
|
528
546
|
const headers = {
|
|
529
547
|
...options?.headers || {}
|
|
530
548
|
};
|
|
531
|
-
if (!options?.formData && !headers["Content-Type"]) {
|
|
549
|
+
if (!options?.formData && !options?.binaryBody && !headers["Content-Type"]) {
|
|
532
550
|
headers["Content-Type"] = "application/json";
|
|
533
551
|
}
|
|
534
552
|
if (this.logger) {
|
|
@@ -547,7 +565,8 @@ var APIClient = class {
|
|
|
547
565
|
headers,
|
|
548
566
|
params: options?.params,
|
|
549
567
|
body: options?.body,
|
|
550
|
-
formData: options?.formData
|
|
568
|
+
formData: options?.formData,
|
|
569
|
+
binaryBody: options?.binaryBody
|
|
551
570
|
});
|
|
552
571
|
const duration = Date.now() - startTime;
|
|
553
572
|
if (response.status >= 400) {
|
|
@@ -883,7 +902,7 @@ var PaymentDetailSchema = zod.z.object({
|
|
|
883
902
|
status_display: zod.z.string(),
|
|
884
903
|
pay_address: zod.z.string().nullable(),
|
|
885
904
|
qr_code_url: zod.z.string().nullable(),
|
|
886
|
-
payment_url: zod.z.url().nullable(),
|
|
905
|
+
payment_url: zod.z.union([zod.z.url(), zod.z.literal("")]).nullable(),
|
|
887
906
|
transaction_hash: zod.z.string().nullable(),
|
|
888
907
|
explorer_link: zod.z.string().nullable(),
|
|
889
908
|
confirmations_count: zod.z.int(),
|
|
@@ -968,15 +987,28 @@ __export(fetchers_exports, {
|
|
|
968
987
|
|
|
969
988
|
// src/api/generated/ext_payments/api-instance.ts
|
|
970
989
|
var globalAPI = null;
|
|
990
|
+
var autoConfigAttempted = false;
|
|
991
|
+
function tryAutoConfigureFromEnv() {
|
|
992
|
+
if (autoConfigAttempted) return;
|
|
993
|
+
autoConfigAttempted = true;
|
|
994
|
+
if (globalAPI) return;
|
|
995
|
+
if (typeof process === "undefined" || !process.env) return;
|
|
996
|
+
const baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.VITE_API_URL || process.env.REACT_APP_API_URL || process.env.API_URL;
|
|
997
|
+
if (baseUrl) {
|
|
998
|
+
globalAPI = new API(baseUrl);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
971
1001
|
function getAPIInstance() {
|
|
1002
|
+
tryAutoConfigureFromEnv();
|
|
972
1003
|
if (!globalAPI) {
|
|
973
1004
|
throw new Error(
|
|
974
|
-
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
1005
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })\n\nOr set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
975
1006
|
);
|
|
976
1007
|
}
|
|
977
1008
|
return globalAPI;
|
|
978
1009
|
}
|
|
979
1010
|
function isAPIConfigured() {
|
|
1011
|
+
tryAutoConfigureFromEnv();
|
|
980
1012
|
return globalAPI !== null;
|
|
981
1013
|
}
|
|
982
1014
|
function configureAPI(config) {
|
|
@@ -1291,7 +1323,8 @@ var API = class {
|
|
|
1291
1323
|
this._loadTokensFromStorage();
|
|
1292
1324
|
this._client = new APIClient(this.baseUrl, {
|
|
1293
1325
|
retryConfig: this.options?.retryConfig,
|
|
1294
|
-
loggerConfig: this.options?.loggerConfig
|
|
1326
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1327
|
+
tokenGetter: () => this.getToken()
|
|
1295
1328
|
});
|
|
1296
1329
|
this._injectAuthHeader();
|
|
1297
1330
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1303,7 +1336,8 @@ var API = class {
|
|
|
1303
1336
|
_reinitClients() {
|
|
1304
1337
|
this._client = new APIClient(this.baseUrl, {
|
|
1305
1338
|
retryConfig: this.options?.retryConfig,
|
|
1306
|
-
loggerConfig: this.options?.loggerConfig
|
|
1339
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1340
|
+
tokenGetter: () => this.getToken()
|
|
1307
1341
|
});
|
|
1308
1342
|
this._injectAuthHeader();
|
|
1309
1343
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1394,6 +1428,7 @@ var API = class {
|
|
|
1394
1428
|
return "./schema.json";
|
|
1395
1429
|
}
|
|
1396
1430
|
};
|
|
1431
|
+
api.initializeExtensionAPI(configureAPI);
|
|
1397
1432
|
var apiPayments = api.createExtensionAPI(API);
|
|
1398
1433
|
function usePaymentsBalanceRetrieve(client) {
|
|
1399
1434
|
return useSWR__default.default(
|
|
@@ -2617,7 +2652,7 @@ var PaymentsLayout = () => {
|
|
|
2617
2652
|
// package.json
|
|
2618
2653
|
var package_default = {
|
|
2619
2654
|
name: "@djangocfg/ext-payments",
|
|
2620
|
-
version: "1.0.
|
|
2655
|
+
version: "1.0.10",
|
|
2621
2656
|
description: "Payments system extension for DjangoCFG",
|
|
2622
2657
|
keywords: [
|
|
2623
2658
|
"django",
|
package/dist/hooks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createConsola, consola } from 'consola';
|
|
2
2
|
import pRetry, { AbortError } from 'p-retry';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
4
|
+
import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
5
|
import { RefreshCw, Plus, XCircle, ExternalLink, Wallet, CreditCard, History, Clock, AlertCircle, CheckCircle2, Search, Filter, ArrowDownLeft, ArrowUpRight } from 'lucide-react';
|
|
6
6
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormDescription, FormMessage, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, TokenIcon, DialogFooter, Button, CopyButton, Tabs, TabsList, TabsTrigger, TabsContent, Card, CardHeader, CardTitle, Skeleton, CardContent, Badge, Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '@djangocfg/ui-core';
|
|
7
7
|
import { createContext, useContext, useState, useMemo, useEffect } from 'react';
|
|
@@ -121,7 +121,7 @@ var models_exports = {};
|
|
|
121
121
|
// src/api/generated/ext_payments/http.ts
|
|
122
122
|
var FetchAdapter = class {
|
|
123
123
|
async request(request) {
|
|
124
|
-
const { method, url, headers, body, params, formData } = request;
|
|
124
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
125
125
|
let finalUrl = url;
|
|
126
126
|
if (params) {
|
|
127
127
|
const searchParams = new URLSearchParams();
|
|
@@ -139,6 +139,9 @@ var FetchAdapter = class {
|
|
|
139
139
|
let requestBody;
|
|
140
140
|
if (formData) {
|
|
141
141
|
requestBody = formData;
|
|
142
|
+
} else if (binaryBody) {
|
|
143
|
+
finalHeaders["Content-Type"] = "application/octet-stream";
|
|
144
|
+
requestBody = binaryBody;
|
|
142
145
|
} else if (body) {
|
|
143
146
|
finalHeaders["Content-Type"] = "application/json";
|
|
144
147
|
requestBody = JSON.stringify(body);
|
|
@@ -463,11 +466,13 @@ var APIClient = class {
|
|
|
463
466
|
httpClient;
|
|
464
467
|
logger = null;
|
|
465
468
|
retryConfig = null;
|
|
469
|
+
tokenGetter = null;
|
|
466
470
|
// Sub-clients
|
|
467
471
|
ext_payments_payments;
|
|
468
472
|
constructor(baseUrl, options) {
|
|
469
473
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
470
474
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
475
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
471
476
|
if (options?.loggerConfig !== void 0) {
|
|
472
477
|
this.logger = new APILogger(options.loggerConfig);
|
|
473
478
|
}
|
|
@@ -490,6 +495,19 @@ var APIClient = class {
|
|
|
490
495
|
}
|
|
491
496
|
return null;
|
|
492
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Get the base URL for building streaming/download URLs.
|
|
500
|
+
*/
|
|
501
|
+
getBaseUrl() {
|
|
502
|
+
return this.baseUrl;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
506
|
+
* Returns null if no token getter is configured or no token is available.
|
|
507
|
+
*/
|
|
508
|
+
getToken() {
|
|
509
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
510
|
+
}
|
|
493
511
|
/**
|
|
494
512
|
* Make HTTP request with Django CSRF and session handling.
|
|
495
513
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -520,7 +538,7 @@ var APIClient = class {
|
|
|
520
538
|
const headers = {
|
|
521
539
|
...options?.headers || {}
|
|
522
540
|
};
|
|
523
|
-
if (!options?.formData && !headers["Content-Type"]) {
|
|
541
|
+
if (!options?.formData && !options?.binaryBody && !headers["Content-Type"]) {
|
|
524
542
|
headers["Content-Type"] = "application/json";
|
|
525
543
|
}
|
|
526
544
|
if (this.logger) {
|
|
@@ -539,7 +557,8 @@ var APIClient = class {
|
|
|
539
557
|
headers,
|
|
540
558
|
params: options?.params,
|
|
541
559
|
body: options?.body,
|
|
542
|
-
formData: options?.formData
|
|
560
|
+
formData: options?.formData,
|
|
561
|
+
binaryBody: options?.binaryBody
|
|
543
562
|
});
|
|
544
563
|
const duration = Date.now() - startTime;
|
|
545
564
|
if (response.status >= 400) {
|
|
@@ -875,7 +894,7 @@ var PaymentDetailSchema = z.object({
|
|
|
875
894
|
status_display: z.string(),
|
|
876
895
|
pay_address: z.string().nullable(),
|
|
877
896
|
qr_code_url: z.string().nullable(),
|
|
878
|
-
payment_url: z.url().nullable(),
|
|
897
|
+
payment_url: z.union([z.url(), z.literal("")]).nullable(),
|
|
879
898
|
transaction_hash: z.string().nullable(),
|
|
880
899
|
explorer_link: z.string().nullable(),
|
|
881
900
|
confirmations_count: z.int(),
|
|
@@ -960,15 +979,28 @@ __export(fetchers_exports, {
|
|
|
960
979
|
|
|
961
980
|
// src/api/generated/ext_payments/api-instance.ts
|
|
962
981
|
var globalAPI = null;
|
|
982
|
+
var autoConfigAttempted = false;
|
|
983
|
+
function tryAutoConfigureFromEnv() {
|
|
984
|
+
if (autoConfigAttempted) return;
|
|
985
|
+
autoConfigAttempted = true;
|
|
986
|
+
if (globalAPI) return;
|
|
987
|
+
if (typeof process === "undefined" || !process.env) return;
|
|
988
|
+
const baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.VITE_API_URL || process.env.REACT_APP_API_URL || process.env.API_URL;
|
|
989
|
+
if (baseUrl) {
|
|
990
|
+
globalAPI = new API(baseUrl);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
963
993
|
function getAPIInstance() {
|
|
994
|
+
tryAutoConfigureFromEnv();
|
|
964
995
|
if (!globalAPI) {
|
|
965
996
|
throw new Error(
|
|
966
|
-
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
997
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })\n\nOr set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
967
998
|
);
|
|
968
999
|
}
|
|
969
1000
|
return globalAPI;
|
|
970
1001
|
}
|
|
971
1002
|
function isAPIConfigured() {
|
|
1003
|
+
tryAutoConfigureFromEnv();
|
|
972
1004
|
return globalAPI !== null;
|
|
973
1005
|
}
|
|
974
1006
|
function configureAPI(config) {
|
|
@@ -1283,7 +1315,8 @@ var API = class {
|
|
|
1283
1315
|
this._loadTokensFromStorage();
|
|
1284
1316
|
this._client = new APIClient(this.baseUrl, {
|
|
1285
1317
|
retryConfig: this.options?.retryConfig,
|
|
1286
|
-
loggerConfig: this.options?.loggerConfig
|
|
1318
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1319
|
+
tokenGetter: () => this.getToken()
|
|
1287
1320
|
});
|
|
1288
1321
|
this._injectAuthHeader();
|
|
1289
1322
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1295,7 +1328,8 @@ var API = class {
|
|
|
1295
1328
|
_reinitClients() {
|
|
1296
1329
|
this._client = new APIClient(this.baseUrl, {
|
|
1297
1330
|
retryConfig: this.options?.retryConfig,
|
|
1298
|
-
loggerConfig: this.options?.loggerConfig
|
|
1331
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1332
|
+
tokenGetter: () => this.getToken()
|
|
1299
1333
|
});
|
|
1300
1334
|
this._injectAuthHeader();
|
|
1301
1335
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1386,6 +1420,7 @@ var API = class {
|
|
|
1386
1420
|
return "./schema.json";
|
|
1387
1421
|
}
|
|
1388
1422
|
};
|
|
1423
|
+
initializeExtensionAPI(configureAPI);
|
|
1389
1424
|
var apiPayments = createExtensionAPI(API);
|
|
1390
1425
|
function usePaymentsBalanceRetrieve(client) {
|
|
1391
1426
|
return useSWR(
|
|
@@ -2609,7 +2644,7 @@ var PaymentsLayout = () => {
|
|
|
2609
2644
|
// package.json
|
|
2610
2645
|
var package_default = {
|
|
2611
2646
|
name: "@djangocfg/ext-payments",
|
|
2612
|
-
version: "1.0.
|
|
2647
|
+
version: "1.0.10",
|
|
2613
2648
|
description: "Payments system extension for DjangoCFG",
|
|
2614
2649
|
keywords: [
|
|
2615
2650
|
"django",
|
package/dist/index.cjs
CHANGED
|
@@ -129,7 +129,7 @@ var models_exports = {};
|
|
|
129
129
|
// src/api/generated/ext_payments/http.ts
|
|
130
130
|
var FetchAdapter = class {
|
|
131
131
|
async request(request) {
|
|
132
|
-
const { method, url, headers, body, params, formData } = request;
|
|
132
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
133
133
|
let finalUrl = url;
|
|
134
134
|
if (params) {
|
|
135
135
|
const searchParams = new URLSearchParams();
|
|
@@ -147,6 +147,9 @@ var FetchAdapter = class {
|
|
|
147
147
|
let requestBody;
|
|
148
148
|
if (formData) {
|
|
149
149
|
requestBody = formData;
|
|
150
|
+
} else if (binaryBody) {
|
|
151
|
+
finalHeaders["Content-Type"] = "application/octet-stream";
|
|
152
|
+
requestBody = binaryBody;
|
|
150
153
|
} else if (body) {
|
|
151
154
|
finalHeaders["Content-Type"] = "application/json";
|
|
152
155
|
requestBody = JSON.stringify(body);
|
|
@@ -471,11 +474,13 @@ var APIClient = class {
|
|
|
471
474
|
httpClient;
|
|
472
475
|
logger = null;
|
|
473
476
|
retryConfig = null;
|
|
477
|
+
tokenGetter = null;
|
|
474
478
|
// Sub-clients
|
|
475
479
|
ext_payments_payments;
|
|
476
480
|
constructor(baseUrl, options) {
|
|
477
481
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
478
482
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
483
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
479
484
|
if (options?.loggerConfig !== void 0) {
|
|
480
485
|
this.logger = new APILogger(options.loggerConfig);
|
|
481
486
|
}
|
|
@@ -498,6 +503,19 @@ var APIClient = class {
|
|
|
498
503
|
}
|
|
499
504
|
return null;
|
|
500
505
|
}
|
|
506
|
+
/**
|
|
507
|
+
* Get the base URL for building streaming/download URLs.
|
|
508
|
+
*/
|
|
509
|
+
getBaseUrl() {
|
|
510
|
+
return this.baseUrl;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
514
|
+
* Returns null if no token getter is configured or no token is available.
|
|
515
|
+
*/
|
|
516
|
+
getToken() {
|
|
517
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
518
|
+
}
|
|
501
519
|
/**
|
|
502
520
|
* Make HTTP request with Django CSRF and session handling.
|
|
503
521
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -528,7 +546,7 @@ var APIClient = class {
|
|
|
528
546
|
const headers = {
|
|
529
547
|
...options?.headers || {}
|
|
530
548
|
};
|
|
531
|
-
if (!options?.formData && !headers["Content-Type"]) {
|
|
549
|
+
if (!options?.formData && !options?.binaryBody && !headers["Content-Type"]) {
|
|
532
550
|
headers["Content-Type"] = "application/json";
|
|
533
551
|
}
|
|
534
552
|
if (this.logger) {
|
|
@@ -547,7 +565,8 @@ var APIClient = class {
|
|
|
547
565
|
headers,
|
|
548
566
|
params: options?.params,
|
|
549
567
|
body: options?.body,
|
|
550
|
-
formData: options?.formData
|
|
568
|
+
formData: options?.formData,
|
|
569
|
+
binaryBody: options?.binaryBody
|
|
551
570
|
});
|
|
552
571
|
const duration = Date.now() - startTime;
|
|
553
572
|
if (response.status >= 400) {
|
|
@@ -883,7 +902,7 @@ var PaymentDetailSchema = zod.z.object({
|
|
|
883
902
|
status_display: zod.z.string(),
|
|
884
903
|
pay_address: zod.z.string().nullable(),
|
|
885
904
|
qr_code_url: zod.z.string().nullable(),
|
|
886
|
-
payment_url: zod.z.url().nullable(),
|
|
905
|
+
payment_url: zod.z.union([zod.z.url(), zod.z.literal("")]).nullable(),
|
|
887
906
|
transaction_hash: zod.z.string().nullable(),
|
|
888
907
|
explorer_link: zod.z.string().nullable(),
|
|
889
908
|
confirmations_count: zod.z.int(),
|
|
@@ -968,15 +987,28 @@ __export(fetchers_exports, {
|
|
|
968
987
|
|
|
969
988
|
// src/api/generated/ext_payments/api-instance.ts
|
|
970
989
|
var globalAPI = null;
|
|
990
|
+
var autoConfigAttempted = false;
|
|
991
|
+
function tryAutoConfigureFromEnv() {
|
|
992
|
+
if (autoConfigAttempted) return;
|
|
993
|
+
autoConfigAttempted = true;
|
|
994
|
+
if (globalAPI) return;
|
|
995
|
+
if (typeof process === "undefined" || !process.env) return;
|
|
996
|
+
const baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.VITE_API_URL || process.env.REACT_APP_API_URL || process.env.API_URL;
|
|
997
|
+
if (baseUrl) {
|
|
998
|
+
globalAPI = new API(baseUrl);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
971
1001
|
function getAPIInstance() {
|
|
1002
|
+
tryAutoConfigureFromEnv();
|
|
972
1003
|
if (!globalAPI) {
|
|
973
1004
|
throw new Error(
|
|
974
|
-
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
1005
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })\n\nOr set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
975
1006
|
);
|
|
976
1007
|
}
|
|
977
1008
|
return globalAPI;
|
|
978
1009
|
}
|
|
979
1010
|
function isAPIConfigured() {
|
|
1011
|
+
tryAutoConfigureFromEnv();
|
|
980
1012
|
return globalAPI !== null;
|
|
981
1013
|
}
|
|
982
1014
|
function configureAPI(config) {
|
|
@@ -1291,7 +1323,8 @@ var API = class {
|
|
|
1291
1323
|
this._loadTokensFromStorage();
|
|
1292
1324
|
this._client = new APIClient(this.baseUrl, {
|
|
1293
1325
|
retryConfig: this.options?.retryConfig,
|
|
1294
|
-
loggerConfig: this.options?.loggerConfig
|
|
1326
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1327
|
+
tokenGetter: () => this.getToken()
|
|
1295
1328
|
});
|
|
1296
1329
|
this._injectAuthHeader();
|
|
1297
1330
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1303,7 +1336,8 @@ var API = class {
|
|
|
1303
1336
|
_reinitClients() {
|
|
1304
1337
|
this._client = new APIClient(this.baseUrl, {
|
|
1305
1338
|
retryConfig: this.options?.retryConfig,
|
|
1306
|
-
loggerConfig: this.options?.loggerConfig
|
|
1339
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1340
|
+
tokenGetter: () => this.getToken()
|
|
1307
1341
|
});
|
|
1308
1342
|
this._injectAuthHeader();
|
|
1309
1343
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1394,6 +1428,7 @@ var API = class {
|
|
|
1394
1428
|
return "./schema.json";
|
|
1395
1429
|
}
|
|
1396
1430
|
};
|
|
1431
|
+
api.initializeExtensionAPI(configureAPI);
|
|
1397
1432
|
var apiPayments = api.createExtensionAPI(API);
|
|
1398
1433
|
function usePaymentsBalanceRetrieve(client) {
|
|
1399
1434
|
return useSWR__default.default(
|
|
@@ -2561,7 +2596,7 @@ var PaymentsLayout = () => {
|
|
|
2561
2596
|
// package.json
|
|
2562
2597
|
var package_default = {
|
|
2563
2598
|
name: "@djangocfg/ext-payments",
|
|
2564
|
-
version: "1.0.
|
|
2599
|
+
version: "1.0.10",
|
|
2565
2600
|
description: "Payments system extension for DjangoCFG",
|
|
2566
2601
|
keywords: [
|
|
2567
2602
|
"django",
|
package/dist/index.d.cts
CHANGED
|
@@ -279,6 +279,8 @@ interface HttpRequest {
|
|
|
279
279
|
params?: Record<string, any>;
|
|
280
280
|
/** FormData for file uploads (multipart/form-data) */
|
|
281
281
|
formData?: FormData;
|
|
282
|
+
/** Binary data for octet-stream uploads */
|
|
283
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
282
284
|
}
|
|
283
285
|
interface HttpResponse<T = any> {
|
|
284
286
|
data: T;
|
|
@@ -531,11 +533,13 @@ declare class APIClient {
|
|
|
531
533
|
private httpClient;
|
|
532
534
|
private logger;
|
|
533
535
|
private retryConfig;
|
|
536
|
+
private tokenGetter;
|
|
534
537
|
ext_payments_payments: ExtPaymentsPayments;
|
|
535
538
|
constructor(baseUrl: string, options?: {
|
|
536
539
|
httpClient?: HttpClientAdapter;
|
|
537
540
|
loggerConfig?: Partial<LoggerConfig>;
|
|
538
541
|
retryConfig?: RetryConfig;
|
|
542
|
+
tokenGetter?: () => string | null;
|
|
539
543
|
});
|
|
540
544
|
/**
|
|
541
545
|
* Get CSRF token from cookies (for SessionAuthentication).
|
|
@@ -543,6 +547,15 @@ declare class APIClient {
|
|
|
543
547
|
* Returns null if cookie doesn't exist (JWT-only auth).
|
|
544
548
|
*/
|
|
545
549
|
getCsrfToken(): string | null;
|
|
550
|
+
/**
|
|
551
|
+
* Get the base URL for building streaming/download URLs.
|
|
552
|
+
*/
|
|
553
|
+
getBaseUrl(): string;
|
|
554
|
+
/**
|
|
555
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
556
|
+
* Returns null if no token getter is configured or no token is available.
|
|
557
|
+
*/
|
|
558
|
+
getToken(): string | null;
|
|
546
559
|
/**
|
|
547
560
|
* Make HTTP request with Django CSRF and session handling.
|
|
548
561
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -551,6 +564,7 @@ declare class APIClient {
|
|
|
551
564
|
params?: Record<string, any>;
|
|
552
565
|
body?: any;
|
|
553
566
|
formData?: FormData;
|
|
567
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
554
568
|
headers?: Record<string, string>;
|
|
555
569
|
}): Promise<T>;
|
|
556
570
|
/**
|
|
@@ -715,7 +729,7 @@ declare const PaymentDetailSchema: z.ZodObject<{
|
|
|
715
729
|
status_display: z.ZodString;
|
|
716
730
|
pay_address: z.ZodNullable<z.ZodString>;
|
|
717
731
|
qr_code_url: z.ZodNullable<z.ZodString>;
|
|
718
|
-
payment_url: z.ZodNullable<z.ZodURL
|
|
732
|
+
payment_url: z.ZodNullable<z.ZodUnion<readonly [z.ZodURL, z.ZodLiteral<"">]>>;
|
|
719
733
|
transaction_hash: z.ZodNullable<z.ZodString>;
|
|
720
734
|
explorer_link: z.ZodNullable<z.ZodString>;
|
|
721
735
|
confirmations_count: z.ZodInt;
|
|
@@ -995,30 +1009,38 @@ declare namespace index {
|
|
|
995
1009
|
}
|
|
996
1010
|
|
|
997
1011
|
/**
|
|
998
|
-
* Global API Instance - Singleton configuration
|
|
1012
|
+
* Global API Instance - Singleton configuration with auto-configuration support
|
|
999
1013
|
*
|
|
1000
|
-
* This module provides a global API instance that
|
|
1001
|
-
*
|
|
1014
|
+
* This module provides a global API instance that auto-configures from
|
|
1015
|
+
* environment variables or can be configured manually.
|
|
1002
1016
|
*
|
|
1003
|
-
*
|
|
1017
|
+
* AUTO-CONFIGURATION (recommended):
|
|
1018
|
+
* Set one of these environment variables and the API will auto-configure:
|
|
1019
|
+
* - NEXT_PUBLIC_API_URL (Next.js)
|
|
1020
|
+
* - VITE_API_URL (Vite)
|
|
1021
|
+
* - REACT_APP_API_URL (Create React App)
|
|
1022
|
+
* - API_URL (generic)
|
|
1023
|
+
*
|
|
1024
|
+
* Then just use fetchers and hooks directly:
|
|
1025
|
+
* ```typescript
|
|
1026
|
+
* import { getUsers } from './_utils/fetchers'
|
|
1027
|
+
* const users = await getUsers({ page: 1 })
|
|
1028
|
+
* ```
|
|
1029
|
+
*
|
|
1030
|
+
* MANUAL CONFIGURATION:
|
|
1004
1031
|
* ```typescript
|
|
1005
|
-
* // Configure once (e.g., in your app entry point)
|
|
1006
1032
|
* import { configureAPI } from './api-instance'
|
|
1007
1033
|
*
|
|
1008
1034
|
* configureAPI({
|
|
1009
1035
|
* baseUrl: 'https://api.example.com',
|
|
1010
1036
|
* token: 'your-jwt-token'
|
|
1011
1037
|
* })
|
|
1012
|
-
*
|
|
1013
|
-
* // Then use fetchers and hooks anywhere without configuration
|
|
1014
|
-
* import { getUsers } from './fetchers'
|
|
1015
|
-
* const users = await getUsers({ page: 1 })
|
|
1016
1038
|
* ```
|
|
1017
1039
|
*
|
|
1018
1040
|
* For SSR or multiple instances:
|
|
1019
1041
|
* ```typescript
|
|
1020
1042
|
* import { API } from './index'
|
|
1021
|
-
* import { getUsers } from './fetchers'
|
|
1043
|
+
* import { getUsers } from './_utils/fetchers'
|
|
1022
1044
|
*
|
|
1023
1045
|
* const api = new API('https://api.example.com')
|
|
1024
1046
|
* const users = await getUsers({ page: 1 }, api)
|
|
@@ -1027,11 +1049,12 @@ declare namespace index {
|
|
|
1027
1049
|
|
|
1028
1050
|
/**
|
|
1029
1051
|
* Get the global API instance
|
|
1030
|
-
*
|
|
1052
|
+
* Auto-configures from environment variables on first call if not manually configured.
|
|
1053
|
+
* @throws Error if API is not configured and no env variable is set
|
|
1031
1054
|
*/
|
|
1032
1055
|
declare function getAPIInstance(): API;
|
|
1033
1056
|
/**
|
|
1034
|
-
* Check if API is configured
|
|
1057
|
+
* Check if API is configured (or can be auto-configured)
|
|
1035
1058
|
*/
|
|
1036
1059
|
declare function isAPIConfigured(): boolean;
|
|
1037
1060
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -279,6 +279,8 @@ interface HttpRequest {
|
|
|
279
279
|
params?: Record<string, any>;
|
|
280
280
|
/** FormData for file uploads (multipart/form-data) */
|
|
281
281
|
formData?: FormData;
|
|
282
|
+
/** Binary data for octet-stream uploads */
|
|
283
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
282
284
|
}
|
|
283
285
|
interface HttpResponse<T = any> {
|
|
284
286
|
data: T;
|
|
@@ -531,11 +533,13 @@ declare class APIClient {
|
|
|
531
533
|
private httpClient;
|
|
532
534
|
private logger;
|
|
533
535
|
private retryConfig;
|
|
536
|
+
private tokenGetter;
|
|
534
537
|
ext_payments_payments: ExtPaymentsPayments;
|
|
535
538
|
constructor(baseUrl: string, options?: {
|
|
536
539
|
httpClient?: HttpClientAdapter;
|
|
537
540
|
loggerConfig?: Partial<LoggerConfig>;
|
|
538
541
|
retryConfig?: RetryConfig;
|
|
542
|
+
tokenGetter?: () => string | null;
|
|
539
543
|
});
|
|
540
544
|
/**
|
|
541
545
|
* Get CSRF token from cookies (for SessionAuthentication).
|
|
@@ -543,6 +547,15 @@ declare class APIClient {
|
|
|
543
547
|
* Returns null if cookie doesn't exist (JWT-only auth).
|
|
544
548
|
*/
|
|
545
549
|
getCsrfToken(): string | null;
|
|
550
|
+
/**
|
|
551
|
+
* Get the base URL for building streaming/download URLs.
|
|
552
|
+
*/
|
|
553
|
+
getBaseUrl(): string;
|
|
554
|
+
/**
|
|
555
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
556
|
+
* Returns null if no token getter is configured or no token is available.
|
|
557
|
+
*/
|
|
558
|
+
getToken(): string | null;
|
|
546
559
|
/**
|
|
547
560
|
* Make HTTP request with Django CSRF and session handling.
|
|
548
561
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -551,6 +564,7 @@ declare class APIClient {
|
|
|
551
564
|
params?: Record<string, any>;
|
|
552
565
|
body?: any;
|
|
553
566
|
formData?: FormData;
|
|
567
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
554
568
|
headers?: Record<string, string>;
|
|
555
569
|
}): Promise<T>;
|
|
556
570
|
/**
|
|
@@ -715,7 +729,7 @@ declare const PaymentDetailSchema: z.ZodObject<{
|
|
|
715
729
|
status_display: z.ZodString;
|
|
716
730
|
pay_address: z.ZodNullable<z.ZodString>;
|
|
717
731
|
qr_code_url: z.ZodNullable<z.ZodString>;
|
|
718
|
-
payment_url: z.ZodNullable<z.ZodURL
|
|
732
|
+
payment_url: z.ZodNullable<z.ZodUnion<readonly [z.ZodURL, z.ZodLiteral<"">]>>;
|
|
719
733
|
transaction_hash: z.ZodNullable<z.ZodString>;
|
|
720
734
|
explorer_link: z.ZodNullable<z.ZodString>;
|
|
721
735
|
confirmations_count: z.ZodInt;
|
|
@@ -995,30 +1009,38 @@ declare namespace index {
|
|
|
995
1009
|
}
|
|
996
1010
|
|
|
997
1011
|
/**
|
|
998
|
-
* Global API Instance - Singleton configuration
|
|
1012
|
+
* Global API Instance - Singleton configuration with auto-configuration support
|
|
999
1013
|
*
|
|
1000
|
-
* This module provides a global API instance that
|
|
1001
|
-
*
|
|
1014
|
+
* This module provides a global API instance that auto-configures from
|
|
1015
|
+
* environment variables or can be configured manually.
|
|
1002
1016
|
*
|
|
1003
|
-
*
|
|
1017
|
+
* AUTO-CONFIGURATION (recommended):
|
|
1018
|
+
* Set one of these environment variables and the API will auto-configure:
|
|
1019
|
+
* - NEXT_PUBLIC_API_URL (Next.js)
|
|
1020
|
+
* - VITE_API_URL (Vite)
|
|
1021
|
+
* - REACT_APP_API_URL (Create React App)
|
|
1022
|
+
* - API_URL (generic)
|
|
1023
|
+
*
|
|
1024
|
+
* Then just use fetchers and hooks directly:
|
|
1025
|
+
* ```typescript
|
|
1026
|
+
* import { getUsers } from './_utils/fetchers'
|
|
1027
|
+
* const users = await getUsers({ page: 1 })
|
|
1028
|
+
* ```
|
|
1029
|
+
*
|
|
1030
|
+
* MANUAL CONFIGURATION:
|
|
1004
1031
|
* ```typescript
|
|
1005
|
-
* // Configure once (e.g., in your app entry point)
|
|
1006
1032
|
* import { configureAPI } from './api-instance'
|
|
1007
1033
|
*
|
|
1008
1034
|
* configureAPI({
|
|
1009
1035
|
* baseUrl: 'https://api.example.com',
|
|
1010
1036
|
* token: 'your-jwt-token'
|
|
1011
1037
|
* })
|
|
1012
|
-
*
|
|
1013
|
-
* // Then use fetchers and hooks anywhere without configuration
|
|
1014
|
-
* import { getUsers } from './fetchers'
|
|
1015
|
-
* const users = await getUsers({ page: 1 })
|
|
1016
1038
|
* ```
|
|
1017
1039
|
*
|
|
1018
1040
|
* For SSR or multiple instances:
|
|
1019
1041
|
* ```typescript
|
|
1020
1042
|
* import { API } from './index'
|
|
1021
|
-
* import { getUsers } from './fetchers'
|
|
1043
|
+
* import { getUsers } from './_utils/fetchers'
|
|
1022
1044
|
*
|
|
1023
1045
|
* const api = new API('https://api.example.com')
|
|
1024
1046
|
* const users = await getUsers({ page: 1 }, api)
|
|
@@ -1027,11 +1049,12 @@ declare namespace index {
|
|
|
1027
1049
|
|
|
1028
1050
|
/**
|
|
1029
1051
|
* Get the global API instance
|
|
1030
|
-
*
|
|
1052
|
+
* Auto-configures from environment variables on first call if not manually configured.
|
|
1053
|
+
* @throws Error if API is not configured and no env variable is set
|
|
1031
1054
|
*/
|
|
1032
1055
|
declare function getAPIInstance(): API;
|
|
1033
1056
|
/**
|
|
1034
|
-
* Check if API is configured
|
|
1057
|
+
* Check if API is configured (or can be auto-configured)
|
|
1035
1058
|
*/
|
|
1036
1059
|
declare function isAPIConfigured(): boolean;
|
|
1037
1060
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createConsola, consola } from 'consola';
|
|
2
2
|
import pRetry, { AbortError } from 'p-retry';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
4
|
+
import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
5
|
import { Wallet, CreditCard, History, RefreshCw, Plus, XCircle, ExternalLink, Search, Filter, Clock, AlertCircle, CheckCircle2, ArrowDownLeft, ArrowUpRight } from 'lucide-react';
|
|
6
6
|
import { Tabs, TabsList, TabsTrigger, TabsContent, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Form, FormField, FormItem, FormLabel, FormControl, Input, FormDescription, FormMessage, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, TokenIcon, DialogFooter, Button, CopyButton, Card, CardHeader, CardTitle, Skeleton, CardContent, Badge, Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '@djangocfg/ui-core';
|
|
7
7
|
import { createContext, useState, useMemo, useEffect, useContext } from 'react';
|
|
@@ -121,7 +121,7 @@ var models_exports = {};
|
|
|
121
121
|
// src/api/generated/ext_payments/http.ts
|
|
122
122
|
var FetchAdapter = class {
|
|
123
123
|
async request(request) {
|
|
124
|
-
const { method, url, headers, body, params, formData } = request;
|
|
124
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
125
125
|
let finalUrl = url;
|
|
126
126
|
if (params) {
|
|
127
127
|
const searchParams = new URLSearchParams();
|
|
@@ -139,6 +139,9 @@ var FetchAdapter = class {
|
|
|
139
139
|
let requestBody;
|
|
140
140
|
if (formData) {
|
|
141
141
|
requestBody = formData;
|
|
142
|
+
} else if (binaryBody) {
|
|
143
|
+
finalHeaders["Content-Type"] = "application/octet-stream";
|
|
144
|
+
requestBody = binaryBody;
|
|
142
145
|
} else if (body) {
|
|
143
146
|
finalHeaders["Content-Type"] = "application/json";
|
|
144
147
|
requestBody = JSON.stringify(body);
|
|
@@ -463,11 +466,13 @@ var APIClient = class {
|
|
|
463
466
|
httpClient;
|
|
464
467
|
logger = null;
|
|
465
468
|
retryConfig = null;
|
|
469
|
+
tokenGetter = null;
|
|
466
470
|
// Sub-clients
|
|
467
471
|
ext_payments_payments;
|
|
468
472
|
constructor(baseUrl, options) {
|
|
469
473
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
470
474
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
475
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
471
476
|
if (options?.loggerConfig !== void 0) {
|
|
472
477
|
this.logger = new APILogger(options.loggerConfig);
|
|
473
478
|
}
|
|
@@ -490,6 +495,19 @@ var APIClient = class {
|
|
|
490
495
|
}
|
|
491
496
|
return null;
|
|
492
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Get the base URL for building streaming/download URLs.
|
|
500
|
+
*/
|
|
501
|
+
getBaseUrl() {
|
|
502
|
+
return this.baseUrl;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
506
|
+
* Returns null if no token getter is configured or no token is available.
|
|
507
|
+
*/
|
|
508
|
+
getToken() {
|
|
509
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
510
|
+
}
|
|
493
511
|
/**
|
|
494
512
|
* Make HTTP request with Django CSRF and session handling.
|
|
495
513
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -520,7 +538,7 @@ var APIClient = class {
|
|
|
520
538
|
const headers = {
|
|
521
539
|
...options?.headers || {}
|
|
522
540
|
};
|
|
523
|
-
if (!options?.formData && !headers["Content-Type"]) {
|
|
541
|
+
if (!options?.formData && !options?.binaryBody && !headers["Content-Type"]) {
|
|
524
542
|
headers["Content-Type"] = "application/json";
|
|
525
543
|
}
|
|
526
544
|
if (this.logger) {
|
|
@@ -539,7 +557,8 @@ var APIClient = class {
|
|
|
539
557
|
headers,
|
|
540
558
|
params: options?.params,
|
|
541
559
|
body: options?.body,
|
|
542
|
-
formData: options?.formData
|
|
560
|
+
formData: options?.formData,
|
|
561
|
+
binaryBody: options?.binaryBody
|
|
543
562
|
});
|
|
544
563
|
const duration = Date.now() - startTime;
|
|
545
564
|
if (response.status >= 400) {
|
|
@@ -875,7 +894,7 @@ var PaymentDetailSchema = z.object({
|
|
|
875
894
|
status_display: z.string(),
|
|
876
895
|
pay_address: z.string().nullable(),
|
|
877
896
|
qr_code_url: z.string().nullable(),
|
|
878
|
-
payment_url: z.url().nullable(),
|
|
897
|
+
payment_url: z.union([z.url(), z.literal("")]).nullable(),
|
|
879
898
|
transaction_hash: z.string().nullable(),
|
|
880
899
|
explorer_link: z.string().nullable(),
|
|
881
900
|
confirmations_count: z.int(),
|
|
@@ -960,15 +979,28 @@ __export(fetchers_exports, {
|
|
|
960
979
|
|
|
961
980
|
// src/api/generated/ext_payments/api-instance.ts
|
|
962
981
|
var globalAPI = null;
|
|
982
|
+
var autoConfigAttempted = false;
|
|
983
|
+
function tryAutoConfigureFromEnv() {
|
|
984
|
+
if (autoConfigAttempted) return;
|
|
985
|
+
autoConfigAttempted = true;
|
|
986
|
+
if (globalAPI) return;
|
|
987
|
+
if (typeof process === "undefined" || !process.env) return;
|
|
988
|
+
const baseUrl = process.env.NEXT_PUBLIC_API_URL || process.env.VITE_API_URL || process.env.REACT_APP_API_URL || process.env.API_URL;
|
|
989
|
+
if (baseUrl) {
|
|
990
|
+
globalAPI = new API(baseUrl);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
963
993
|
function getAPIInstance() {
|
|
994
|
+
tryAutoConfigureFromEnv();
|
|
964
995
|
if (!globalAPI) {
|
|
965
996
|
throw new Error(
|
|
966
|
-
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })'
|
|
997
|
+
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\nExample:\n import { configureAPI } from "./api-instance"\n configureAPI({ baseUrl: "https://api.example.com" })\n\nOr set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
967
998
|
);
|
|
968
999
|
}
|
|
969
1000
|
return globalAPI;
|
|
970
1001
|
}
|
|
971
1002
|
function isAPIConfigured() {
|
|
1003
|
+
tryAutoConfigureFromEnv();
|
|
972
1004
|
return globalAPI !== null;
|
|
973
1005
|
}
|
|
974
1006
|
function configureAPI(config) {
|
|
@@ -1283,7 +1315,8 @@ var API = class {
|
|
|
1283
1315
|
this._loadTokensFromStorage();
|
|
1284
1316
|
this._client = new APIClient(this.baseUrl, {
|
|
1285
1317
|
retryConfig: this.options?.retryConfig,
|
|
1286
|
-
loggerConfig: this.options?.loggerConfig
|
|
1318
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1319
|
+
tokenGetter: () => this.getToken()
|
|
1287
1320
|
});
|
|
1288
1321
|
this._injectAuthHeader();
|
|
1289
1322
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1295,7 +1328,8 @@ var API = class {
|
|
|
1295
1328
|
_reinitClients() {
|
|
1296
1329
|
this._client = new APIClient(this.baseUrl, {
|
|
1297
1330
|
retryConfig: this.options?.retryConfig,
|
|
1298
|
-
loggerConfig: this.options?.loggerConfig
|
|
1331
|
+
loggerConfig: this.options?.loggerConfig,
|
|
1332
|
+
tokenGetter: () => this.getToken()
|
|
1299
1333
|
});
|
|
1300
1334
|
this._injectAuthHeader();
|
|
1301
1335
|
this.ext_payments_payments = this._client.ext_payments_payments;
|
|
@@ -1386,6 +1420,7 @@ var API = class {
|
|
|
1386
1420
|
return "./schema.json";
|
|
1387
1421
|
}
|
|
1388
1422
|
};
|
|
1423
|
+
initializeExtensionAPI(configureAPI);
|
|
1389
1424
|
var apiPayments = createExtensionAPI(API);
|
|
1390
1425
|
function usePaymentsBalanceRetrieve(client) {
|
|
1391
1426
|
return useSWR(
|
|
@@ -2553,7 +2588,7 @@ var PaymentsLayout = () => {
|
|
|
2553
2588
|
// package.json
|
|
2554
2589
|
var package_default = {
|
|
2555
2590
|
name: "@djangocfg/ext-payments",
|
|
2556
|
-
version: "1.0.
|
|
2591
|
+
version: "1.0.10",
|
|
2557
2592
|
description: "Payments system extension for DjangoCFG",
|
|
2558
2593
|
keywords: [
|
|
2559
2594
|
"django",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ext-payments",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Payments system extension for DjangoCFG",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
"check": "tsc --noEmit"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
|
-
"@djangocfg/api": "^2.1.
|
|
62
|
+
"@djangocfg/api": "^2.1.107",
|
|
63
63
|
"@djangocfg/ext-base": "^1.0.8",
|
|
64
|
-
"@djangocfg/ui-core": "^2.1.
|
|
65
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
64
|
+
"@djangocfg/ui-core": "^2.1.107",
|
|
65
|
+
"@djangocfg/ui-nextjs": "^2.1.107",
|
|
66
66
|
"consola": "^3.4.2",
|
|
67
67
|
"lucide-react": "^0.545.0",
|
|
68
68
|
"next": "^15.5.7",
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"moment": "^2.30.1"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@djangocfg/api": "^2.1.
|
|
76
|
+
"@djangocfg/api": "^2.1.107",
|
|
77
77
|
"@djangocfg/ext-base": "^1.0.8",
|
|
78
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
79
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
78
|
+
"@djangocfg/typescript-config": "^2.1.107",
|
|
79
|
+
"@djangocfg/ui-nextjs": "^2.1.107",
|
|
80
80
|
"@types/node": "^24.7.2",
|
|
81
81
|
"@types/react": "^19.0.0",
|
|
82
82
|
"consola": "^3.4.2",
|
|
@@ -65,12 +65,5 @@ openapi_client = OpenAPIClientConfig(
|
|
|
65
65
|
)
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
**Copy to Next.js** (if `nextjs_admin` configured):
|
|
69
|
-
```python
|
|
70
|
-
nextjs_admin = NextJsAdminConfig(
|
|
71
|
-
project_path="../frontend/apps/...",
|
|
72
|
-
api_output_path="app/_lib/api/generated",
|
|
73
|
-
)
|
|
74
|
-
```
|
|
75
|
-
|
|
76
68
|
@see https://djangocfg.com/docs/features/api-generation
|
|
69
|
+
|
|
@@ -25,7 +25,7 @@ export const PaymentDetailSchema = z.object({
|
|
|
25
25
|
status_display: z.string(),
|
|
26
26
|
pay_address: z.string().nullable(),
|
|
27
27
|
qr_code_url: z.string().nullable(),
|
|
28
|
-
payment_url: z.url().nullable(),
|
|
28
|
+
payment_url: z.union([z.url(), z.literal('')]).nullable(),
|
|
29
29
|
transaction_hash: z.string().nullable(),
|
|
30
30
|
explorer_link: z.string().nullable(),
|
|
31
31
|
confirmations_count: z.int(),
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
// Auto-generated by DjangoCFG - see CLAUDE.md
|
|
2
2
|
/**
|
|
3
|
-
* Global API Instance - Singleton configuration
|
|
3
|
+
* Global API Instance - Singleton configuration with auto-configuration support
|
|
4
4
|
*
|
|
5
|
-
* This module provides a global API instance that
|
|
6
|
-
*
|
|
5
|
+
* This module provides a global API instance that auto-configures from
|
|
6
|
+
* environment variables or can be configured manually.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* AUTO-CONFIGURATION (recommended):
|
|
9
|
+
* Set one of these environment variables and the API will auto-configure:
|
|
10
|
+
* - NEXT_PUBLIC_API_URL (Next.js)
|
|
11
|
+
* - VITE_API_URL (Vite)
|
|
12
|
+
* - REACT_APP_API_URL (Create React App)
|
|
13
|
+
* - API_URL (generic)
|
|
14
|
+
*
|
|
15
|
+
* Then just use fetchers and hooks directly:
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { getUsers } from './_utils/fetchers'
|
|
18
|
+
* const users = await getUsers({ page: 1 })
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* MANUAL CONFIGURATION:
|
|
9
22
|
* ```typescript
|
|
10
|
-
* // Configure once (e.g., in your app entry point)
|
|
11
23
|
* import { configureAPI } from './api-instance'
|
|
12
24
|
*
|
|
13
25
|
* configureAPI({
|
|
14
26
|
* baseUrl: 'https://api.example.com',
|
|
15
27
|
* token: 'your-jwt-token'
|
|
16
28
|
* })
|
|
17
|
-
*
|
|
18
|
-
* // Then use fetchers and hooks anywhere without configuration
|
|
19
|
-
* import { getUsers } from './fetchers'
|
|
20
|
-
* const users = await getUsers({ page: 1 })
|
|
21
29
|
* ```
|
|
22
30
|
*
|
|
23
31
|
* For SSR or multiple instances:
|
|
24
32
|
* ```typescript
|
|
25
33
|
* import { API } from './index'
|
|
26
|
-
* import { getUsers } from './fetchers'
|
|
34
|
+
* import { getUsers } from './_utils/fetchers'
|
|
27
35
|
*
|
|
28
36
|
* const api = new API('https://api.example.com')
|
|
29
37
|
* const users = await getUsers({ page: 1 }, api)
|
|
@@ -33,27 +41,67 @@
|
|
|
33
41
|
import { API, type APIOptions } from './index'
|
|
34
42
|
|
|
35
43
|
let globalAPI: API | null = null
|
|
44
|
+
let autoConfigAttempted = false
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Auto-configure from environment variable if available (Next.js pattern)
|
|
48
|
+
* This allows hooks and fetchers to work without explicit configureAPI() call
|
|
49
|
+
*
|
|
50
|
+
* Supported environment variables:
|
|
51
|
+
* - NEXT_PUBLIC_API_URL (Next.js)
|
|
52
|
+
* - VITE_API_URL (Vite)
|
|
53
|
+
* - REACT_APP_API_URL (Create React App)
|
|
54
|
+
* - API_URL (generic)
|
|
55
|
+
*/
|
|
56
|
+
function tryAutoConfigureFromEnv(): void {
|
|
57
|
+
// Only attempt once
|
|
58
|
+
if (autoConfigAttempted) return
|
|
59
|
+
autoConfigAttempted = true
|
|
60
|
+
|
|
61
|
+
// Skip if already configured
|
|
62
|
+
if (globalAPI) return
|
|
63
|
+
|
|
64
|
+
// Skip if process is not available (pure browser without bundler)
|
|
65
|
+
if (typeof process === 'undefined' || !process.env) return
|
|
66
|
+
|
|
67
|
+
// Try different environment variable patterns
|
|
68
|
+
const baseUrl =
|
|
69
|
+
process.env.NEXT_PUBLIC_API_URL ||
|
|
70
|
+
process.env.VITE_API_URL ||
|
|
71
|
+
process.env.REACT_APP_API_URL ||
|
|
72
|
+
process.env.API_URL
|
|
73
|
+
|
|
74
|
+
if (baseUrl) {
|
|
75
|
+
globalAPI = new API(baseUrl)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
36
78
|
|
|
37
79
|
/**
|
|
38
80
|
* Get the global API instance
|
|
39
|
-
*
|
|
81
|
+
* Auto-configures from environment variables on first call if not manually configured.
|
|
82
|
+
* @throws Error if API is not configured and no env variable is set
|
|
40
83
|
*/
|
|
41
84
|
export function getAPIInstance(): API {
|
|
85
|
+
// Try auto-configuration on first access (lazy initialization)
|
|
86
|
+
tryAutoConfigureFromEnv()
|
|
87
|
+
|
|
42
88
|
if (!globalAPI) {
|
|
43
89
|
throw new Error(
|
|
44
90
|
'API not configured. Call configureAPI() with your base URL before using fetchers or hooks.\n\n' +
|
|
45
91
|
'Example:\n' +
|
|
46
92
|
' import { configureAPI } from "./api-instance"\n' +
|
|
47
|
-
' configureAPI({ baseUrl: "https://api.example.com" })'
|
|
93
|
+
' configureAPI({ baseUrl: "https://api.example.com" })\n\n' +
|
|
94
|
+
'Or set environment variable: NEXT_PUBLIC_API_URL, VITE_API_URL, or REACT_APP_API_URL'
|
|
48
95
|
)
|
|
49
96
|
}
|
|
50
97
|
return globalAPI
|
|
51
98
|
}
|
|
52
99
|
|
|
53
100
|
/**
|
|
54
|
-
* Check if API is configured
|
|
101
|
+
* Check if API is configured (or can be auto-configured)
|
|
55
102
|
*/
|
|
56
103
|
export function isAPIConfigured(): boolean {
|
|
104
|
+
tryAutoConfigureFromEnv()
|
|
57
105
|
return globalAPI !== null
|
|
58
106
|
}
|
|
59
107
|
|
|
@@ -25,6 +25,7 @@ export class APIClient {
|
|
|
25
25
|
private httpClient: HttpClientAdapter;
|
|
26
26
|
private logger: APILogger | null = null;
|
|
27
27
|
private retryConfig: RetryConfig | null = null;
|
|
28
|
+
private tokenGetter: (() => string | null) | null = null;
|
|
28
29
|
|
|
29
30
|
// Sub-clients
|
|
30
31
|
public ext_payments_payments: ExtPaymentsPayments;
|
|
@@ -35,10 +36,12 @@ export class APIClient {
|
|
|
35
36
|
httpClient?: HttpClientAdapter;
|
|
36
37
|
loggerConfig?: Partial<LoggerConfig>;
|
|
37
38
|
retryConfig?: RetryConfig;
|
|
39
|
+
tokenGetter?: () => string | null;
|
|
38
40
|
}
|
|
39
41
|
) {
|
|
40
42
|
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
41
43
|
this.httpClient = options?.httpClient || new FetchAdapter();
|
|
44
|
+
this.tokenGetter = options?.tokenGetter || null;
|
|
42
45
|
|
|
43
46
|
// Initialize logger if config provided
|
|
44
47
|
if (options?.loggerConfig !== undefined) {
|
|
@@ -69,6 +72,21 @@ export class APIClient {
|
|
|
69
72
|
return null;
|
|
70
73
|
}
|
|
71
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Get the base URL for building streaming/download URLs.
|
|
77
|
+
*/
|
|
78
|
+
getBaseUrl(): string {
|
|
79
|
+
return this.baseUrl;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get JWT token for URL authentication (used in streaming endpoints).
|
|
84
|
+
* Returns null if no token getter is configured or no token is available.
|
|
85
|
+
*/
|
|
86
|
+
getToken(): string | null {
|
|
87
|
+
return this.tokenGetter ? this.tokenGetter() : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
/**
|
|
73
91
|
* Make HTTP request with Django CSRF and session handling.
|
|
74
92
|
* Automatically retries on network errors and 5xx server errors.
|
|
@@ -80,6 +98,7 @@ export class APIClient {
|
|
|
80
98
|
params?: Record<string, any>;
|
|
81
99
|
body?: any;
|
|
82
100
|
formData?: FormData;
|
|
101
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
83
102
|
headers?: Record<string, string>;
|
|
84
103
|
}
|
|
85
104
|
): Promise<T> {
|
|
@@ -116,6 +135,7 @@ export class APIClient {
|
|
|
116
135
|
params?: Record<string, any>;
|
|
117
136
|
body?: any;
|
|
118
137
|
formData?: FormData;
|
|
138
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
119
139
|
headers?: Record<string, string>;
|
|
120
140
|
}
|
|
121
141
|
): Promise<T> {
|
|
@@ -129,8 +149,8 @@ export class APIClient {
|
|
|
129
149
|
...(options?.headers || {})
|
|
130
150
|
};
|
|
131
151
|
|
|
132
|
-
// Don't set Content-Type for FormData (browser will set it with boundary)
|
|
133
|
-
if (!options?.formData && !headers['Content-Type']) {
|
|
152
|
+
// Don't set Content-Type for FormData/binaryBody (browser will set it with boundary)
|
|
153
|
+
if (!options?.formData && !options?.binaryBody && !headers['Content-Type']) {
|
|
134
154
|
headers['Content-Type'] = 'application/json';
|
|
135
155
|
}
|
|
136
156
|
|
|
@@ -157,6 +177,7 @@ export class APIClient {
|
|
|
157
177
|
params: options?.params,
|
|
158
178
|
body: options?.body,
|
|
159
179
|
formData: options?.formData,
|
|
180
|
+
binaryBody: options?.binaryBody,
|
|
160
181
|
});
|
|
161
182
|
|
|
162
183
|
const duration = Date.now() - startTime;
|
|
@@ -14,6 +14,8 @@ export interface HttpRequest {
|
|
|
14
14
|
params?: Record<string, any>;
|
|
15
15
|
/** FormData for file uploads (multipart/form-data) */
|
|
16
16
|
formData?: FormData;
|
|
17
|
+
/** Binary data for octet-stream uploads */
|
|
18
|
+
binaryBody?: Blob | ArrayBuffer;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export interface HttpResponse<T = any> {
|
|
@@ -37,7 +39,7 @@ export interface HttpClientAdapter {
|
|
|
37
39
|
*/
|
|
38
40
|
export class FetchAdapter implements HttpClientAdapter {
|
|
39
41
|
async request<T = any>(request: HttpRequest): Promise<HttpResponse<T>> {
|
|
40
|
-
const { method, url, headers, body, params, formData } = request;
|
|
42
|
+
const { method, url, headers, body, params, formData, binaryBody } = request;
|
|
41
43
|
|
|
42
44
|
// Build URL with query params
|
|
43
45
|
let finalUrl = url;
|
|
@@ -58,12 +60,16 @@ export class FetchAdapter implements HttpClientAdapter {
|
|
|
58
60
|
const finalHeaders: Record<string, string> = { ...headers };
|
|
59
61
|
|
|
60
62
|
// Determine body and content-type
|
|
61
|
-
let requestBody: string | FormData | undefined;
|
|
63
|
+
let requestBody: string | FormData | Blob | ArrayBuffer | undefined;
|
|
62
64
|
|
|
63
65
|
if (formData) {
|
|
64
66
|
// For multipart/form-data, let browser set Content-Type with boundary
|
|
65
67
|
requestBody = formData;
|
|
66
68
|
// Don't set Content-Type - browser will set it with boundary
|
|
69
|
+
} else if (binaryBody) {
|
|
70
|
+
// Binary upload (application/octet-stream)
|
|
71
|
+
finalHeaders['Content-Type'] = 'application/octet-stream';
|
|
72
|
+
requestBody = binaryBody;
|
|
67
73
|
} else if (body) {
|
|
68
74
|
// JSON request
|
|
69
75
|
finalHeaders['Content-Type'] = 'application/json';
|
|
@@ -133,10 +133,11 @@ export class API {
|
|
|
133
133
|
|
|
134
134
|
this._loadTokensFromStorage();
|
|
135
135
|
|
|
136
|
-
// Initialize APIClient
|
|
136
|
+
// Initialize APIClient with token getter for URL authentication
|
|
137
137
|
this._client = new APIClient(this.baseUrl, {
|
|
138
138
|
retryConfig: this.options?.retryConfig,
|
|
139
139
|
loggerConfig: this.options?.loggerConfig,
|
|
140
|
+
tokenGetter: () => this.getToken(),
|
|
140
141
|
});
|
|
141
142
|
|
|
142
143
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
|
@@ -155,6 +156,7 @@ export class API {
|
|
|
155
156
|
this._client = new APIClient(this.baseUrl, {
|
|
156
157
|
retryConfig: this.options?.retryConfig,
|
|
157
158
|
loggerConfig: this.options?.loggerConfig,
|
|
159
|
+
tokenGetter: () => this.getToken(),
|
|
158
160
|
});
|
|
159
161
|
|
|
160
162
|
// Always inject auth header wrapper (reads token dynamically from storage)
|
package/src/api/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
1
|
+
import { createExtensionAPI, initializeExtensionAPI } from '@djangocfg/ext-base/api';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Payments Extension API
|
|
@@ -6,5 +6,10 @@ import { createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
|
6
6
|
* Pre-configured API instance with shared authentication
|
|
7
7
|
*/
|
|
8
8
|
import { API } from './generated/ext_payments';
|
|
9
|
+
import { configureAPI } from './generated/ext_payments/api-instance';
|
|
9
10
|
|
|
11
|
+
// Initialize global API singleton for hooks and fetchers
|
|
12
|
+
initializeExtensionAPI(configureAPI);
|
|
13
|
+
|
|
14
|
+
// Create instance for direct usage
|
|
10
15
|
export const apiPayments = createExtensionAPI(API);
|