@central-ticket/queue-sdk 0.0.1 → 0.0.2
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/centralq-C3ukDo0x.d.mts +134 -0
- package/dist/centralq-C3ukDo0x.d.ts +134 -0
- package/dist/{chunk-A4HITWM4.mjs → chunk-4MXU7S6A.mjs} +1 -1
- package/dist/{chunk-42RGFZKP.mjs → chunk-A37B25XO.mjs} +27 -0
- package/dist/chunk-BVCZFNM3.mjs +329 -0
- package/dist/{chunk-JR7BCYB5.mjs → chunk-GWPLLJTU.mjs} +2 -2
- package/dist/chunk-JJ33EJ65.mjs +31 -0
- package/dist/chunk-P73Q2ZIO.mjs +167 -0
- package/dist/chunk-XIQ6LS62.mjs +312 -0
- package/dist/index.d.mts +31 -3
- package/dist/index.d.ts +31 -3
- package/dist/index.js +166 -4
- package/dist/index.mjs +3 -3
- package/dist/react.d.mts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +70 -2
- package/dist/react.mjs +2 -2
- package/dist/server.js +1 -1
- package/dist/server.mjs +2 -2
- package/dist/svelte.d.mts +1 -1
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.js +70 -2
- package/dist/svelte.mjs +2 -2
- package/dist/vue.d.mts +1 -1
- package/dist/vue.d.ts +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// src/queue-client.ts
|
|
2
|
+
var CENTRALQ_DEFAULT_API_URL = "http://localhost:3001";
|
|
3
|
+
function normalizeApiUrl(apiUrl) {
|
|
4
|
+
const trimmed = apiUrl.replace(/\/+$/, "");
|
|
5
|
+
return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed;
|
|
6
|
+
}
|
|
7
|
+
var QueueHttpClient = class {
|
|
8
|
+
constructor(apiUrl = CENTRALQ_DEFAULT_API_URL, apiKey, queueInitToken) {
|
|
9
|
+
this.apiUrl = apiUrl;
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
this.queueInitToken = queueInitToken;
|
|
12
|
+
this.apiUrl = normalizeApiUrl(this.apiUrl);
|
|
13
|
+
}
|
|
14
|
+
get headers() {
|
|
15
|
+
const h = { "Content-Type": "application/json" };
|
|
16
|
+
if (this.apiKey) h["x-api-key"] = this.apiKey;
|
|
17
|
+
if (this.queueInitToken) h["x-queue-init-token"] = this.queueInitToken;
|
|
18
|
+
return h;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Intenta unir a un usuario a la cola de un evento.
|
|
22
|
+
* Llama a POST /api/queue/:eventId/join en el worker.
|
|
23
|
+
*/
|
|
24
|
+
async joinQueue(eventId, userId) {
|
|
25
|
+
const res = await fetch(
|
|
26
|
+
`${this.apiUrl}/api/queue/${encodeURIComponent(eventId)}/join`,
|
|
27
|
+
{
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: this.headers,
|
|
30
|
+
body: JSON.stringify({ userId })
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
const body = await res.json().catch(() => ({}));
|
|
35
|
+
throw new Error(
|
|
36
|
+
body.message ?? `Error ${res.status} al conectar con el sistema de colas`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return res.json();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Envía un heartbeat para mantener vivo el slot (waiting o active).
|
|
43
|
+
* El SDK lo llama cada 10s automáticamente.
|
|
44
|
+
*/
|
|
45
|
+
async sendHeartbeat(eventId, userId) {
|
|
46
|
+
await fetch(
|
|
47
|
+
`${this.apiUrl}/api/queue/${encodeURIComponent(eventId)}/heartbeat`,
|
|
48
|
+
{
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: this.headers,
|
|
51
|
+
body: JSON.stringify({ userId })
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Libera el slot del usuario inmediatamente.
|
|
57
|
+
* Llamar al completar la compra o al salir voluntariamente.
|
|
58
|
+
*/
|
|
59
|
+
async leaveQueue(eventId, userId) {
|
|
60
|
+
await fetch(
|
|
61
|
+
`${this.apiUrl}/api/queue/${encodeURIComponent(eventId)}/leave`,
|
|
62
|
+
{
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: this.headers,
|
|
65
|
+
body: JSON.stringify({ userId })
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
async issueQueueInitToken(eventId, userId, admissionProof) {
|
|
70
|
+
const res = await fetch(
|
|
71
|
+
`${this.apiUrl}/api/queue/init/${encodeURIComponent(eventId)}`,
|
|
72
|
+
{
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: this.headers,
|
|
75
|
+
body: JSON.stringify({ userId, admissionProof })
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
const body = await res.json().catch(() => ({}));
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
body.message ?? `Error ${res.status} al inicializar sesi\xF3n de cola`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
const token = body.queueInitToken ?? body.initToken;
|
|
85
|
+
if (!body.userId || !token || !body.expiresAt) {
|
|
86
|
+
throw new Error("Respuesta inv\xE1lida al inicializar sesi\xF3n de cola");
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
userId: body.userId,
|
|
90
|
+
queueInitToken: token,
|
|
91
|
+
expiresAt: body.expiresAt
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async getProtection(eventId) {
|
|
95
|
+
const res = await fetch(
|
|
96
|
+
`${this.apiUrl}/api/queue/${encodeURIComponent(eventId)}/protection`,
|
|
97
|
+
{ headers: this.headers }
|
|
98
|
+
);
|
|
99
|
+
const body = await res.json().catch(() => ({}));
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
body.message ?? `Error ${res.status} al consultar protecci\xF3n`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
eventId: body.eventId ?? eventId,
|
|
107
|
+
configured: body.configured === true,
|
|
108
|
+
protected: body.protected === true,
|
|
109
|
+
isActive: body.isActive === true,
|
|
110
|
+
admissionMode: body.admissionMode ?? "PUBLIC",
|
|
111
|
+
challengeRequired: body.challengeRequired === true
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async getAdmissionChallenge(eventId) {
|
|
115
|
+
const res = await fetch(
|
|
116
|
+
`${this.apiUrl}/api/queue/${encodeURIComponent(eventId)}/admission`,
|
|
117
|
+
{ headers: this.headers }
|
|
118
|
+
);
|
|
119
|
+
const body = await res.json().catch(() => ({}));
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
body.message ?? `Error ${res.status} al preparar la admisi\xF3n`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
if (body.required !== true) return { required: false };
|
|
126
|
+
if (!("publicKey" in body) || !body.publicKey) {
|
|
127
|
+
throw new Error("Respuesta inv\xE1lida al preparar la admisi\xF3n");
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
required: true,
|
|
131
|
+
publicKey: body.publicKey,
|
|
132
|
+
appearance: "interaction-only"
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async verifyToken(eventId, token) {
|
|
136
|
+
const res = await fetch(
|
|
137
|
+
`${this.apiUrl}/api/queue/verify/${encodeURIComponent(eventId)}`,
|
|
138
|
+
{
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: this.headers,
|
|
141
|
+
body: JSON.stringify({ token })
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
const body = await res.json().catch(() => ({
|
|
145
|
+
valid: false,
|
|
146
|
+
reason: "Respuesta inv\xE1lida"
|
|
147
|
+
}));
|
|
148
|
+
if (body.valid === true && body.userId && body.eventId && body.expiresAt) {
|
|
149
|
+
return body;
|
|
150
|
+
}
|
|
151
|
+
if (body.valid === false) {
|
|
152
|
+
return { valid: false, reason: body.reason ?? "Token inv\xE1lido" };
|
|
153
|
+
}
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
return {
|
|
156
|
+
valid: false,
|
|
157
|
+
reason: body.message ?? `Error ${res.status} al validar token de cola`
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return { valid: false, reason: "Respuesta inv\xE1lida" };
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export {
|
|
165
|
+
CENTRALQ_DEFAULT_API_URL,
|
|
166
|
+
QueueHttpClient
|
|
167
|
+
};
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CENTRALQ_DEFAULT_API_URL,
|
|
3
|
+
QueueHttpClient
|
|
4
|
+
} from "./chunk-P73Q2ZIO.mjs";
|
|
5
|
+
|
|
6
|
+
// src/admission.ts
|
|
7
|
+
var turnstileScript = null;
|
|
8
|
+
function loadManagedAdmissionDriver() {
|
|
9
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
10
|
+
return Promise.reject(
|
|
11
|
+
new Error("La admisi\xF3n administrada requiere un navegador")
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
if (window.turnstile) return Promise.resolve(window.turnstile);
|
|
15
|
+
if (turnstileScript) return turnstileScript;
|
|
16
|
+
turnstileScript = new Promise((resolve, reject) => {
|
|
17
|
+
const script = document.createElement("script");
|
|
18
|
+
script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
|
|
19
|
+
script.async = true;
|
|
20
|
+
script.defer = true;
|
|
21
|
+
script.onload = () => {
|
|
22
|
+
if (window.turnstile) resolve(window.turnstile);
|
|
23
|
+
else reject(new Error("No se pudo inicializar la admisi\xF3n administrada"));
|
|
24
|
+
};
|
|
25
|
+
script.onerror = () => reject(new Error("No se pudo cargar la admisi\xF3n administrada"));
|
|
26
|
+
document.head.appendChild(script);
|
|
27
|
+
});
|
|
28
|
+
return turnstileScript;
|
|
29
|
+
}
|
|
30
|
+
async function acquireManagedAdmissionProof(publicKey) {
|
|
31
|
+
const driver = await loadManagedAdmissionDriver();
|
|
32
|
+
const container = document.createElement("div");
|
|
33
|
+
container.style.position = "fixed";
|
|
34
|
+
container.style.inset = "0";
|
|
35
|
+
container.style.zIndex = "2147483647";
|
|
36
|
+
container.style.display = "grid";
|
|
37
|
+
container.style.placeItems = "center";
|
|
38
|
+
container.style.pointerEvents = "none";
|
|
39
|
+
document.body.appendChild(container);
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
let widgetId = "";
|
|
42
|
+
const cleanup = () => {
|
|
43
|
+
if (widgetId) driver.remove(widgetId);
|
|
44
|
+
container.remove();
|
|
45
|
+
};
|
|
46
|
+
widgetId = driver.render(container, {
|
|
47
|
+
sitekey: publicKey,
|
|
48
|
+
appearance: "interaction-only",
|
|
49
|
+
execution: "execute",
|
|
50
|
+
action: "centralq_admission",
|
|
51
|
+
callback: (token) => {
|
|
52
|
+
cleanup();
|
|
53
|
+
resolve(token);
|
|
54
|
+
},
|
|
55
|
+
"error-callback": () => {
|
|
56
|
+
cleanup();
|
|
57
|
+
reject(new Error("La validaci\xF3n de admisi\xF3n fall\xF3"));
|
|
58
|
+
},
|
|
59
|
+
"expired-callback": () => {
|
|
60
|
+
cleanup();
|
|
61
|
+
reject(new Error("La validaci\xF3n de admisi\xF3n expir\xF3"));
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
driver.execute(widgetId);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/centralq.ts
|
|
69
|
+
var CentralQ = class _CentralQ {
|
|
70
|
+
constructor(options) {
|
|
71
|
+
this.element = null;
|
|
72
|
+
this.destroyed = false;
|
|
73
|
+
// biome-ignore lint: allow explicit any for generic event map
|
|
74
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
75
|
+
this.client = new QueueHttpClient(
|
|
76
|
+
options.apiUrl,
|
|
77
|
+
options.apiKey,
|
|
78
|
+
options.queueInitToken
|
|
79
|
+
);
|
|
80
|
+
this.eventId = options.eventId;
|
|
81
|
+
this.pollInterval = options.pollInterval ?? 1e4;
|
|
82
|
+
this.container = options.container ?? document.body;
|
|
83
|
+
this.userId = this.resolveUserId(options.userId);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Inicializa CentralQ y comienza el flujo de cola automáticamente.
|
|
87
|
+
* Monta el overlay de UI y empieza a hacer polling.
|
|
88
|
+
*/
|
|
89
|
+
static init(options) {
|
|
90
|
+
const instance = new _CentralQ(options);
|
|
91
|
+
instance.mount();
|
|
92
|
+
instance.checkQueue();
|
|
93
|
+
return instance;
|
|
94
|
+
}
|
|
95
|
+
// Event API
|
|
96
|
+
/** Suscribirse a un evento del ciclo de vida de la cola */
|
|
97
|
+
on(event, listener) {
|
|
98
|
+
if (!this.listeners.has(event)) {
|
|
99
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
100
|
+
}
|
|
101
|
+
this.listeners.get(event).add(listener);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
/** Desuscribirse de un evento */
|
|
105
|
+
off(event, listener) {
|
|
106
|
+
this.listeners.get(event)?.delete(listener);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
emit(event, detail) {
|
|
110
|
+
this.listeners.get(event)?.forEach((fn) => fn(detail));
|
|
111
|
+
}
|
|
112
|
+
// Métodos públicos
|
|
113
|
+
/**
|
|
114
|
+
* Libera el slot del usuario inmediatamente.
|
|
115
|
+
* Llamar cuando el usuario completa la compra.
|
|
116
|
+
*/
|
|
117
|
+
leave() {
|
|
118
|
+
this.stopTimers();
|
|
119
|
+
this.updateUI("ACTIVE");
|
|
120
|
+
this.client.leaveQueue(this.eventId, this.userId).catch(() => {
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Destruye la instancia: para todos los timers, desmonta el overlay,
|
|
125
|
+
* y libera el slot en el servidor.
|
|
126
|
+
*/
|
|
127
|
+
destroy() {
|
|
128
|
+
this.destroyed = true;
|
|
129
|
+
this.stopTimers();
|
|
130
|
+
this.client.leaveQueue(this.eventId, this.userId).catch(() => {
|
|
131
|
+
});
|
|
132
|
+
this.unmount();
|
|
133
|
+
this.listeners.clear();
|
|
134
|
+
}
|
|
135
|
+
/** Retorna el userId resuelto (externo o autogenerado) */
|
|
136
|
+
getUserId() {
|
|
137
|
+
return this.userId;
|
|
138
|
+
}
|
|
139
|
+
// userId: genera y persiste automáticamente
|
|
140
|
+
resolveUserId(externalId) {
|
|
141
|
+
if (externalId) return externalId;
|
|
142
|
+
const key = `ctq_anon_${this.eventId}`;
|
|
143
|
+
try {
|
|
144
|
+
const stored = sessionStorage.getItem(key);
|
|
145
|
+
if (stored) return stored;
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
const generated = `anon_${crypto.randomUUID()}`;
|
|
149
|
+
try {
|
|
150
|
+
sessionStorage.setItem(key, generated);
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
return generated;
|
|
154
|
+
}
|
|
155
|
+
// UI: montar/desmontar el Web Component
|
|
156
|
+
mount() {
|
|
157
|
+
import("./queue-element-DXBW64U2.mjs");
|
|
158
|
+
this.element = document.createElement("central-q");
|
|
159
|
+
this.element.onRetry = () => {
|
|
160
|
+
this.updateUI("LOADING");
|
|
161
|
+
this.checkQueue();
|
|
162
|
+
};
|
|
163
|
+
this.container.appendChild(this.element);
|
|
164
|
+
}
|
|
165
|
+
unmount() {
|
|
166
|
+
if (this.element) {
|
|
167
|
+
this.element.remove();
|
|
168
|
+
this.element = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
updateUI(status, data) {
|
|
172
|
+
if (!this.element) return;
|
|
173
|
+
this.element.status = status;
|
|
174
|
+
if (data?.position !== void 0) this.element.position = data.position;
|
|
175
|
+
if (data?.ahead !== void 0) this.element.ahead = data.ahead;
|
|
176
|
+
}
|
|
177
|
+
// Timers
|
|
178
|
+
stopTimers() {
|
|
179
|
+
if (this.pollingTimer) {
|
|
180
|
+
clearInterval(this.pollingTimer);
|
|
181
|
+
this.pollingTimer = void 0;
|
|
182
|
+
}
|
|
183
|
+
if (this.heartbeatTimer) {
|
|
184
|
+
clearInterval(this.heartbeatTimer);
|
|
185
|
+
this.heartbeatTimer = void 0;
|
|
186
|
+
}
|
|
187
|
+
if (this.expiryTimer) {
|
|
188
|
+
clearTimeout(this.expiryTimer);
|
|
189
|
+
this.expiryTimer = void 0;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
startHeartbeat() {
|
|
193
|
+
if (this.heartbeatTimer) return;
|
|
194
|
+
this.heartbeatTimer = setInterval(() => {
|
|
195
|
+
this.client.sendHeartbeat(this.eventId, this.userId).catch(() => {
|
|
196
|
+
});
|
|
197
|
+
}, this.pollInterval);
|
|
198
|
+
}
|
|
199
|
+
scheduleExpiry(expiresAt) {
|
|
200
|
+
if (this.expiryTimer) clearTimeout(this.expiryTimer);
|
|
201
|
+
const msLeft = expiresAt * 1e3 - Date.now();
|
|
202
|
+
if (msLeft <= 0) {
|
|
203
|
+
this.handleExpired();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
this.expiryTimer = setTimeout(() => this.handleExpired(), msLeft);
|
|
207
|
+
}
|
|
208
|
+
handleExpired() {
|
|
209
|
+
this.stopTimers();
|
|
210
|
+
this.updateUI("EXPIRED");
|
|
211
|
+
this.emit("expired", {
|
|
212
|
+
userId: this.userId,
|
|
213
|
+
eventId: this.eventId
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// Core: polling + join
|
|
217
|
+
async checkQueue() {
|
|
218
|
+
if (this.destroyed) return;
|
|
219
|
+
try {
|
|
220
|
+
const res = await this.client.joinQueue(this.eventId, this.userId);
|
|
221
|
+
if (res.status === "ACTIVE") {
|
|
222
|
+
if (this.pollingTimer) {
|
|
223
|
+
clearInterval(this.pollingTimer);
|
|
224
|
+
this.pollingTimer = void 0;
|
|
225
|
+
}
|
|
226
|
+
this.startHeartbeat();
|
|
227
|
+
this.scheduleExpiry(res.expiresAt);
|
|
228
|
+
this.updateUI("ACTIVE");
|
|
229
|
+
this.emit("passed", {
|
|
230
|
+
token: res.token,
|
|
231
|
+
expiresAt: res.expiresAt,
|
|
232
|
+
userId: this.userId,
|
|
233
|
+
eventId: this.eventId
|
|
234
|
+
});
|
|
235
|
+
} else if (res.status === "WAITING") {
|
|
236
|
+
this.updateUI("WAITING", {
|
|
237
|
+
position: res.position,
|
|
238
|
+
ahead: res.ahead
|
|
239
|
+
});
|
|
240
|
+
this.emit("position", {
|
|
241
|
+
position: res.position,
|
|
242
|
+
ahead: res.ahead,
|
|
243
|
+
userId: this.userId,
|
|
244
|
+
eventId: this.eventId
|
|
245
|
+
});
|
|
246
|
+
if (!this.pollingTimer) {
|
|
247
|
+
this.pollingTimer = setInterval(
|
|
248
|
+
() => this.checkQueue(),
|
|
249
|
+
this.pollInterval
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch {
|
|
254
|
+
this.updateUI("ERROR");
|
|
255
|
+
this.stopTimers();
|
|
256
|
+
this.emit("error", {
|
|
257
|
+
userId: this.userId,
|
|
258
|
+
eventId: this.eventId
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var CentralQClient = class {
|
|
264
|
+
constructor(defaults) {
|
|
265
|
+
this.defaults = defaults;
|
|
266
|
+
}
|
|
267
|
+
issueQueueInitToken(eventId, userId) {
|
|
268
|
+
const client = new QueueHttpClient(
|
|
269
|
+
this.defaults.apiUrl,
|
|
270
|
+
this.defaults.apiKey
|
|
271
|
+
);
|
|
272
|
+
return this.issueInitToken(client, eventId, userId);
|
|
273
|
+
}
|
|
274
|
+
async issueInitToken(client, eventId, userId) {
|
|
275
|
+
if (typeof window === "undefined") {
|
|
276
|
+
return client.issueQueueInitToken(eventId, userId);
|
|
277
|
+
}
|
|
278
|
+
const protection = await client.getProtection(eventId);
|
|
279
|
+
if (!protection.challengeRequired) {
|
|
280
|
+
return client.issueQueueInitToken(eventId, userId);
|
|
281
|
+
}
|
|
282
|
+
const challenge = await client.getAdmissionChallenge(eventId);
|
|
283
|
+
if (!challenge.required) {
|
|
284
|
+
throw new Error("El evento requiere admisi\xF3n administrada");
|
|
285
|
+
}
|
|
286
|
+
const proof = await acquireManagedAdmissionProof(challenge.publicKey);
|
|
287
|
+
return client.issueQueueInitToken(eventId, userId, proof);
|
|
288
|
+
}
|
|
289
|
+
createQueue(options) {
|
|
290
|
+
return CentralQ.init({
|
|
291
|
+
apiUrl: options.apiUrl ?? this.defaults.apiUrl,
|
|
292
|
+
apiKey: options.apiKey ?? this.defaults.apiKey,
|
|
293
|
+
eventId: options.eventId,
|
|
294
|
+
userId: options.userId ?? this.defaults.userId,
|
|
295
|
+
queueInitToken: options.queueInitToken ?? this.defaults.queueInitToken,
|
|
296
|
+
pollInterval: options.pollInterval ?? this.defaults.pollInterval,
|
|
297
|
+
container: options.container ?? this.defaults.container
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
function createCentralQClient(options) {
|
|
302
|
+
return new CentralQClient({
|
|
303
|
+
...options,
|
|
304
|
+
apiUrl: options.apiUrl ?? CENTRALQ_DEFAULT_API_URL
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export {
|
|
309
|
+
CentralQ,
|
|
310
|
+
CentralQClient,
|
|
311
|
+
createCentralQClient
|
|
312
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CentralQ, a as CentralQClient, b as CentralQClientOptions, c as CentralQCreateOptions, d as CentralQOptions, E as ErrorDetail, e as ExpiredDetail, P as PassedDetail, f as PositionDetail, Q as QueueStatus, g as createCentralQClient } from './centralq-
|
|
1
|
+
export { C as CentralQ, a as CentralQClient, b as CentralQClientOptions, c as CentralQCreateOptions, d as CentralQOptions, E as ErrorDetail, e as ExpiredDetail, P as PassedDetail, f as PositionDetail, Q as QueueStatus, g as createCentralQClient } from './centralq-C3ukDo0x.mjs';
|
|
2
2
|
export { QueueTokenValidationResult, ValidateQueueTokenServerOptions, validateQueueTokenServer } from './server.mjs';
|
|
3
3
|
import * as lit from 'lit';
|
|
4
4
|
import { LitElement } from 'lit';
|
|
@@ -20,6 +20,31 @@ interface QueueInitResponse {
|
|
|
20
20
|
queueInitToken: string;
|
|
21
21
|
expiresAt: number;
|
|
22
22
|
}
|
|
23
|
+
type AdmissionMode = "PUBLIC" | "MANAGED" | "TRUSTED";
|
|
24
|
+
interface QueueProtectionResponse {
|
|
25
|
+
eventId: string;
|
|
26
|
+
configured: boolean;
|
|
27
|
+
protected: boolean;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
admissionMode: AdmissionMode;
|
|
30
|
+
challengeRequired: boolean;
|
|
31
|
+
}
|
|
32
|
+
type AdmissionChallengeResponse = {
|
|
33
|
+
required: false;
|
|
34
|
+
} | {
|
|
35
|
+
required: true;
|
|
36
|
+
publicKey: string;
|
|
37
|
+
appearance: "interaction-only";
|
|
38
|
+
};
|
|
39
|
+
type QueueVerifyResponse = {
|
|
40
|
+
valid: true;
|
|
41
|
+
userId: string;
|
|
42
|
+
eventId: string;
|
|
43
|
+
expiresAt: string;
|
|
44
|
+
} | {
|
|
45
|
+
valid: false;
|
|
46
|
+
reason: string;
|
|
47
|
+
};
|
|
23
48
|
declare const CENTRALQ_DEFAULT_API_URL = "http://localhost:3001";
|
|
24
49
|
/** @internal — HTTP client usado internamente por CentralQ */
|
|
25
50
|
declare class QueueHttpClient {
|
|
@@ -43,7 +68,10 @@ declare class QueueHttpClient {
|
|
|
43
68
|
* Llamar al completar la compra o al salir voluntariamente.
|
|
44
69
|
*/
|
|
45
70
|
leaveQueue(eventId: string, userId: string): Promise<void>;
|
|
46
|
-
issueQueueInitToken(eventId: string, userId?: string): Promise<QueueInitResponse>;
|
|
71
|
+
issueQueueInitToken(eventId: string, userId?: string, admissionProof?: string): Promise<QueueInitResponse>;
|
|
72
|
+
getProtection(eventId: string): Promise<QueueProtectionResponse>;
|
|
73
|
+
getAdmissionChallenge(eventId: string): Promise<AdmissionChallengeResponse>;
|
|
74
|
+
verifyToken(eventId: string, token: string): Promise<QueueVerifyResponse>;
|
|
47
75
|
}
|
|
48
76
|
|
|
49
77
|
/**
|
|
@@ -61,4 +89,4 @@ declare class CentralQElement extends LitElement {
|
|
|
61
89
|
render(): lit.TemplateResult<1>;
|
|
62
90
|
}
|
|
63
91
|
|
|
64
|
-
export { CENTRALQ_DEFAULT_API_URL, CentralQElement, QueueHttpClient, type QueueJoinResponse };
|
|
92
|
+
export { type AdmissionChallengeResponse, type AdmissionMode, CENTRALQ_DEFAULT_API_URL, CentralQElement, QueueHttpClient, type QueueJoinResponse, type QueueProtectionResponse, type QueueVerifyResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CentralQ, a as CentralQClient, b as CentralQClientOptions, c as CentralQCreateOptions, d as CentralQOptions, E as ErrorDetail, e as ExpiredDetail, P as PassedDetail, f as PositionDetail, Q as QueueStatus, g as createCentralQClient } from './centralq-
|
|
1
|
+
export { C as CentralQ, a as CentralQClient, b as CentralQClientOptions, c as CentralQCreateOptions, d as CentralQOptions, E as ErrorDetail, e as ExpiredDetail, P as PassedDetail, f as PositionDetail, Q as QueueStatus, g as createCentralQClient } from './centralq-C3ukDo0x.js';
|
|
2
2
|
export { QueueTokenValidationResult, ValidateQueueTokenServerOptions, validateQueueTokenServer } from './server.js';
|
|
3
3
|
import * as lit from 'lit';
|
|
4
4
|
import { LitElement } from 'lit';
|
|
@@ -20,6 +20,31 @@ interface QueueInitResponse {
|
|
|
20
20
|
queueInitToken: string;
|
|
21
21
|
expiresAt: number;
|
|
22
22
|
}
|
|
23
|
+
type AdmissionMode = "PUBLIC" | "MANAGED" | "TRUSTED";
|
|
24
|
+
interface QueueProtectionResponse {
|
|
25
|
+
eventId: string;
|
|
26
|
+
configured: boolean;
|
|
27
|
+
protected: boolean;
|
|
28
|
+
isActive: boolean;
|
|
29
|
+
admissionMode: AdmissionMode;
|
|
30
|
+
challengeRequired: boolean;
|
|
31
|
+
}
|
|
32
|
+
type AdmissionChallengeResponse = {
|
|
33
|
+
required: false;
|
|
34
|
+
} | {
|
|
35
|
+
required: true;
|
|
36
|
+
publicKey: string;
|
|
37
|
+
appearance: "interaction-only";
|
|
38
|
+
};
|
|
39
|
+
type QueueVerifyResponse = {
|
|
40
|
+
valid: true;
|
|
41
|
+
userId: string;
|
|
42
|
+
eventId: string;
|
|
43
|
+
expiresAt: string;
|
|
44
|
+
} | {
|
|
45
|
+
valid: false;
|
|
46
|
+
reason: string;
|
|
47
|
+
};
|
|
23
48
|
declare const CENTRALQ_DEFAULT_API_URL = "http://localhost:3001";
|
|
24
49
|
/** @internal — HTTP client usado internamente por CentralQ */
|
|
25
50
|
declare class QueueHttpClient {
|
|
@@ -43,7 +68,10 @@ declare class QueueHttpClient {
|
|
|
43
68
|
* Llamar al completar la compra o al salir voluntariamente.
|
|
44
69
|
*/
|
|
45
70
|
leaveQueue(eventId: string, userId: string): Promise<void>;
|
|
46
|
-
issueQueueInitToken(eventId: string, userId?: string): Promise<QueueInitResponse>;
|
|
71
|
+
issueQueueInitToken(eventId: string, userId?: string, admissionProof?: string): Promise<QueueInitResponse>;
|
|
72
|
+
getProtection(eventId: string): Promise<QueueProtectionResponse>;
|
|
73
|
+
getAdmissionChallenge(eventId: string): Promise<AdmissionChallengeResponse>;
|
|
74
|
+
verifyToken(eventId: string, token: string): Promise<QueueVerifyResponse>;
|
|
47
75
|
}
|
|
48
76
|
|
|
49
77
|
/**
|
|
@@ -61,4 +89,4 @@ declare class CentralQElement extends LitElement {
|
|
|
61
89
|
render(): lit.TemplateResult<1>;
|
|
62
90
|
}
|
|
63
91
|
|
|
64
|
-
export { CENTRALQ_DEFAULT_API_URL, CentralQElement, QueueHttpClient, type QueueJoinResponse };
|
|
92
|
+
export { type AdmissionChallengeResponse, type AdmissionMode, CENTRALQ_DEFAULT_API_URL, CentralQElement, QueueHttpClient, type QueueJoinResponse, type QueueProtectionResponse, type QueueVerifyResponse };
|