sbcwallet 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.
- package/.env.example +10 -0
- package/.github/workflows/build.yml +66 -0
- package/.github/workflows/release.yml +57 -0
- package/APPLE_WALLET_SETUP.md +318 -0
- package/GOOGLE_WALLET_SETUP.md +473 -0
- package/LICENSE +201 -0
- package/README.md +187 -0
- package/dist/adapters/apple.d.ts +10 -0
- package/dist/adapters/apple.js +153 -0
- package/dist/adapters/google.d.ts +26 -0
- package/dist/adapters/google.js +431 -0
- package/dist/api/unified.d.ts +67 -0
- package/dist/api/unified.js +375 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +11 -0
- package/dist/profiles/healthcare/index.d.ts +91 -0
- package/dist/profiles/healthcare/index.js +151 -0
- package/dist/profiles/logistics/index.d.ts +91 -0
- package/dist/profiles/logistics/index.js +152 -0
- package/dist/profiles/loyalty/index.d.ts +91 -0
- package/dist/profiles/loyalty/index.js +81 -0
- package/dist/templates/apple/child.json +59 -0
- package/dist/templates/apple/parent.json +54 -0
- package/dist/templates/google/child_object.json +38 -0
- package/dist/templates/google/loyalty_class.json +7 -0
- package/dist/templates/google/loyalty_object.json +29 -0
- package/dist/templates/google/parent_class.json +10 -0
- package/dist/templates/google/parent_object.json +33 -0
- package/dist/types.d.ts +422 -0
- package/dist/types.js +80 -0
- package/dist/utils/progress-image.d.ts +23 -0
- package/dist/utils/progress-image.js +94 -0
- package/examples/.loyalty-fixed-state.json +10 -0
- package/examples/claim-flow.ts +163 -0
- package/examples/loyalty-admin-server.js +207 -0
- package/examples/loyalty-admin.html +260 -0
- package/examples/loyalty-fixed-card-server.js +288 -0
- package/examples/loyalty-flow.ts +78 -0
- package/examples/loyalty-google-issue.js +115 -0
- package/package.json +51 -0
- package/scripts/copy-assets.js +35 -0
- package/scripts/smoke-dist-import.js +39 -0
- package/setup-google-class.js +97 -0
- package/setup-google-class.ts +105 -0
- package/src/adapters/apple.ts +193 -0
- package/src/adapters/google.ts +521 -0
- package/src/api/unified.ts +487 -0
- package/src/index.ts +74 -0
- package/src/profiles/healthcare/index.ts +157 -0
- package/src/profiles/logistics/index.ts +158 -0
- package/src/profiles/loyalty/index.ts +87 -0
- package/src/templates/apple/child.json +59 -0
- package/src/templates/apple/parent.json +54 -0
- package/src/templates/google/child_object.json +38 -0
- package/src/templates/google/loyalty_class.json +7 -0
- package/src/templates/google/loyalty_object.json +29 -0
- package/src/templates/google/parent_class.json +10 -0
- package/src/templates/google/parent_object.json +33 -0
- package/src/types.ts +324 -0
- package/src/utils/progress-image.ts +130 -0
- package/test-google-wallet.js +78 -0
- package/test-google-wallet.ts +94 -0
- package/tests/adapters.test.ts +244 -0
- package/tests/loyalty.test.ts +39 -0
- package/tests/unified.test.ts +388 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# ποΈ sbcwallet
|
|
2
|
+
|
|
3
|
+
Unified Wallet-Pass SDK for Real-World Credentials
|
|
4
|
+
|
|
5
|
+
sbcwallet is a TypeScript SDK for generating, signing, and managing verifiable passes on Apple Wallet and Google Wallet.
|
|
6
|
+
Built on @sbcwallet, it bridges cryptographic truth and real-world credentials β enabling secure, interoperable workflows for logistics, healthcare, and beyond.
|
|
7
|
+
|
|
8
|
+
βΈ»
|
|
9
|
+
|
|
10
|
+
## β¨ Overview
|
|
11
|
+
|
|
12
|
+
sbcwallet provides a unified abstraction layer for issuing and updating wallet passes across multiple ecosystems.
|
|
13
|
+
It standardizes claim flows (like PES β TO) and status pipelines (ISSUED β PRESENCE β OPS β EXITED) while maintaining verifiable hashes, signatures, and anchor integrity via sbcwallet Core.
|
|
14
|
+
|
|
15
|
+
βΈ»
|
|
16
|
+
|
|
17
|
+
## π Quickstart
|
|
18
|
+
|
|
19
|
+
```jsnpm install sbcwallet
|
|
20
|
+
|
|
21
|
+
import { createParentSchedule, createChildTicket, getPkpassBuffer } from 'sbcwallet'
|
|
22
|
+
|
|
23
|
+
// 1οΈβ£ Create a parent PES schedule
|
|
24
|
+
const pes = await createParentSchedule({
|
|
25
|
+
profile: 'logistics',
|
|
26
|
+
programName: 'Morning Yard Veracruz',
|
|
27
|
+
site: 'Patio Gate 3'
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// 2οΈβ£ Claim a child Transport Order
|
|
31
|
+
const to = await createChildTicket({
|
|
32
|
+
parentId: pes.id,
|
|
33
|
+
plate: 'ABC123A',
|
|
34
|
+
carrier: 'Transportes Golfo'
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// 3οΈβ£ Generate Apple Wallet pass
|
|
38
|
+
const buf = await getPkpassBuffer('child', to)
|
|
39
|
+
await fs.promises.writeFile('ticket.pkpass', buf)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## π Loyalty Cards (Multi-tenant)
|
|
43
|
+
|
|
44
|
+
Each business defines its own loyalty program, customers create accounts, and each customer gets a loyalty card that shows:
|
|
45
|
+
- A QR/barcode identifier (`memberId`)
|
|
46
|
+
- Current points (`points`) which can be updated
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import {
|
|
50
|
+
createBusiness,
|
|
51
|
+
createCustomerAccount,
|
|
52
|
+
createLoyaltyProgram,
|
|
53
|
+
issueLoyaltyCard,
|
|
54
|
+
updateLoyaltyPoints,
|
|
55
|
+
getGoogleObject
|
|
56
|
+
} from 'sbcwallet'
|
|
57
|
+
|
|
58
|
+
const biz = createBusiness({ name: 'SBC Coffee', pointsLabel: 'Beans' })
|
|
59
|
+
await createLoyaltyProgram({ businessId: biz.id })
|
|
60
|
+
|
|
61
|
+
const customer = createCustomerAccount({ businessId: biz.id, fullName: 'Alice' })
|
|
62
|
+
const card = await issueLoyaltyCard({ businessId: biz.id, customerId: customer.id, initialPoints: 10 })
|
|
63
|
+
await updateLoyaltyPoints({ cardId: card.id, delta: 5 })
|
|
64
|
+
|
|
65
|
+
const { saveUrl } = await getGoogleObject('child', card)
|
|
66
|
+
console.log(saveUrl)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
βΈ»
|
|
70
|
+
|
|
71
|
+
## π§ Architecture
|
|
72
|
+
```bash
|
|
73
|
+
sbcwallet
|
|
74
|
+
βββ adapters/ # Apple + Google Wallet adapters
|
|
75
|
+
βββ api/ # Unified issuance/update API
|
|
76
|
+
βββ profiles/ # Domain-specific field maps
|
|
77
|
+
βββ templates/ # JSON templates for passes
|
|
78
|
+
βββ types.ts # Shared types and validation
|
|
79
|
+
```
|
|
80
|
+
### Key Components
|
|
81
|
+
```bash
|
|
82
|
+
Module Description
|
|
83
|
+
adapters/apple.ts Builds and signs .pkpass files using passkit-generator.
|
|
84
|
+
adapters/google.ts Creates Google Wallet class/object JSON payloads.
|
|
85
|
+
api/unified.ts Unified functions: createParentSchedule, createChildTicket, updatePassStatus.
|
|
86
|
+
profiles/ Domain-specific mappings (logistics, healthcare, etc.).
|
|
87
|
+
templates/ JSON templates for field mapping and layout.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
βΈ»
|
|
91
|
+
|
|
92
|
+
## π§© Profiles
|
|
93
|
+
|
|
94
|
+
### Logistics (default)
|
|
95
|
+
|
|
96
|
+
Entity Description Example
|
|
97
|
+
Parent (PES) Program Entry Schedule Gate window, site, available slots
|
|
98
|
+
Child (TO) Transport Order Plate, carrier, client, status
|
|
99
|
+
Statuses ISSUED β PRESENCE β SCALE β OPS β EXITED
|
|
100
|
+
|
|
101
|
+
### Healthcare (reference)
|
|
102
|
+
|
|
103
|
+
Entity Description Example
|
|
104
|
+
Parent Appointment Batch Doctor, location, date
|
|
105
|
+
Child Patient Visit Ticket Patient, procedure, status
|
|
106
|
+
Statuses SCHEDULED β CHECKIN β PROCEDURE β DISCHARGED
|
|
107
|
+
|
|
108
|
+
Switch profiles dynamically:
|
|
109
|
+
```js
|
|
110
|
+
await createChildTicket({ profile: 'healthcare', ... })
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
βΈ»
|
|
114
|
+
|
|
115
|
+
## π Integration with sbcwallet Core
|
|
116
|
+
|
|
117
|
+
sbcwallet Pass automatically uses:
|
|
118
|
+
β’ hashEvent() for deterministic hashes
|
|
119
|
+
β’ signCredential() for ECDSA signatures
|
|
120
|
+
β’ dailyMerkle() for anchoring batches
|
|
121
|
+
|
|
122
|
+
This ensures every pass is cryptographically verifiable and compatible with sbcwalletβs event audit trail.
|
|
123
|
+
|
|
124
|
+
βΈ»
|
|
125
|
+
|
|
126
|
+
## π§ͺ Testing
|
|
127
|
+
|
|
128
|
+
`npm run test`
|
|
129
|
+
|
|
130
|
+
Tests include:
|
|
131
|
+
β’ Apple .pkpass field mapping
|
|
132
|
+
β’ Google Wallet JSON validity
|
|
133
|
+
β’ Cross-profile field validation
|
|
134
|
+
β’ Core integration (hash + sign + verify)
|
|
135
|
+
|
|
136
|
+
βΈ»
|
|
137
|
+
|
|
138
|
+
## βοΈ Environment Variables (Apple Wallet)
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
APPLE_TEAM_ID=ABCD1234
|
|
142
|
+
APPLE_PASS_TYPE_ID=pass.com.sbcwallet.logistics
|
|
143
|
+
APPLE_CERT_PATH=./certs/pass.p12
|
|
144
|
+
APPLE_CERT_PASSWORD=yourpassword
|
|
145
|
+
APPLE_WWDR_PATH=./certs/wwdr.pem
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
For Google Wallet, include:
|
|
149
|
+
```sh
|
|
150
|
+
GOOGLE_ISSUER_ID=issuer-id
|
|
151
|
+
GOOGLE_SA_JSON=./google/credentials.json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
βΈ»
|
|
155
|
+
|
|
156
|
+
## π§Ύ License
|
|
157
|
+
|
|
158
|
+
Apache License 2.0
|
|
159
|
+
Β© 2025 sbcwallet β open and extensible.
|
|
160
|
+
|
|
161
|
+
βΈ»
|
|
162
|
+
|
|
163
|
+
## π€ Contributing
|
|
164
|
+
1. Fork the repo
|
|
165
|
+
2. Run npm install
|
|
166
|
+
3. Add or improve a profile under src/profiles/
|
|
167
|
+
4. Write tests in tests/
|
|
168
|
+
5. Submit a PR using conventional commits
|
|
169
|
+
|
|
170
|
+
βΈ»
|
|
171
|
+
|
|
172
|
+
## π§ Part of the sbcwallet Ecosystem
|
|
173
|
+
|
|
174
|
+
Repo Purpose
|
|
175
|
+
```sh
|
|
176
|
+
sbcwallet/core Verifiable event SDK β hashing, signing, Merkle trees
|
|
177
|
+
sbcwallet/pass Wallet-pass abstraction over Core (this repo)
|
|
178
|
+
sbcwallet/wallet Reference logistics PWA & API
|
|
179
|
+
sbcwallet/id Hosted identity & orchestration layer (SaaS)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
βΈ»
|
|
183
|
+
|
|
184
|
+
βsbcwallet Pass connects cryptographic truth with human experience β
|
|
185
|
+
turning every credential into a verifiable story.β
|
|
186
|
+
|
|
187
|
+
Reflection: evidence β logic consistent brevity optimized
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PassData, ApplePassConfig, ProfileConfig } from '../types.js';
|
|
2
|
+
export declare class AppleWalletAdapter {
|
|
3
|
+
private config;
|
|
4
|
+
constructor(config?: Partial<ApplePassConfig>);
|
|
5
|
+
generatePkpass(passData: PassData, profile: ProfileConfig, passType: 'parent' | 'child'): Promise<Buffer>;
|
|
6
|
+
private mergeTemplates;
|
|
7
|
+
private populateTemplate;
|
|
8
|
+
private getFieldValue;
|
|
9
|
+
}
|
|
10
|
+
export default AppleWalletAdapter;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { PKPass } from 'passkit-generator';
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
export class AppleWalletAdapter {
|
|
8
|
+
config;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = {
|
|
11
|
+
teamId: config?.teamId || process.env.APPLE_TEAM_ID || '',
|
|
12
|
+
passTypeId: config?.passTypeId || process.env.APPLE_PASS_TYPE_ID || '',
|
|
13
|
+
certPath: config?.certPath || process.env.APPLE_CERT_PATH || '',
|
|
14
|
+
certPassword: config?.certPassword || process.env.APPLE_CERT_PASSWORD || '',
|
|
15
|
+
wwdrPath: config?.wwdrPath || process.env.APPLE_WWDR_PATH || ''
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async generatePkpass(passData, profile, passType) {
|
|
19
|
+
try {
|
|
20
|
+
// Load template
|
|
21
|
+
const templatePath = join(__dirname, '..', 'templates', 'apple', `${passType}.json`);
|
|
22
|
+
const templateContent = await readFile(templatePath, 'utf-8');
|
|
23
|
+
const baseTemplate = JSON.parse(templateContent);
|
|
24
|
+
// Get profile-specific template
|
|
25
|
+
const profileTemplate = profile.defaultTemplates.apple[passType];
|
|
26
|
+
// Merge templates
|
|
27
|
+
const template = this.mergeTemplates(baseTemplate, profileTemplate);
|
|
28
|
+
// Apply pass data to template
|
|
29
|
+
const populatedTemplate = this.populateTemplate(template, passData, profile, passType);
|
|
30
|
+
// Build pass props from populated template
|
|
31
|
+
const passProps = {
|
|
32
|
+
serialNumber: passData.id,
|
|
33
|
+
description: populatedTemplate.description || 'sbcwallet Pass',
|
|
34
|
+
organizationName: populatedTemplate.organizationName || 'sbcwallet',
|
|
35
|
+
passTypeIdentifier: this.config.passTypeId,
|
|
36
|
+
teamIdentifier: this.config.teamId
|
|
37
|
+
};
|
|
38
|
+
// Add colors
|
|
39
|
+
if (populatedTemplate.backgroundColor) {
|
|
40
|
+
passProps.backgroundColor = populatedTemplate.backgroundColor;
|
|
41
|
+
}
|
|
42
|
+
if (populatedTemplate.foregroundColor) {
|
|
43
|
+
passProps.foregroundColor = populatedTemplate.foregroundColor;
|
|
44
|
+
}
|
|
45
|
+
if (populatedTemplate.labelColor) {
|
|
46
|
+
passProps.labelColor = populatedTemplate.labelColor;
|
|
47
|
+
}
|
|
48
|
+
if (populatedTemplate.logoText) {
|
|
49
|
+
passProps.logoText = populatedTemplate.logoText;
|
|
50
|
+
}
|
|
51
|
+
// Add barcodes
|
|
52
|
+
if (populatedTemplate.barcodes && populatedTemplate.barcodes.length > 0) {
|
|
53
|
+
passProps.barcodes = populatedTemplate.barcodes;
|
|
54
|
+
}
|
|
55
|
+
// Add generic fields
|
|
56
|
+
if (populatedTemplate.generic) {
|
|
57
|
+
passProps.generic = populatedTemplate.generic;
|
|
58
|
+
}
|
|
59
|
+
// Create pass
|
|
60
|
+
const pass = new PKPass({}, {
|
|
61
|
+
wwdr: this.config.wwdrPath,
|
|
62
|
+
signerCert: this.config.certPath,
|
|
63
|
+
signerKey: this.config.certPath,
|
|
64
|
+
signerKeyPassphrase: this.config.certPassword
|
|
65
|
+
}, passProps);
|
|
66
|
+
// Generate buffer
|
|
67
|
+
const buffer = await pass.getAsBuffer();
|
|
68
|
+
return buffer;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new Error(`Failed to generate Apple Wallet pass: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
mergeTemplates(base, profile) {
|
|
75
|
+
return {
|
|
76
|
+
...base,
|
|
77
|
+
...profile,
|
|
78
|
+
generic: {
|
|
79
|
+
...base.generic,
|
|
80
|
+
...profile.generic,
|
|
81
|
+
primaryFields: profile.generic?.primaryFields || base.generic?.primaryFields,
|
|
82
|
+
secondaryFields: profile.generic?.secondaryFields || base.generic?.secondaryFields,
|
|
83
|
+
auxiliaryFields: profile.generic?.auxiliaryFields || base.generic?.auxiliaryFields,
|
|
84
|
+
backFields: profile.generic?.backFields || base.generic?.backFields,
|
|
85
|
+
headerFields: profile.generic?.headerFields || base.generic?.headerFields
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
populateTemplate(template, passData, profile, passType) {
|
|
90
|
+
const populated = { ...template };
|
|
91
|
+
if (populated.generic) {
|
|
92
|
+
// Populate primary fields
|
|
93
|
+
if (populated.generic.primaryFields) {
|
|
94
|
+
populated.generic.primaryFields = populated.generic.primaryFields.map(field => {
|
|
95
|
+
const value = this.getFieldValue(field.key, passData);
|
|
96
|
+
return { ...field, value: value || field.value };
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// Populate secondary fields
|
|
100
|
+
if (populated.generic.secondaryFields) {
|
|
101
|
+
populated.generic.secondaryFields = populated.generic.secondaryFields.map(field => {
|
|
102
|
+
const value = this.getFieldValue(field.key, passData);
|
|
103
|
+
return { ...field, value: value || field.value };
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Populate auxiliary fields
|
|
107
|
+
if (populated.generic.auxiliaryFields) {
|
|
108
|
+
populated.generic.auxiliaryFields = populated.generic.auxiliaryFields.map(field => {
|
|
109
|
+
const value = this.getFieldValue(field.key, passData);
|
|
110
|
+
return { ...field, value: value || field.value };
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// Populate back fields
|
|
114
|
+
if (populated.generic.backFields) {
|
|
115
|
+
populated.generic.backFields = populated.generic.backFields.map(field => {
|
|
116
|
+
const value = this.getFieldValue(field.key, passData);
|
|
117
|
+
return { ...field, value: value || field.value };
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Set barcode message
|
|
122
|
+
if (populated.barcodes && populated.barcodes.length > 0) {
|
|
123
|
+
const barcodeValue = passData.memberId || passData.id;
|
|
124
|
+
populated.barcodes[0].message = barcodeValue;
|
|
125
|
+
}
|
|
126
|
+
return populated;
|
|
127
|
+
}
|
|
128
|
+
getFieldValue(key, passData) {
|
|
129
|
+
// Handle nested keys like 'window.from'
|
|
130
|
+
const keys = key.split('.');
|
|
131
|
+
let value = passData;
|
|
132
|
+
for (const k of keys) {
|
|
133
|
+
if (value && typeof value === 'object' && k in value) {
|
|
134
|
+
value = value[k];
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
return '';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Map field names for common fields
|
|
141
|
+
if (key === 'scheduleId' || key === 'orderId' || key === 'batchId' || key === 'visitId') {
|
|
142
|
+
return passData.id;
|
|
143
|
+
}
|
|
144
|
+
if (key === 'windowFrom' && passData.type === 'parent' && passData.window) {
|
|
145
|
+
return new Date(passData.window.from).toLocaleString();
|
|
146
|
+
}
|
|
147
|
+
if (key === 'windowTo' && passData.type === 'parent' && passData.window) {
|
|
148
|
+
return new Date(passData.window.to).toLocaleString();
|
|
149
|
+
}
|
|
150
|
+
return value !== undefined && value !== null ? String(value) : '';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export default AppleWalletAdapter;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PassData, GooglePassConfig, GooglePassObject, ProfileConfig } from '../types.js';
|
|
2
|
+
export declare class GoogleWalletAdapter {
|
|
3
|
+
private config;
|
|
4
|
+
private auth;
|
|
5
|
+
constructor(config?: Partial<GooglePassConfig>);
|
|
6
|
+
generatePassObject(passData: PassData, profile: ProfileConfig, passType: 'parent' | 'child'): Promise<{
|
|
7
|
+
object: GooglePassObject;
|
|
8
|
+
saveUrl: string;
|
|
9
|
+
}>;
|
|
10
|
+
private generateLoyaltyClass;
|
|
11
|
+
private populateObject;
|
|
12
|
+
private applyLoyaltyExtras;
|
|
13
|
+
private getFieldValue;
|
|
14
|
+
private generateSaveUrl;
|
|
15
|
+
private upsertInAPI;
|
|
16
|
+
/**
|
|
17
|
+
* Generate and add hero image with progress bar to the pass object
|
|
18
|
+
*
|
|
19
|
+
* Note: Google Wallet API requires publicly accessible URLs for images.
|
|
20
|
+
* This method generates the hero image and saves it locally.
|
|
21
|
+
* For production, upload images to a CDN/cloud storage and use those URLs.
|
|
22
|
+
*/
|
|
23
|
+
private addHeroImage;
|
|
24
|
+
createClass(profile: ProfileConfig, passType: 'parent' | 'child'): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export default GoogleWalletAdapter;
|