@spoketech/hub-client 0.1.0
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 +252 -0
- package/dist/index.d.ts +37304 -0
- package/dist/index.js +4497 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
- package/skills/spoke-hub-client/SKILL.md +39 -0
- package/skills/spoke-hub-client/agents/openai.yaml +4 -0
- package/skills/spoke-hub-client/references/workflows.md +83 -0
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# `@spoketech/hub-client`
|
|
2
|
+
|
|
3
|
+
Async-first npm client for the Spoke Hub API, with optional Effect-native APIs underneath.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @spoketech/hub-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Client Shapes
|
|
12
|
+
|
|
13
|
+
The package exposes a friendly SDK surface plus the generated API client:
|
|
14
|
+
|
|
15
|
+
- `makePromiseSpokeClient`: Recommended object-style SDK for normal app and integration code.
|
|
16
|
+
- `makePromiseHubApiClient` / `makePromiseServiceHubApiClient`: Generated Promise client that mirrors HTTP routes.
|
|
17
|
+
- `makeHubApiClient` / `makeServiceHubApiClient`: Raw Effect clients when your app already uses Effect.
|
|
18
|
+
|
|
19
|
+
The generated client takes a single request object. Depending on the endpoint, that object can contain:
|
|
20
|
+
|
|
21
|
+
- `path`: Route parameters like `organizationId`, `memberId`, `guestId`, `runId`, or `serviceClientId`.
|
|
22
|
+
- `payload`: JSON request body.
|
|
23
|
+
- `urlParams`: Query-string parameters.
|
|
24
|
+
- `headers`: Per-call headers. Most callers should set auth at client creation time instead.
|
|
25
|
+
|
|
26
|
+
## Recommended Usage
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { makePromiseSpokeClient } from "@spoketech/hub-client";
|
|
30
|
+
|
|
31
|
+
const { client } = await makePromiseSpokeClient({
|
|
32
|
+
baseUrl: "https://hub.example.com",
|
|
33
|
+
clientId: process.env.SPOKE_CLIENT_ID!,
|
|
34
|
+
privateKey: process.env.SPOKE_PRIVATE_KEY!,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const members = await client.members.list({
|
|
38
|
+
organizationId: "org_123",
|
|
39
|
+
responseMode: "med",
|
|
40
|
+
page: 1,
|
|
41
|
+
pageSize: 25,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const member = await client.members.get({
|
|
45
|
+
organizationId: "org_123",
|
|
46
|
+
memberId: "mem_123",
|
|
47
|
+
responseMode: "full",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const guests = await client.guests.list({
|
|
51
|
+
organizationId: "org_123",
|
|
52
|
+
name: "Jane",
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Live Onsite Resource Calls
|
|
57
|
+
|
|
58
|
+
For member-source and voucher operations that must run from the venue network, use the onsite resource wrapper. It dispatches the command and waits briefly for the onsite client to complete it. If the onsite client takes longer than `waitMs`, the response includes the accepted command so callers can continue polling or observe webhooks.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { makePromiseOnsiteResourceClient } from "@spoketech/hub-client";
|
|
62
|
+
|
|
63
|
+
const { client } = await makePromiseOnsiteResourceClient({
|
|
64
|
+
baseUrl: "https://hub.example.com",
|
|
65
|
+
clientId: process.env.SPOKE_CLIENT_ID!,
|
|
66
|
+
privateKey: process.env.SPOKE_PRIVATE_KEY!,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const lookup = await client.members.lookup({
|
|
70
|
+
organizationId: "org_123",
|
|
71
|
+
lookupBy: "member_id",
|
|
72
|
+
lookupValue: "12345",
|
|
73
|
+
waitMs: 10_000,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (lookup.settled && lookup.command.status === "completed") {
|
|
77
|
+
console.log(lookup.command.result);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const voucher = await client.vouchers.issue({
|
|
81
|
+
organizationId: "org_123",
|
|
82
|
+
waitMs: 10_000,
|
|
83
|
+
payload: {
|
|
84
|
+
memberId: "mem_123",
|
|
85
|
+
rewardId: "reward_456",
|
|
86
|
+
quantity: 1,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The full Spoke client exposes the same live onsite wrapper under `client.onsite`:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const { client } = await makePromiseSpokeClient(options);
|
|
95
|
+
|
|
96
|
+
const lookup = await client.onsite.members.lookup({
|
|
97
|
+
organizationId: "org_123",
|
|
98
|
+
lookupBy: "member_id",
|
|
99
|
+
lookupValue: "12345",
|
|
100
|
+
waitMs: 10_000,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Service Client Authentication
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { makePromiseServiceHubApiClient } from "@spoketech/hub-client";
|
|
108
|
+
|
|
109
|
+
const { client } = await makePromiseServiceHubApiClient({
|
|
110
|
+
baseUrl: "https://hub.example.com",
|
|
111
|
+
clientId: process.env.SPOKE_CLIENT_ID!,
|
|
112
|
+
privateKey: process.env.SPOKE_PRIVATE_KEY!,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const organizations = await client.organizations.listOrganizations({
|
|
116
|
+
urlParams: { page: "1", pageSize: "25", name: "Spoke" },
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`baseUrl` should usually be the site origin. The client appends `/api` by default, so requests target `/api/v1/...`. Override `apiBasePath` if your deployment exposes the API somewhere else.
|
|
121
|
+
|
|
122
|
+
`makePromiseServiceHubApiClient` returns the generated low-level client. It mirrors HTTP routes with `path`, `payload`, and `urlParams`. Prefer `makePromiseSpokeClient` for app and integration code; it keeps object-style inputs while still returning `hubClient` as a raw escape hatch.
|
|
123
|
+
|
|
124
|
+
## Included Skill
|
|
125
|
+
|
|
126
|
+
The npm package also ships a Codex skill at `skills/spoke-hub-client/`. If the package is installed in `node_modules`, the skill lives at:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
node_modules/@spoketech/hub-client/skills/spoke-hub-client
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Effect Usage
|
|
133
|
+
|
|
134
|
+
If you do want the raw Effect client, `makeHubApiClient` and `makeServiceHubApiClient` are still exported.
|
|
135
|
+
|
|
136
|
+
## Onsite Source Writes
|
|
137
|
+
|
|
138
|
+
For Odyssey Gaming sources, member creation, update, renewal, lookup, and onsite voucher issuing are command requests, not direct Hub-to-Nexus/SENPOS API calls.
|
|
139
|
+
|
|
140
|
+
- The Hub publishes a command to the configured onsite agent through AWS IoT Core.
|
|
141
|
+
- The onsite agent runs on the venue network, calls Nexus from the onsite IP, and then posts the result back to Hub through the completion endpoints.
|
|
142
|
+
- The `onsiteCalls.callOnsiteResource` endpoint and onsite resource wrapper wait briefly for completion, then return the accepted command if the onsite client is still working.
|
|
143
|
+
|
|
144
|
+
Relevant configuration:
|
|
145
|
+
|
|
146
|
+
- Hub: `AWS_IOT_DATA_ENDPOINT`, `AWS_REGION`, `ONSITE_AGENT_IOT_TOPIC_PREFIX`
|
|
147
|
+
- Onsite agent: `ONSITE_AGENT_TRANSPORT=iot`, `ONSITE_AGENT_IOT_TOPIC_PREFIX`
|
|
148
|
+
|
|
149
|
+
## Endpoint Reference
|
|
150
|
+
|
|
151
|
+
All routes below are relative to `/api/v1`. The promise client and the Effect client use the same method names.
|
|
152
|
+
|
|
153
|
+
### Auth
|
|
154
|
+
|
|
155
|
+
| Client method | Route | Request | Returns |
|
|
156
|
+
| --- | --- | --- | --- |
|
|
157
|
+
| `client.auth.getAdminSession({})` | `GET /admin/session` | none | `AdminSession` |
|
|
158
|
+
|
|
159
|
+
### Organizations
|
|
160
|
+
|
|
161
|
+
| Client method | Route | Request | Returns |
|
|
162
|
+
| --- | --- | --- | --- |
|
|
163
|
+
| `client.organizations.listOrganizations({ urlParams })` | `GET /organizations` | optional `page`, `pageSize`, `name` | `PaginatedOrganizations` |
|
|
164
|
+
| `client.organizations.createOrganization({ payload })` | `POST /organizations` | `CreateOrganizationInput` | `Organization` |
|
|
165
|
+
| `client.organizations.updateOrganization({ path, payload })` | `PATCH /organizations/:organizationId` | `path.organizationId`, `UpdateOrganizationInput` | `Organization` |
|
|
166
|
+
| `client.organizations.deleteOrganization({ path, payload })` | `DELETE /organizations/:organizationId` | `path.organizationId`, `DeletePayload` | `void` |
|
|
167
|
+
|
|
168
|
+
### Members
|
|
169
|
+
|
|
170
|
+
| Client method | Route | Request | Returns |
|
|
171
|
+
| --- | --- | --- | --- |
|
|
172
|
+
| `client.members.listOrganizationMembers({ path, urlParams })` | `GET /organizations/:organizationId/members` | `path.organizationId`, optional paging and search `urlParams` | `OrganizationMembersListResponse` |
|
|
173
|
+
| `client.members.getOrganizationMember({ path, urlParams })` | `GET /organizations/:organizationId/members/:memberId` | `path.organizationId`, `path.memberId`, optional `responseMode` | `MemberResponse` |
|
|
174
|
+
| `client.members.listOrganizationMemberMembershipTypes({ path, urlParams })` | `GET /organizations/:organizationId/members/membership-types` | `path.organizationId`, optional `page`, `pageSize` | `PaginatedOrganizationMemberMembershipTypes` |
|
|
175
|
+
| `client.members.listOrganizationMemberRatingGrades({ path, urlParams })` | `GET /organizations/:organizationId/members/rating-grades` | `path.organizationId`, optional `page`, `pageSize` | `PaginatedOrganizationMemberRatingGrades` |
|
|
176
|
+
| `client.members.createOrganizationMember({ path, payload })` | `POST /organizations/:organizationId/members` | `path.organizationId`, `CreateMemberInput` for local-member creation | `Member` |
|
|
177
|
+
| `client.members.requestSourceManagedMemberCreate({ path, payload })` | `POST /organizations/:organizationId/members/source-create` | `path.organizationId`, `RequestSourceManagedMemberCreateInput` for Odyssey/onsite source creation | `OrganizationMemberSourceCommand` |
|
|
178
|
+
| `client.members.requestSourceManagedMemberRenewal({ path, payload })` | `POST /organizations/:organizationId/members/:memberId/source-renewal` | `path.organizationId`, `path.memberId`, `RequestSourceManagedMemberRenewalInput` for Odyssey/onsite source renewal | `OrganizationMemberSourceCommand` |
|
|
179
|
+
| `client.members.updateOrganizationMember({ path, payload })` | `PATCH /organizations/:organizationId/members/:memberId` | `path.organizationId`, `path.memberId`, `UpdateMemberInput` | `Member` |
|
|
180
|
+
| `client.members.deleteOrganizationMember({ path, payload })` | `DELETE /organizations/:organizationId/members/:memberId` | `path.organizationId`, `path.memberId`, `DeletePayload` | `void` |
|
|
181
|
+
|
|
182
|
+
### Member Sources
|
|
183
|
+
|
|
184
|
+
| Client method | Route | Request | Returns |
|
|
185
|
+
| --- | --- | --- | --- |
|
|
186
|
+
| `client.memberSources.getOrganizationMemberSource({ path })` | `GET /organizations/:organizationId/member-source` | `path.organizationId` | `OrganizationMemberSource \| null` |
|
|
187
|
+
| `client.memberSources.upsertOrganizationMemberSource({ path, payload })` | `PUT /organizations/:organizationId/member-source` | `path.organizationId`, `UpsertOrganizationMemberSourceInput` | `OrganizationMemberSource` |
|
|
188
|
+
| `client.memberSources.bootstrapOrganizationMemberSourceAgent({ path, payload })` | `POST /organizations/:organizationId/member-source/agent/bootstrap` | `path.organizationId`, `BootstrapOrganizationMemberSourceAgentInput` | `BootstrapOrganizationMemberSourceAgentResponse` |
|
|
189
|
+
| `client.memberSources.getOrganizationMemberSourceCsvUploadReadiness({ path })` | `GET /organizations/:organizationId/member-source/csv-upload-readiness` | `path.organizationId` | `CsvUploadReadiness` |
|
|
190
|
+
| `client.memberSources.getOrganizationMemberSourceCsvMapping({ path })` | `GET /organizations/:organizationId/member-source/csv-mapping` | `path.organizationId` | `OrganizationMemberSourceCsvMapping \| null` |
|
|
191
|
+
| `client.memberSources.upsertOrganizationMemberSourceCsvMapping({ path, payload })` | `PUT /organizations/:organizationId/member-source/csv-mapping` | `path.organizationId`, `UpsertOrganizationMemberSourceCsvMappingInput` | `OrganizationMemberSourceCsvMapping` |
|
|
192
|
+
| `client.memberSources.createOrganizationMemberSourceCsvUpload({ path, payload })` | `POST /organizations/:organizationId/member-source/csv-uploads` | `path.organizationId`, `CreateOrganizationMemberSourceCsvUploadInput` | `CreateOrganizationMemberSourceCsvUploadResponse` |
|
|
193
|
+
| `client.memberSources.listOrganizationMemberSyncRuns({ path, urlParams })` | `GET /organizations/:organizationId/member-source/runs` | `path.organizationId`, optional `page`, `pageSize` | `PaginatedOrganizationMemberSyncRuns` |
|
|
194
|
+
| `client.memberSources.listOrganizationMemberSourceCommands({ path, urlParams })` | `GET /organizations/:organizationId/member-source/commands` | `path.organizationId`, optional `page`, `pageSize` | `PaginatedOrganizationMemberSourceCommands` |
|
|
195
|
+
| `client.memberSources.triggerOrganizationMemberSync({ path, payload })` | `POST /organizations/:organizationId/member-source/sync` | `path.organizationId`, `TriggerOrganizationMemberSyncInput` | `OrganizationMemberSyncRun` |
|
|
196
|
+
|
|
197
|
+
### Vouchers
|
|
198
|
+
|
|
199
|
+
| Client method | Route | Request | Returns |
|
|
200
|
+
| --- | --- | --- | --- |
|
|
201
|
+
| `client.vouchers.getOrganizationVoucherProvider({ path })` | `GET /organizations/:organizationId/voucher-provider` | `path.organizationId` | `OrganizationVoucherProvider \| null` |
|
|
202
|
+
| `client.vouchers.upsertOrganizationVoucherProvider({ path, payload })` | `PUT /organizations/:organizationId/voucher-provider` | `path.organizationId`, `UpsertOrganizationVoucherProviderInput` | `OrganizationVoucherProvider` |
|
|
203
|
+
| `client.vouchers.requestVoucherIssue({ path, payload })` | `POST /organizations/:organizationId/vouchers/issue` | `path.organizationId`, `RequestVoucherIssueInput` | `OrganizationVoucherCommand` |
|
|
204
|
+
| `client.vouchers.pollOnsiteVoucherCommand({ path })` | `POST /organizations/:organizationId/onsite-voucher-commands/poll` | `path.organizationId` | `OnsiteVoucherCommand \| null` |
|
|
205
|
+
| `client.vouchers.completeOnsiteVoucherCommand({ path, payload })` | `POST /organizations/:organizationId/onsite-voucher-commands/:commandId/complete` | `path.organizationId`, `path.commandId`, `CompleteOnsiteVoucherCommandInput` | `OrganizationVoucherCommand` |
|
|
206
|
+
|
|
207
|
+
### Onsite Calls
|
|
208
|
+
|
|
209
|
+
| Client method | Route | Request | Returns |
|
|
210
|
+
| --- | --- | --- | --- |
|
|
211
|
+
| `client.onsiteCalls.callOnsiteResource({ path, payload })` | `POST /organizations/:organizationId/onsite-calls` | `OnsiteResourceCallRequest` for member create/update/renew/lookup or voucher issue | `OnsiteResourceCallResponse` |
|
|
212
|
+
|
|
213
|
+
### Onsite Agents
|
|
214
|
+
|
|
215
|
+
| Client method | Route | Request | Returns |
|
|
216
|
+
| --- | --- | --- | --- |
|
|
217
|
+
| `client.onsiteAgents.heartbeatOnsiteAgent({ payload })` | `POST /onsite-agent/heartbeat` | `OnsiteAgentHeartbeatInput` | `OrganizationMemberSourceAgent` |
|
|
218
|
+
| `client.onsiteAgents.pollOnsiteAgentCommand({})` | `POST /onsite-agent/commands/poll` | none | `OnsiteAgentCommand \| null` |
|
|
219
|
+
| `client.onsiteAgents.pollOnsiteAgentMemberCreateCommand({})` | `POST /onsite-agent/member-commands/poll` | none | `OnsiteAgentMemberCreateCommand \| null` |
|
|
220
|
+
| `client.onsiteAgents.pollOnsiteAgentMemberRenewalCommand({})` | `POST /onsite-agent/member-renewal-commands/poll` | none | `OnsiteAgentMemberRenewalCommand \| null` |
|
|
221
|
+
| `client.onsiteAgents.completeOnsiteAgentRun({ path, payload })` | `POST /onsite-agent/runs/:runId/complete` | `path.runId`, `OnsiteAgentCompleteRunInput` | `OrganizationMemberSyncRun` |
|
|
222
|
+
| `client.onsiteAgents.completeOnsiteAgentMemberCreate({ path, payload })` | `POST /onsite-agent/member-commands/:commandId/complete` | `path.commandId`, `OnsiteAgentCompleteMemberCreateInput` | `OrganizationMemberSourceCommand` |
|
|
223
|
+
| `client.onsiteAgents.completeOnsiteAgentMemberRenewal({ path, payload })` | `POST /onsite-agent/member-renewal-commands/:commandId/complete` | `path.commandId`, `OnsiteAgentCompleteMemberRenewalInput` | `OrganizationMemberSourceCommand` |
|
|
224
|
+
|
|
225
|
+
### Guests
|
|
226
|
+
|
|
227
|
+
| Client method | Route | Request | Returns |
|
|
228
|
+
| --- | --- | --- | --- |
|
|
229
|
+
| `client.guests.listGuests({ path, urlParams })` | `GET /organizations/:organizationId/guests` | `path.organizationId`, optional paging and filters `urlParams` | `PaginatedGuests` |
|
|
230
|
+
| `client.guests.createGuest({ path, payload })` | `POST /organizations/:organizationId/guests` | `path.organizationId`, `CreateGuestInput` | `Guest` |
|
|
231
|
+
| `client.guests.updateGuest({ path, payload })` | `PATCH /organizations/:organizationId/guests/:guestId` | `path.organizationId`, `path.guestId`, `UpdateGuestInput` | `Guest` |
|
|
232
|
+
| `client.guests.deleteGuest({ path, payload })` | `DELETE /organizations/:organizationId/guests/:guestId` | `path.organizationId`, `path.guestId`, `DeletePayload` | `void` |
|
|
233
|
+
|
|
234
|
+
### Service Clients
|
|
235
|
+
|
|
236
|
+
| Client method | Route | Request | Returns |
|
|
237
|
+
| --- | --- | --- | --- |
|
|
238
|
+
| `client.serviceClients.listServiceClients({ urlParams })` | `GET /service-clients` | optional `page`, `pageSize` | `PaginatedServiceClients` |
|
|
239
|
+
| `client.serviceClients.createServiceClient({ payload })` | `POST /service-clients` | `CreateServiceClientInput` | `{ client: ServiceClient; privateKey: string }` |
|
|
240
|
+
| `client.serviceClients.updateServiceClient({ path, payload })` | `PATCH /service-clients/:serviceClientId` | `path.serviceClientId`, `UpdateServiceClientInput` | `{ client: ServiceClient; privateKey?: string }` |
|
|
241
|
+
|
|
242
|
+
## Type Exports
|
|
243
|
+
|
|
244
|
+
The package re-exports the shared contract types, so you can import payload and response types directly:
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import type {
|
|
248
|
+
CreateMemberInput,
|
|
249
|
+
MemberResponse,
|
|
250
|
+
OrganizationMembersListResponse,
|
|
251
|
+
} from "@spoketech/hub-client";
|
|
252
|
+
```
|