@liberfi.io/react-redpacket 0.1.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/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # @liberfi.io/react-redpacket
2
+
3
+ Redpacket domain runtime and React bindings.
4
+
5
+ This package is wallet-agnostic. ChainStream, Pinata, Privy, Next, and
6
+ browser routes stay in the application Adapter.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pnpm add @liberfi.io/react-redpacket
12
+ ```
@@ -0,0 +1,107 @@
1
+ import * as react from 'react';
2
+ import { PropsWithChildren } from 'react';
3
+ import { Chain } from '@liberfi.io/types';
4
+
5
+ declare const redPacketQueryKeys: {
6
+ packet: (idOrShareId: string) => readonly ["redPacket", string];
7
+ walletClaims: (address: string, cursor?: string) => readonly ["walletClaims", string, string];
8
+ packetClaims: (redPacketId: string, cursor?: string) => readonly ["redPacketClaims", string, string];
9
+ walletPackets: (address: string, cursor?: string) => readonly ["walletRedPackets", string, string];
10
+ };
11
+
12
+ interface CreateFixedAmountRedPacketIntent {
13
+ chain: Chain;
14
+ creator: string;
15
+ mint: string;
16
+ maxClaims: number;
17
+ fixedAmount: string;
18
+ memo?: string;
19
+ password?: string;
20
+ }
21
+ interface CreateRandomAmountRedPacketIntent {
22
+ chain: Chain;
23
+ creator: string;
24
+ mint: string;
25
+ maxClaims: number;
26
+ totalAmount: string;
27
+ memo?: string;
28
+ password?: string;
29
+ }
30
+ interface ClaimRedPacketIntent {
31
+ chain: Chain;
32
+ shareId: string;
33
+ claimer: string;
34
+ password?: string;
35
+ }
36
+ type RedpacketPacketStatus = "ongoing" | "finished" | "expired";
37
+ interface RedpacketRecord {
38
+ id: string;
39
+ shareId: string;
40
+ status: RedpacketPacketStatus;
41
+ totalAmount: string;
42
+ claimedAmount?: string;
43
+ claimedCount?: number;
44
+ maxClaims: number;
45
+ memo?: string;
46
+ mint?: string;
47
+ creator?: string;
48
+ expiredAt?: number;
49
+ }
50
+ declare function redpacketRecordStatus(record: Pick<RedpacketRecord, "claimedAmount" | "totalAmount" | "claimedCount" | "maxClaims" | "expiredAt">): RedpacketPacketStatus;
51
+ type RedpacketIntentStatus = "idle" | "validating" | "signing" | "submitting" | "succeeded" | "failed" | "rejected" | "already-claimed";
52
+
53
+ type RedpacketCommand = {
54
+ kind: "create-fixed";
55
+ intent: CreateFixedAmountRedPacketIntent;
56
+ } | {
57
+ kind: "create-random";
58
+ intent: CreateRandomAmountRedPacketIntent;
59
+ } | {
60
+ kind: "claim";
61
+ intent: ClaimRedPacketIntent;
62
+ };
63
+ interface RedpacketSnapshot {
64
+ status: RedpacketIntentStatus;
65
+ command?: RedpacketCommand;
66
+ packetId?: string;
67
+ error?: Error;
68
+ }
69
+ interface RedpacketSignerPort {
70
+ sign(command: RedpacketCommand): Promise<string>;
71
+ }
72
+ interface RedpacketExecutionPort {
73
+ submit(signed: string, command: RedpacketCommand): Promise<{
74
+ packetId: string;
75
+ alreadyClaimed?: boolean;
76
+ }>;
77
+ }
78
+ declare function validateRedpacketCommand(command: RedpacketCommand): void;
79
+ declare function createRedpacketRuntime(options: {
80
+ signer?: RedpacketSignerPort;
81
+ execution: RedpacketExecutionPort;
82
+ onChange?: (snapshot: RedpacketSnapshot) => void;
83
+ }): {
84
+ snapshot(): RedpacketSnapshot;
85
+ submit(command: RedpacketCommand): Promise<RedpacketSnapshot>;
86
+ };
87
+ declare function createInMemoryRedpacketPorts(options?: {
88
+ signError?: Error;
89
+ alreadyClaimed?: boolean;
90
+ timeout?: boolean;
91
+ }): {
92
+ signer: {
93
+ sign(): Promise<string>;
94
+ };
95
+ execution: {
96
+ submit(signed: string, command: RedpacketCommand): Promise<{
97
+ packetId: string;
98
+ alreadyClaimed: boolean | undefined;
99
+ }>;
100
+ };
101
+ };
102
+
103
+ declare const PACKAGE_NAME: "@liberfi.io/react-redpacket";
104
+ declare function RedpacketProvider({ children }: PropsWithChildren): react.FunctionComponentElement<react.ProviderProps<boolean>>;
105
+ declare function useRedpacketReady(): boolean;
106
+
107
+ export { type ClaimRedPacketIntent, type CreateFixedAmountRedPacketIntent, type CreateRandomAmountRedPacketIntent, PACKAGE_NAME, type RedpacketCommand, type RedpacketExecutionPort, type RedpacketIntentStatus, type RedpacketPacketStatus, RedpacketProvider, type RedpacketRecord, type RedpacketSignerPort, type RedpacketSnapshot, createInMemoryRedpacketPorts, createRedpacketRuntime, redPacketQueryKeys, redpacketRecordStatus, useRedpacketReady, validateRedpacketCommand };
@@ -0,0 +1,107 @@
1
+ import * as react from 'react';
2
+ import { PropsWithChildren } from 'react';
3
+ import { Chain } from '@liberfi.io/types';
4
+
5
+ declare const redPacketQueryKeys: {
6
+ packet: (idOrShareId: string) => readonly ["redPacket", string];
7
+ walletClaims: (address: string, cursor?: string) => readonly ["walletClaims", string, string];
8
+ packetClaims: (redPacketId: string, cursor?: string) => readonly ["redPacketClaims", string, string];
9
+ walletPackets: (address: string, cursor?: string) => readonly ["walletRedPackets", string, string];
10
+ };
11
+
12
+ interface CreateFixedAmountRedPacketIntent {
13
+ chain: Chain;
14
+ creator: string;
15
+ mint: string;
16
+ maxClaims: number;
17
+ fixedAmount: string;
18
+ memo?: string;
19
+ password?: string;
20
+ }
21
+ interface CreateRandomAmountRedPacketIntent {
22
+ chain: Chain;
23
+ creator: string;
24
+ mint: string;
25
+ maxClaims: number;
26
+ totalAmount: string;
27
+ memo?: string;
28
+ password?: string;
29
+ }
30
+ interface ClaimRedPacketIntent {
31
+ chain: Chain;
32
+ shareId: string;
33
+ claimer: string;
34
+ password?: string;
35
+ }
36
+ type RedpacketPacketStatus = "ongoing" | "finished" | "expired";
37
+ interface RedpacketRecord {
38
+ id: string;
39
+ shareId: string;
40
+ status: RedpacketPacketStatus;
41
+ totalAmount: string;
42
+ claimedAmount?: string;
43
+ claimedCount?: number;
44
+ maxClaims: number;
45
+ memo?: string;
46
+ mint?: string;
47
+ creator?: string;
48
+ expiredAt?: number;
49
+ }
50
+ declare function redpacketRecordStatus(record: Pick<RedpacketRecord, "claimedAmount" | "totalAmount" | "claimedCount" | "maxClaims" | "expiredAt">): RedpacketPacketStatus;
51
+ type RedpacketIntentStatus = "idle" | "validating" | "signing" | "submitting" | "succeeded" | "failed" | "rejected" | "already-claimed";
52
+
53
+ type RedpacketCommand = {
54
+ kind: "create-fixed";
55
+ intent: CreateFixedAmountRedPacketIntent;
56
+ } | {
57
+ kind: "create-random";
58
+ intent: CreateRandomAmountRedPacketIntent;
59
+ } | {
60
+ kind: "claim";
61
+ intent: ClaimRedPacketIntent;
62
+ };
63
+ interface RedpacketSnapshot {
64
+ status: RedpacketIntentStatus;
65
+ command?: RedpacketCommand;
66
+ packetId?: string;
67
+ error?: Error;
68
+ }
69
+ interface RedpacketSignerPort {
70
+ sign(command: RedpacketCommand): Promise<string>;
71
+ }
72
+ interface RedpacketExecutionPort {
73
+ submit(signed: string, command: RedpacketCommand): Promise<{
74
+ packetId: string;
75
+ alreadyClaimed?: boolean;
76
+ }>;
77
+ }
78
+ declare function validateRedpacketCommand(command: RedpacketCommand): void;
79
+ declare function createRedpacketRuntime(options: {
80
+ signer?: RedpacketSignerPort;
81
+ execution: RedpacketExecutionPort;
82
+ onChange?: (snapshot: RedpacketSnapshot) => void;
83
+ }): {
84
+ snapshot(): RedpacketSnapshot;
85
+ submit(command: RedpacketCommand): Promise<RedpacketSnapshot>;
86
+ };
87
+ declare function createInMemoryRedpacketPorts(options?: {
88
+ signError?: Error;
89
+ alreadyClaimed?: boolean;
90
+ timeout?: boolean;
91
+ }): {
92
+ signer: {
93
+ sign(): Promise<string>;
94
+ };
95
+ execution: {
96
+ submit(signed: string, command: RedpacketCommand): Promise<{
97
+ packetId: string;
98
+ alreadyClaimed: boolean | undefined;
99
+ }>;
100
+ };
101
+ };
102
+
103
+ declare const PACKAGE_NAME: "@liberfi.io/react-redpacket";
104
+ declare function RedpacketProvider({ children }: PropsWithChildren): react.FunctionComponentElement<react.ProviderProps<boolean>>;
105
+ declare function useRedpacketReady(): boolean;
106
+
107
+ export { type ClaimRedPacketIntent, type CreateFixedAmountRedPacketIntent, type CreateRandomAmountRedPacketIntent, PACKAGE_NAME, type RedpacketCommand, type RedpacketExecutionPort, type RedpacketIntentStatus, type RedpacketPacketStatus, RedpacketProvider, type RedpacketRecord, type RedpacketSignerPort, type RedpacketSnapshot, createInMemoryRedpacketPorts, createRedpacketRuntime, redPacketQueryKeys, redpacketRecordStatus, useRedpacketReady, validateRedpacketCommand };
package/dist/index.js ADDED
@@ -0,0 +1,147 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/index.ts
6
+
7
+ // src/query-keys.ts
8
+ var redPacketQueryKeys = {
9
+ packet: (idOrShareId) => ["redPacket", idOrShareId],
10
+ walletClaims: (address, cursor = "") => ["walletClaims", address, cursor],
11
+ packetClaims: (redPacketId, cursor = "") => ["redPacketClaims", redPacketId, cursor],
12
+ walletPackets: (address, cursor = "") => ["walletRedPackets", address, cursor]
13
+ };
14
+
15
+ // src/types.ts
16
+ function redpacketRecordStatus(record) {
17
+ if (Number(record.claimedAmount ?? 0) >= Number(record.totalAmount) || (record.claimedCount ?? 0) >= record.maxClaims) {
18
+ return "finished";
19
+ }
20
+ if ((record.expiredAt ?? Number.POSITIVE_INFINITY) > Date.now()) {
21
+ return "ongoing";
22
+ }
23
+ return "expired";
24
+ }
25
+
26
+ // src/redpacket-runtime.ts
27
+ function validateRedpacketCommand(command) {
28
+ if (command.kind === "create-fixed") {
29
+ const n = Number(command.intent.fixedAmount);
30
+ if (!Number.isFinite(n) || n <= 0) throw new Error("invalid amount");
31
+ if (command.intent.maxClaims < 1) throw new Error("invalid claim count");
32
+ }
33
+ if (command.kind === "create-random") {
34
+ const n = Number(command.intent.totalAmount);
35
+ if (!Number.isFinite(n) || n <= 0) throw new Error("invalid amount");
36
+ if (command.intent.maxClaims < 1) throw new Error("invalid claim count");
37
+ }
38
+ if (command.kind === "claim" && !command.intent.shareId) {
39
+ throw new Error("missing packet");
40
+ }
41
+ }
42
+ function createRedpacketRuntime(options) {
43
+ let current = { status: "idle" };
44
+ const claimed = /* @__PURE__ */ new Set();
45
+ const set = (next) => {
46
+ current = next;
47
+ options.onChange?.(next);
48
+ return next;
49
+ };
50
+ return {
51
+ snapshot() {
52
+ return current;
53
+ },
54
+ async submit(command) {
55
+ if (command.kind === "claim" && claimed.has(command.intent.shareId)) {
56
+ return set({
57
+ status: "already-claimed",
58
+ command,
59
+ error: new Error("already claimed")
60
+ });
61
+ }
62
+ set({ status: "validating", command });
63
+ try {
64
+ validateRedpacketCommand(command);
65
+ } catch (error) {
66
+ const err = error instanceof Error ? error : new Error(String(error));
67
+ return set({ status: "failed", command, error: err });
68
+ }
69
+ if (!options.signer) {
70
+ return set({
71
+ status: "rejected",
72
+ command,
73
+ error: new Error("missing signer")
74
+ });
75
+ }
76
+ set({ status: "signing", command });
77
+ let signed;
78
+ try {
79
+ signed = await options.signer.sign(command);
80
+ } catch (error) {
81
+ const err = error instanceof Error ? error : new Error(String(error));
82
+ return set({ status: "rejected", command, error: err });
83
+ }
84
+ set({ status: "submitting", command });
85
+ try {
86
+ const result = await options.execution.submit(signed, command);
87
+ if (result.alreadyClaimed) {
88
+ claimed.add(command.kind === "claim" ? command.intent.shareId : result.packetId);
89
+ return set({
90
+ status: "already-claimed",
91
+ command,
92
+ packetId: result.packetId
93
+ });
94
+ }
95
+ if (command.kind === "claim") claimed.add(command.intent.shareId);
96
+ return set({
97
+ status: "succeeded",
98
+ command,
99
+ packetId: result.packetId
100
+ });
101
+ } catch (error) {
102
+ const err = error instanceof Error ? error : new Error(String(error));
103
+ return set({ status: "failed", command, error: err });
104
+ }
105
+ }
106
+ };
107
+ }
108
+ function createInMemoryRedpacketPorts(options = {}) {
109
+ return {
110
+ signer: {
111
+ async sign() {
112
+ if (options.signError) throw options.signError;
113
+ return "signed";
114
+ }
115
+ },
116
+ execution: {
117
+ async submit(signed, command) {
118
+ if (options.timeout) throw new Error("submit timeout");
119
+ return {
120
+ packetId: command.kind === "claim" ? command.intent.shareId : "packet-memory",
121
+ alreadyClaimed: options.alreadyClaimed
122
+ };
123
+ }
124
+ }
125
+ };
126
+ }
127
+
128
+ // src/index.ts
129
+ var PACKAGE_NAME = "@liberfi.io/react-redpacket";
130
+ var ReadyContext = react.createContext(true);
131
+ function RedpacketProvider({ children }) {
132
+ return react.createElement(ReadyContext.Provider, { value: true }, children);
133
+ }
134
+ function useRedpacketReady() {
135
+ return react.useContext(ReadyContext);
136
+ }
137
+
138
+ exports.PACKAGE_NAME = PACKAGE_NAME;
139
+ exports.RedpacketProvider = RedpacketProvider;
140
+ exports.createInMemoryRedpacketPorts = createInMemoryRedpacketPorts;
141
+ exports.createRedpacketRuntime = createRedpacketRuntime;
142
+ exports.redPacketQueryKeys = redPacketQueryKeys;
143
+ exports.redpacketRecordStatus = redpacketRecordStatus;
144
+ exports.useRedpacketReady = useRedpacketReady;
145
+ exports.validateRedpacketCommand = validateRedpacketCommand;
146
+ //# sourceMappingURL=index.js.map
147
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/query-keys.ts","../src/types.ts","../src/redpacket-runtime.ts","../src/index.ts"],"names":["createContext","createElement","useContext"],"mappings":"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","file":"index.js","sourcesContent":["export const redPacketQueryKeys = {\n packet: (idOrShareId: string) => [\"redPacket\", idOrShareId] as const,\n walletClaims: (address: string, cursor = \"\") =>\n [\"walletClaims\", address, cursor] as const,\n packetClaims: (redPacketId: string, cursor = \"\") =>\n [\"redPacketClaims\", redPacketId, cursor] as const,\n walletPackets: (address: string, cursor = \"\") =>\n [\"walletRedPackets\", address, cursor] as const,\n};\n","import type { Chain } from \"@liberfi.io/types\";\n\nexport interface CreateFixedAmountRedPacketIntent {\n chain: Chain;\n creator: string;\n mint: string;\n maxClaims: number;\n fixedAmount: string;\n memo?: string;\n password?: string;\n}\n\nexport interface CreateRandomAmountRedPacketIntent {\n chain: Chain;\n creator: string;\n mint: string;\n maxClaims: number;\n totalAmount: string;\n memo?: string;\n password?: string;\n}\n\nexport interface ClaimRedPacketIntent {\n chain: Chain;\n shareId: string;\n claimer: string;\n password?: string;\n}\n\nexport type RedpacketPacketStatus = \"ongoing\" | \"finished\" | \"expired\";\n\nexport interface RedpacketRecord {\n id: string;\n shareId: string;\n status: RedpacketPacketStatus;\n totalAmount: string;\n claimedAmount?: string;\n claimedCount?: number;\n maxClaims: number;\n memo?: string;\n mint?: string;\n creator?: string;\n expiredAt?: number;\n}\n\nexport function redpacketRecordStatus(\n record: Pick<\n RedpacketRecord,\n \"claimedAmount\" | \"totalAmount\" | \"claimedCount\" | \"maxClaims\" | \"expiredAt\"\n >,\n): RedpacketPacketStatus {\n if (\n Number(record.claimedAmount ?? 0) >= Number(record.totalAmount) ||\n (record.claimedCount ?? 0) >= record.maxClaims\n ) {\n return \"finished\";\n }\n if ((record.expiredAt ?? Number.POSITIVE_INFINITY) > Date.now()) {\n return \"ongoing\";\n }\n return \"expired\";\n}\n\nexport type RedpacketIntentStatus =\n | \"idle\"\n | \"validating\"\n | \"signing\"\n | \"submitting\"\n | \"succeeded\"\n | \"failed\"\n | \"rejected\"\n | \"already-claimed\";\n","import type {\n ClaimRedPacketIntent,\n CreateFixedAmountRedPacketIntent,\n CreateRandomAmountRedPacketIntent,\n RedpacketIntentStatus,\n} from \"./types\";\n\nexport type RedpacketCommand =\n | { kind: \"create-fixed\"; intent: CreateFixedAmountRedPacketIntent }\n | { kind: \"create-random\"; intent: CreateRandomAmountRedPacketIntent }\n | { kind: \"claim\"; intent: ClaimRedPacketIntent };\n\nexport interface RedpacketSnapshot {\n status: RedpacketIntentStatus;\n command?: RedpacketCommand;\n packetId?: string;\n error?: Error;\n}\n\nexport interface RedpacketSignerPort {\n sign(command: RedpacketCommand): Promise<string>;\n}\n\nexport interface RedpacketExecutionPort {\n submit(\n signed: string,\n command: RedpacketCommand,\n ): Promise<{ packetId: string; alreadyClaimed?: boolean }>;\n}\n\nexport function validateRedpacketCommand(command: RedpacketCommand): void {\n if (command.kind === \"create-fixed\") {\n const n = Number(command.intent.fixedAmount);\n if (!Number.isFinite(n) || n <= 0) throw new Error(\"invalid amount\");\n if (command.intent.maxClaims < 1) throw new Error(\"invalid claim count\");\n }\n if (command.kind === \"create-random\") {\n const n = Number(command.intent.totalAmount);\n if (!Number.isFinite(n) || n <= 0) throw new Error(\"invalid amount\");\n if (command.intent.maxClaims < 1) throw new Error(\"invalid claim count\");\n }\n if (command.kind === \"claim\" && !command.intent.shareId) {\n throw new Error(\"missing packet\");\n }\n}\n\nexport function createRedpacketRuntime(options: {\n signer?: RedpacketSignerPort;\n execution: RedpacketExecutionPort;\n onChange?: (snapshot: RedpacketSnapshot) => void;\n}) {\n let current: RedpacketSnapshot = { status: \"idle\" };\n const claimed = new Set<string>();\n const set = (next: RedpacketSnapshot) => {\n current = next;\n options.onChange?.(next);\n return next;\n };\n\n return {\n snapshot() {\n return current;\n },\n async submit(command: RedpacketCommand) {\n if (command.kind === \"claim\" && claimed.has(command.intent.shareId)) {\n return set({\n status: \"already-claimed\",\n command,\n error: new Error(\"already claimed\"),\n });\n }\n set({ status: \"validating\", command });\n try {\n validateRedpacketCommand(command);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"failed\", command, error: err });\n }\n if (!options.signer) {\n return set({\n status: \"rejected\",\n command,\n error: new Error(\"missing signer\"),\n });\n }\n set({ status: \"signing\", command });\n let signed: string;\n try {\n signed = await options.signer.sign(command);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"rejected\", command, error: err });\n }\n set({ status: \"submitting\", command });\n try {\n const result = await options.execution.submit(signed, command);\n if (result.alreadyClaimed) {\n claimed.add(command.kind === \"claim\" ? command.intent.shareId : result.packetId);\n return set({\n status: \"already-claimed\",\n command,\n packetId: result.packetId,\n });\n }\n if (command.kind === \"claim\") claimed.add(command.intent.shareId);\n return set({\n status: \"succeeded\",\n command,\n packetId: result.packetId,\n });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"failed\", command, error: err });\n }\n },\n };\n}\n\nexport function createInMemoryRedpacketPorts(options: {\n signError?: Error;\n alreadyClaimed?: boolean;\n timeout?: boolean;\n} = {}) {\n return {\n signer: {\n async sign() {\n if (options.signError) throw options.signError;\n return \"signed\";\n },\n },\n execution: {\n async submit(signed: string, command: RedpacketCommand) {\n void signed;\n if (options.timeout) throw new Error(\"submit timeout\");\n return {\n packetId:\n command.kind === \"claim\" ? command.intent.shareId : \"packet-memory\",\n alreadyClaimed: options.alreadyClaimed,\n };\n },\n },\n };\n}\n","import {\n createContext,\n createElement,\n useContext,\n type PropsWithChildren,\n} from \"react\";\n\nexport const PACKAGE_NAME = \"@liberfi.io/react-redpacket\" as const;\n\nconst ReadyContext = createContext(true);\n\nexport function RedpacketProvider({ children }: PropsWithChildren) {\n return createElement(ReadyContext.Provider, { value: true }, children);\n}\n\nexport function useRedpacketReady(): boolean {\n return useContext(ReadyContext);\n}\n\nexport { redPacketQueryKeys } from \"./query-keys\";\nexport type {\n ClaimRedPacketIntent,\n CreateFixedAmountRedPacketIntent,\n CreateRandomAmountRedPacketIntent,\n RedpacketIntentStatus,\n RedpacketPacketStatus,\n RedpacketRecord,\n} from \"./types\";\nexport { redpacketRecordStatus } from \"./types\";\nexport {\n createInMemoryRedpacketPorts,\n createRedpacketRuntime,\n validateRedpacketCommand,\n} from \"./redpacket-runtime\";\nexport type {\n RedpacketCommand,\n RedpacketExecutionPort,\n RedpacketSignerPort,\n RedpacketSnapshot,\n} from \"./redpacket-runtime\";\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,138 @@
1
+ import { createContext, createElement, useContext } from 'react';
2
+
3
+ // src/index.ts
4
+
5
+ // src/query-keys.ts
6
+ var redPacketQueryKeys = {
7
+ packet: (idOrShareId) => ["redPacket", idOrShareId],
8
+ walletClaims: (address, cursor = "") => ["walletClaims", address, cursor],
9
+ packetClaims: (redPacketId, cursor = "") => ["redPacketClaims", redPacketId, cursor],
10
+ walletPackets: (address, cursor = "") => ["walletRedPackets", address, cursor]
11
+ };
12
+
13
+ // src/types.ts
14
+ function redpacketRecordStatus(record) {
15
+ if (Number(record.claimedAmount ?? 0) >= Number(record.totalAmount) || (record.claimedCount ?? 0) >= record.maxClaims) {
16
+ return "finished";
17
+ }
18
+ if ((record.expiredAt ?? Number.POSITIVE_INFINITY) > Date.now()) {
19
+ return "ongoing";
20
+ }
21
+ return "expired";
22
+ }
23
+
24
+ // src/redpacket-runtime.ts
25
+ function validateRedpacketCommand(command) {
26
+ if (command.kind === "create-fixed") {
27
+ const n = Number(command.intent.fixedAmount);
28
+ if (!Number.isFinite(n) || n <= 0) throw new Error("invalid amount");
29
+ if (command.intent.maxClaims < 1) throw new Error("invalid claim count");
30
+ }
31
+ if (command.kind === "create-random") {
32
+ const n = Number(command.intent.totalAmount);
33
+ if (!Number.isFinite(n) || n <= 0) throw new Error("invalid amount");
34
+ if (command.intent.maxClaims < 1) throw new Error("invalid claim count");
35
+ }
36
+ if (command.kind === "claim" && !command.intent.shareId) {
37
+ throw new Error("missing packet");
38
+ }
39
+ }
40
+ function createRedpacketRuntime(options) {
41
+ let current = { status: "idle" };
42
+ const claimed = /* @__PURE__ */ new Set();
43
+ const set = (next) => {
44
+ current = next;
45
+ options.onChange?.(next);
46
+ return next;
47
+ };
48
+ return {
49
+ snapshot() {
50
+ return current;
51
+ },
52
+ async submit(command) {
53
+ if (command.kind === "claim" && claimed.has(command.intent.shareId)) {
54
+ return set({
55
+ status: "already-claimed",
56
+ command,
57
+ error: new Error("already claimed")
58
+ });
59
+ }
60
+ set({ status: "validating", command });
61
+ try {
62
+ validateRedpacketCommand(command);
63
+ } catch (error) {
64
+ const err = error instanceof Error ? error : new Error(String(error));
65
+ return set({ status: "failed", command, error: err });
66
+ }
67
+ if (!options.signer) {
68
+ return set({
69
+ status: "rejected",
70
+ command,
71
+ error: new Error("missing signer")
72
+ });
73
+ }
74
+ set({ status: "signing", command });
75
+ let signed;
76
+ try {
77
+ signed = await options.signer.sign(command);
78
+ } catch (error) {
79
+ const err = error instanceof Error ? error : new Error(String(error));
80
+ return set({ status: "rejected", command, error: err });
81
+ }
82
+ set({ status: "submitting", command });
83
+ try {
84
+ const result = await options.execution.submit(signed, command);
85
+ if (result.alreadyClaimed) {
86
+ claimed.add(command.kind === "claim" ? command.intent.shareId : result.packetId);
87
+ return set({
88
+ status: "already-claimed",
89
+ command,
90
+ packetId: result.packetId
91
+ });
92
+ }
93
+ if (command.kind === "claim") claimed.add(command.intent.shareId);
94
+ return set({
95
+ status: "succeeded",
96
+ command,
97
+ packetId: result.packetId
98
+ });
99
+ } catch (error) {
100
+ const err = error instanceof Error ? error : new Error(String(error));
101
+ return set({ status: "failed", command, error: err });
102
+ }
103
+ }
104
+ };
105
+ }
106
+ function createInMemoryRedpacketPorts(options = {}) {
107
+ return {
108
+ signer: {
109
+ async sign() {
110
+ if (options.signError) throw options.signError;
111
+ return "signed";
112
+ }
113
+ },
114
+ execution: {
115
+ async submit(signed, command) {
116
+ if (options.timeout) throw new Error("submit timeout");
117
+ return {
118
+ packetId: command.kind === "claim" ? command.intent.shareId : "packet-memory",
119
+ alreadyClaimed: options.alreadyClaimed
120
+ };
121
+ }
122
+ }
123
+ };
124
+ }
125
+
126
+ // src/index.ts
127
+ var PACKAGE_NAME = "@liberfi.io/react-redpacket";
128
+ var ReadyContext = createContext(true);
129
+ function RedpacketProvider({ children }) {
130
+ return createElement(ReadyContext.Provider, { value: true }, children);
131
+ }
132
+ function useRedpacketReady() {
133
+ return useContext(ReadyContext);
134
+ }
135
+
136
+ export { PACKAGE_NAME, RedpacketProvider, createInMemoryRedpacketPorts, createRedpacketRuntime, redPacketQueryKeys, redpacketRecordStatus, useRedpacketReady, validateRedpacketCommand };
137
+ //# sourceMappingURL=index.mjs.map
138
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/query-keys.ts","../src/types.ts","../src/redpacket-runtime.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["export const redPacketQueryKeys = {\n packet: (idOrShareId: string) => [\"redPacket\", idOrShareId] as const,\n walletClaims: (address: string, cursor = \"\") =>\n [\"walletClaims\", address, cursor] as const,\n packetClaims: (redPacketId: string, cursor = \"\") =>\n [\"redPacketClaims\", redPacketId, cursor] as const,\n walletPackets: (address: string, cursor = \"\") =>\n [\"walletRedPackets\", address, cursor] as const,\n};\n","import type { Chain } from \"@liberfi.io/types\";\n\nexport interface CreateFixedAmountRedPacketIntent {\n chain: Chain;\n creator: string;\n mint: string;\n maxClaims: number;\n fixedAmount: string;\n memo?: string;\n password?: string;\n}\n\nexport interface CreateRandomAmountRedPacketIntent {\n chain: Chain;\n creator: string;\n mint: string;\n maxClaims: number;\n totalAmount: string;\n memo?: string;\n password?: string;\n}\n\nexport interface ClaimRedPacketIntent {\n chain: Chain;\n shareId: string;\n claimer: string;\n password?: string;\n}\n\nexport type RedpacketPacketStatus = \"ongoing\" | \"finished\" | \"expired\";\n\nexport interface RedpacketRecord {\n id: string;\n shareId: string;\n status: RedpacketPacketStatus;\n totalAmount: string;\n claimedAmount?: string;\n claimedCount?: number;\n maxClaims: number;\n memo?: string;\n mint?: string;\n creator?: string;\n expiredAt?: number;\n}\n\nexport function redpacketRecordStatus(\n record: Pick<\n RedpacketRecord,\n \"claimedAmount\" | \"totalAmount\" | \"claimedCount\" | \"maxClaims\" | \"expiredAt\"\n >,\n): RedpacketPacketStatus {\n if (\n Number(record.claimedAmount ?? 0) >= Number(record.totalAmount) ||\n (record.claimedCount ?? 0) >= record.maxClaims\n ) {\n return \"finished\";\n }\n if ((record.expiredAt ?? Number.POSITIVE_INFINITY) > Date.now()) {\n return \"ongoing\";\n }\n return \"expired\";\n}\n\nexport type RedpacketIntentStatus =\n | \"idle\"\n | \"validating\"\n | \"signing\"\n | \"submitting\"\n | \"succeeded\"\n | \"failed\"\n | \"rejected\"\n | \"already-claimed\";\n","import type {\n ClaimRedPacketIntent,\n CreateFixedAmountRedPacketIntent,\n CreateRandomAmountRedPacketIntent,\n RedpacketIntentStatus,\n} from \"./types\";\n\nexport type RedpacketCommand =\n | { kind: \"create-fixed\"; intent: CreateFixedAmountRedPacketIntent }\n | { kind: \"create-random\"; intent: CreateRandomAmountRedPacketIntent }\n | { kind: \"claim\"; intent: ClaimRedPacketIntent };\n\nexport interface RedpacketSnapshot {\n status: RedpacketIntentStatus;\n command?: RedpacketCommand;\n packetId?: string;\n error?: Error;\n}\n\nexport interface RedpacketSignerPort {\n sign(command: RedpacketCommand): Promise<string>;\n}\n\nexport interface RedpacketExecutionPort {\n submit(\n signed: string,\n command: RedpacketCommand,\n ): Promise<{ packetId: string; alreadyClaimed?: boolean }>;\n}\n\nexport function validateRedpacketCommand(command: RedpacketCommand): void {\n if (command.kind === \"create-fixed\") {\n const n = Number(command.intent.fixedAmount);\n if (!Number.isFinite(n) || n <= 0) throw new Error(\"invalid amount\");\n if (command.intent.maxClaims < 1) throw new Error(\"invalid claim count\");\n }\n if (command.kind === \"create-random\") {\n const n = Number(command.intent.totalAmount);\n if (!Number.isFinite(n) || n <= 0) throw new Error(\"invalid amount\");\n if (command.intent.maxClaims < 1) throw new Error(\"invalid claim count\");\n }\n if (command.kind === \"claim\" && !command.intent.shareId) {\n throw new Error(\"missing packet\");\n }\n}\n\nexport function createRedpacketRuntime(options: {\n signer?: RedpacketSignerPort;\n execution: RedpacketExecutionPort;\n onChange?: (snapshot: RedpacketSnapshot) => void;\n}) {\n let current: RedpacketSnapshot = { status: \"idle\" };\n const claimed = new Set<string>();\n const set = (next: RedpacketSnapshot) => {\n current = next;\n options.onChange?.(next);\n return next;\n };\n\n return {\n snapshot() {\n return current;\n },\n async submit(command: RedpacketCommand) {\n if (command.kind === \"claim\" && claimed.has(command.intent.shareId)) {\n return set({\n status: \"already-claimed\",\n command,\n error: new Error(\"already claimed\"),\n });\n }\n set({ status: \"validating\", command });\n try {\n validateRedpacketCommand(command);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"failed\", command, error: err });\n }\n if (!options.signer) {\n return set({\n status: \"rejected\",\n command,\n error: new Error(\"missing signer\"),\n });\n }\n set({ status: \"signing\", command });\n let signed: string;\n try {\n signed = await options.signer.sign(command);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"rejected\", command, error: err });\n }\n set({ status: \"submitting\", command });\n try {\n const result = await options.execution.submit(signed, command);\n if (result.alreadyClaimed) {\n claimed.add(command.kind === \"claim\" ? command.intent.shareId : result.packetId);\n return set({\n status: \"already-claimed\",\n command,\n packetId: result.packetId,\n });\n }\n if (command.kind === \"claim\") claimed.add(command.intent.shareId);\n return set({\n status: \"succeeded\",\n command,\n packetId: result.packetId,\n });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n return set({ status: \"failed\", command, error: err });\n }\n },\n };\n}\n\nexport function createInMemoryRedpacketPorts(options: {\n signError?: Error;\n alreadyClaimed?: boolean;\n timeout?: boolean;\n} = {}) {\n return {\n signer: {\n async sign() {\n if (options.signError) throw options.signError;\n return \"signed\";\n },\n },\n execution: {\n async submit(signed: string, command: RedpacketCommand) {\n void signed;\n if (options.timeout) throw new Error(\"submit timeout\");\n return {\n packetId:\n command.kind === \"claim\" ? command.intent.shareId : \"packet-memory\",\n alreadyClaimed: options.alreadyClaimed,\n };\n },\n },\n };\n}\n","import {\n createContext,\n createElement,\n useContext,\n type PropsWithChildren,\n} from \"react\";\n\nexport const PACKAGE_NAME = \"@liberfi.io/react-redpacket\" as const;\n\nconst ReadyContext = createContext(true);\n\nexport function RedpacketProvider({ children }: PropsWithChildren) {\n return createElement(ReadyContext.Provider, { value: true }, children);\n}\n\nexport function useRedpacketReady(): boolean {\n return useContext(ReadyContext);\n}\n\nexport { redPacketQueryKeys } from \"./query-keys\";\nexport type {\n ClaimRedPacketIntent,\n CreateFixedAmountRedPacketIntent,\n CreateRandomAmountRedPacketIntent,\n RedpacketIntentStatus,\n RedpacketPacketStatus,\n RedpacketRecord,\n} from \"./types\";\nexport { redpacketRecordStatus } from \"./types\";\nexport {\n createInMemoryRedpacketPorts,\n createRedpacketRuntime,\n validateRedpacketCommand,\n} from \"./redpacket-runtime\";\nexport type {\n RedpacketCommand,\n RedpacketExecutionPort,\n RedpacketSignerPort,\n RedpacketSnapshot,\n} from \"./redpacket-runtime\";\n"]}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@liberfi.io/react-redpacket",
3
+ "version": "0.1.1",
4
+ "description": "Redpacket domain runtime and React bindings",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "peerDependencies": {
25
+ "@tanstack/react-query": ">=5",
26
+ "react": ">=18",
27
+ "react-dom": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@liberfi.io/types": "0.4.74",
31
+ "@liberfi.io/utils": "0.2.73"
32
+ },
33
+ "devDependencies": {
34
+ "@tanstack/react-query": "^5.90.2",
35
+ "@testing-library/jest-dom": "^6.9.1",
36
+ "@testing-library/react": "^16.3.0",
37
+ "@types/jest": "^30.0.0",
38
+ "@types/react": "^19.1.13",
39
+ "@types/react-dom": "^19.1.9",
40
+ "jest": "^30.2.0",
41
+ "jest-environment-jsdom": "^30.2.0",
42
+ "react": "^19.1.1",
43
+ "react-dom": "^19.1.1",
44
+ "rimraf": "^5.0.5",
45
+ "ts-jest": "^29.4.5",
46
+ "tsup": "^8.5.0",
47
+ "typescript": "^5.9.2",
48
+ "tsconfig": "0.1.257"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "scripts": {
54
+ "dev": "tsup --watch",
55
+ "build": "rimraf -rf dist && tsup",
56
+ "test": "jest --config jest.config.cjs --runInBand --detectOpenHandles",
57
+ "typecheck": "tsc --noEmit -p tsconfig.json",
58
+ "lint": "eslint src"
59
+ }
60
+ }