@sneekin/sdk 1.0.0 → 1.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/dist/index.cjs CHANGED
@@ -24,10 +24,37 @@ __export(src_exports, {
24
24
  SneekApiError: () => SneekApiError,
25
25
  SneekClient: () => SneekClient,
26
26
  SneekPayClient: () => SneekPayClient,
27
- deriveKeys: () => deriveKeys
27
+ deriveKeys: () => deriveKeys,
28
+ isValidApiKey: () => isValidApiKey
28
29
  });
29
30
  module.exports = __toCommonJS(src_exports);
30
31
 
32
+ // src/core/derive-keys.ts
33
+ var import_node_crypto = require("crypto");
34
+ var KEY_LABELS = {
35
+ qrSigningKey: "sneek-qr-v1",
36
+ webhookSigningKey: "sneek-webhook-v1",
37
+ proofKey: "sneek-proof-v1"
38
+ };
39
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
40
+ function isValidApiKey(apiKey) {
41
+ return API_KEY_PATTERN.test(apiKey);
42
+ }
43
+ function deriveKeys(apiKey) {
44
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
45
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
46
+ }
47
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
48
+ const derive = (label) => Buffer.from(
49
+ (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
50
+ );
51
+ return {
52
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
53
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
54
+ proofKey: derive(KEY_LABELS.proofKey)
55
+ };
56
+ }
57
+
31
58
  // src/core/client.ts
32
59
  var SneekApiError = class extends Error {
33
60
  constructor(status, type, title, detail) {
@@ -52,6 +79,7 @@ var SneekClient = class {
52
79
  constructor(options) {
53
80
  if (!options.apiUrl) throw new Error("apiUrl is required");
54
81
  if (!options.apiKey) throw new Error("apiKey is required");
82
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
55
83
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
56
84
  this.apiKey = options.apiKey;
57
85
  this.fetchImpl = options.fetch ?? fetch;
@@ -123,28 +151,6 @@ function asProblem(value) {
123
151
  };
124
152
  }
125
153
 
126
- // src/core/derive-keys.ts
127
- var import_node_crypto = require("crypto");
128
- var KEY_LABELS = {
129
- qrSigningKey: "sneek-qr-v1",
130
- webhookSigningKey: "sneek-webhook-v1",
131
- proofKey: "sneek-proof-v1"
132
- };
133
- function deriveKeys(apiKey) {
134
- if (typeof apiKey !== "string" || apiKey.length === 0) {
135
- throw new TypeError("apiKey must be a nonempty string");
136
- }
137
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
138
- const derive = (label) => Buffer.from(
139
- (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
140
- );
141
- return {
142
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
143
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
144
- proofKey: derive(KEY_LABELS.proofKey)
145
- };
146
- }
147
-
148
154
  // src/pay/payments.ts
149
155
  var SneekPayClient = class {
150
156
  client;
@@ -219,5 +225,6 @@ var OrdersClient = class {
219
225
  SneekApiError,
220
226
  SneekClient,
221
227
  SneekPayClient,
222
- deriveKeys
228
+ deriveKeys,
229
+ isValidApiKey
223
230
  });
package/dist/index.js CHANGED
@@ -1,3 +1,29 @@
1
+ // src/core/derive-keys.ts
2
+ import { hkdfSync } from "crypto";
3
+ var KEY_LABELS = {
4
+ qrSigningKey: "sneek-qr-v1",
5
+ webhookSigningKey: "sneek-webhook-v1",
6
+ proofKey: "sneek-proof-v1"
7
+ };
8
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
9
+ function isValidApiKey(apiKey) {
10
+ return API_KEY_PATTERN.test(apiKey);
11
+ }
12
+ function deriveKeys(apiKey) {
13
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
14
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
15
+ }
16
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
17
+ const derive = (label) => Buffer.from(
18
+ hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
19
+ );
20
+ return {
21
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
22
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
23
+ proofKey: derive(KEY_LABELS.proofKey)
24
+ };
25
+ }
26
+
1
27
  // src/core/client.ts
2
28
  var SneekApiError = class extends Error {
3
29
  constructor(status, type, title, detail) {
@@ -22,6 +48,7 @@ var SneekClient = class {
22
48
  constructor(options) {
23
49
  if (!options.apiUrl) throw new Error("apiUrl is required");
24
50
  if (!options.apiKey) throw new Error("apiKey is required");
51
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
25
52
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
26
53
  this.apiKey = options.apiKey;
27
54
  this.fetchImpl = options.fetch ?? fetch;
@@ -93,28 +120,6 @@ function asProblem(value) {
93
120
  };
94
121
  }
95
122
 
96
- // src/core/derive-keys.ts
97
- import { hkdfSync } from "crypto";
98
- var KEY_LABELS = {
99
- qrSigningKey: "sneek-qr-v1",
100
- webhookSigningKey: "sneek-webhook-v1",
101
- proofKey: "sneek-proof-v1"
102
- };
103
- function deriveKeys(apiKey) {
104
- if (typeof apiKey !== "string" || apiKey.length === 0) {
105
- throw new TypeError("apiKey must be a nonempty string");
106
- }
107
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
108
- const derive = (label) => Buffer.from(
109
- hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
110
- );
111
- return {
112
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
113
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
114
- proofKey: derive(KEY_LABELS.proofKey)
115
- };
116
- }
117
-
118
123
  // src/pay/payments.ts
119
124
  var SneekPayClient = class {
120
125
  client;
@@ -188,5 +193,6 @@ export {
188
193
  SneekApiError,
189
194
  SneekClient,
190
195
  SneekPayClient,
191
- deriveKeys
196
+ deriveKeys,
197
+ isValidApiKey
192
198
  };
@@ -0,0 +1,15 @@
1
+ import type { GetMessageResponse, SendMessage, SendMessageResponse } from '../core/generated/api.js';
2
+ import { SneekApiError, type SneekClientOptions } from '../core/index.js';
3
+ export type SneekMessagesClientOptions = SneekClientOptions;
4
+ export interface SendMessageOptions {
5
+ idempotencyKey?: string;
6
+ }
7
+ /** Typed access to the Sneek message send and delivery-status APIs. */
8
+ export declare class SneekMessagesClient {
9
+ private readonly client;
10
+ constructor(options: SneekMessagesClientOptions);
11
+ send(input: SendMessage, options?: SendMessageOptions): Promise<SendMessageResponse>;
12
+ get(id: string): Promise<GetMessageResponse>;
13
+ }
14
+ export { SneekApiError };
15
+ export default SneekMessagesClient;
@@ -22,10 +22,38 @@ var messages_exports = {};
22
22
  __export(messages_exports, {
23
23
  SneekApiError: () => SneekApiError,
24
24
  SneekClient: () => SneekClient,
25
- deriveKeys: () => deriveKeys
25
+ SneekMessagesClient: () => SneekMessagesClient,
26
+ deriveKeys: () => deriveKeys,
27
+ isValidApiKey: () => isValidApiKey
26
28
  });
27
29
  module.exports = __toCommonJS(messages_exports);
28
30
 
31
+ // src/core/derive-keys.ts
32
+ var import_node_crypto = require("crypto");
33
+ var KEY_LABELS = {
34
+ qrSigningKey: "sneek-qr-v1",
35
+ webhookSigningKey: "sneek-webhook-v1",
36
+ proofKey: "sneek-proof-v1"
37
+ };
38
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
39
+ function isValidApiKey(apiKey) {
40
+ return API_KEY_PATTERN.test(apiKey);
41
+ }
42
+ function deriveKeys(apiKey) {
43
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
44
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
45
+ }
46
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
47
+ const derive = (label) => Buffer.from(
48
+ (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
49
+ );
50
+ return {
51
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
52
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
53
+ proofKey: derive(KEY_LABELS.proofKey)
54
+ };
55
+ }
56
+
29
57
  // src/core/client.ts
30
58
  var SneekApiError = class extends Error {
31
59
  constructor(status, type, title, detail) {
@@ -50,6 +78,7 @@ var SneekClient = class {
50
78
  constructor(options) {
51
79
  if (!options.apiUrl) throw new Error("apiUrl is required");
52
80
  if (!options.apiKey) throw new Error("apiKey is required");
81
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
53
82
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
54
83
  this.apiKey = options.apiKey;
55
84
  this.fetchImpl = options.fetch ?? fetch;
@@ -121,30 +150,28 @@ function asProblem(value) {
121
150
  };
122
151
  }
123
152
 
124
- // src/core/derive-keys.ts
125
- var import_node_crypto = require("crypto");
126
- var KEY_LABELS = {
127
- qrSigningKey: "sneek-qr-v1",
128
- webhookSigningKey: "sneek-webhook-v1",
129
- proofKey: "sneek-proof-v1"
130
- };
131
- function deriveKeys(apiKey) {
132
- if (typeof apiKey !== "string" || apiKey.length === 0) {
133
- throw new TypeError("apiKey must be a nonempty string");
153
+ // src/messages/client.ts
154
+ var SneekMessagesClient = class {
155
+ client;
156
+ constructor(options) {
157
+ this.client = new SneekClient(options);
134
158
  }
135
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
136
- const derive = (label) => Buffer.from(
137
- (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
138
- );
139
- return {
140
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
141
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
142
- proofKey: derive(KEY_LABELS.proofKey)
143
- };
144
- }
159
+ send(input, options = {}) {
160
+ const headers = options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : void 0;
161
+ return this.client.request("POST", "/api/messages/send", input, headers);
162
+ }
163
+ get(id) {
164
+ return this.client.request(
165
+ "GET",
166
+ `/api/messages/${encodeURIComponent(id)}`
167
+ );
168
+ }
169
+ };
145
170
  // Annotate the CommonJS export names for ESM import in node:
146
171
  0 && (module.exports = {
147
172
  SneekApiError,
148
173
  SneekClient,
149
- deriveKeys
174
+ SneekMessagesClient,
175
+ deriveKeys,
176
+ isValidApiKey
150
177
  });
@@ -1 +1,2 @@
1
1
  export * from '../core/index.js';
2
+ export * from './client.js';
@@ -1,3 +1,29 @@
1
+ // src/core/derive-keys.ts
2
+ import { hkdfSync } from "crypto";
3
+ var KEY_LABELS = {
4
+ qrSigningKey: "sneek-qr-v1",
5
+ webhookSigningKey: "sneek-webhook-v1",
6
+ proofKey: "sneek-proof-v1"
7
+ };
8
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
9
+ function isValidApiKey(apiKey) {
10
+ return API_KEY_PATTERN.test(apiKey);
11
+ }
12
+ function deriveKeys(apiKey) {
13
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
14
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
15
+ }
16
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
17
+ const derive = (label) => Buffer.from(
18
+ hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
19
+ );
20
+ return {
21
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
22
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
23
+ proofKey: derive(KEY_LABELS.proofKey)
24
+ };
25
+ }
26
+
1
27
  // src/core/client.ts
2
28
  var SneekApiError = class extends Error {
3
29
  constructor(status, type, title, detail) {
@@ -22,6 +48,7 @@ var SneekClient = class {
22
48
  constructor(options) {
23
49
  if (!options.apiUrl) throw new Error("apiUrl is required");
24
50
  if (!options.apiKey) throw new Error("apiKey is required");
51
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
25
52
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
26
53
  this.apiKey = options.apiKey;
27
54
  this.fetchImpl = options.fetch ?? fetch;
@@ -93,29 +120,27 @@ function asProblem(value) {
93
120
  };
94
121
  }
95
122
 
96
- // src/core/derive-keys.ts
97
- import { hkdfSync } from "crypto";
98
- var KEY_LABELS = {
99
- qrSigningKey: "sneek-qr-v1",
100
- webhookSigningKey: "sneek-webhook-v1",
101
- proofKey: "sneek-proof-v1"
102
- };
103
- function deriveKeys(apiKey) {
104
- if (typeof apiKey !== "string" || apiKey.length === 0) {
105
- throw new TypeError("apiKey must be a nonempty string");
123
+ // src/messages/client.ts
124
+ var SneekMessagesClient = class {
125
+ client;
126
+ constructor(options) {
127
+ this.client = new SneekClient(options);
106
128
  }
107
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
108
- const derive = (label) => Buffer.from(
109
- hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
110
- );
111
- return {
112
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
113
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
114
- proofKey: derive(KEY_LABELS.proofKey)
115
- };
116
- }
129
+ send(input, options = {}) {
130
+ const headers = options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : void 0;
131
+ return this.client.request("POST", "/api/messages/send", input, headers);
132
+ }
133
+ get(id) {
134
+ return this.client.request(
135
+ "GET",
136
+ `/api/messages/${encodeURIComponent(id)}`
137
+ );
138
+ }
139
+ };
117
140
  export {
118
141
  SneekApiError,
119
142
  SneekClient,
120
- deriveKeys
143
+ SneekMessagesClient,
144
+ deriveKeys,
145
+ isValidApiKey
121
146
  };
@@ -24,10 +24,37 @@ __export(pay_exports, {
24
24
  SneekApiError: () => SneekApiError,
25
25
  SneekClient: () => SneekClient,
26
26
  SneekPayClient: () => SneekPayClient,
27
- deriveKeys: () => deriveKeys
27
+ deriveKeys: () => deriveKeys,
28
+ isValidApiKey: () => isValidApiKey
28
29
  });
29
30
  module.exports = __toCommonJS(pay_exports);
30
31
 
32
+ // src/core/derive-keys.ts
33
+ var import_node_crypto = require("crypto");
34
+ var KEY_LABELS = {
35
+ qrSigningKey: "sneek-qr-v1",
36
+ webhookSigningKey: "sneek-webhook-v1",
37
+ proofKey: "sneek-proof-v1"
38
+ };
39
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
40
+ function isValidApiKey(apiKey) {
41
+ return API_KEY_PATTERN.test(apiKey);
42
+ }
43
+ function deriveKeys(apiKey) {
44
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
45
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
46
+ }
47
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
48
+ const derive = (label) => Buffer.from(
49
+ (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
50
+ );
51
+ return {
52
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
53
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
54
+ proofKey: derive(KEY_LABELS.proofKey)
55
+ };
56
+ }
57
+
31
58
  // src/core/client.ts
32
59
  var SneekApiError = class extends Error {
33
60
  constructor(status, type, title, detail) {
@@ -52,6 +79,7 @@ var SneekClient = class {
52
79
  constructor(options) {
53
80
  if (!options.apiUrl) throw new Error("apiUrl is required");
54
81
  if (!options.apiKey) throw new Error("apiKey is required");
82
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
55
83
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
56
84
  this.apiKey = options.apiKey;
57
85
  this.fetchImpl = options.fetch ?? fetch;
@@ -123,28 +151,6 @@ function asProblem(value) {
123
151
  };
124
152
  }
125
153
 
126
- // src/core/derive-keys.ts
127
- var import_node_crypto = require("crypto");
128
- var KEY_LABELS = {
129
- qrSigningKey: "sneek-qr-v1",
130
- webhookSigningKey: "sneek-webhook-v1",
131
- proofKey: "sneek-proof-v1"
132
- };
133
- function deriveKeys(apiKey) {
134
- if (typeof apiKey !== "string" || apiKey.length === 0) {
135
- throw new TypeError("apiKey must be a nonempty string");
136
- }
137
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
138
- const derive = (label) => Buffer.from(
139
- (0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
140
- );
141
- return {
142
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
143
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
144
- proofKey: derive(KEY_LABELS.proofKey)
145
- };
146
- }
147
-
148
154
  // src/pay/payments.ts
149
155
  var SneekPayClient = class {
150
156
  client;
@@ -219,5 +225,6 @@ var OrdersClient = class {
219
225
  SneekApiError,
220
226
  SneekClient,
221
227
  SneekPayClient,
222
- deriveKeys
228
+ deriveKeys,
229
+ isValidApiKey
223
230
  });
package/dist/pay/index.js CHANGED
@@ -1,3 +1,29 @@
1
+ // src/core/derive-keys.ts
2
+ import { hkdfSync } from "crypto";
3
+ var KEY_LABELS = {
4
+ qrSigningKey: "sneek-qr-v1",
5
+ webhookSigningKey: "sneek-webhook-v1",
6
+ proofKey: "sneek-proof-v1"
7
+ };
8
+ var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
9
+ function isValidApiKey(apiKey) {
10
+ return API_KEY_PATTERN.test(apiKey);
11
+ }
12
+ function deriveKeys(apiKey) {
13
+ if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
14
+ throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
15
+ }
16
+ const inputKeyMaterial = Buffer.from(apiKey, "utf8");
17
+ const derive = (label) => Buffer.from(
18
+ hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
19
+ );
20
+ return {
21
+ qrSigningKey: derive(KEY_LABELS.qrSigningKey),
22
+ webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
23
+ proofKey: derive(KEY_LABELS.proofKey)
24
+ };
25
+ }
26
+
1
27
  // src/core/client.ts
2
28
  var SneekApiError = class extends Error {
3
29
  constructor(status, type, title, detail) {
@@ -22,6 +48,7 @@ var SneekClient = class {
22
48
  constructor(options) {
23
49
  if (!options.apiUrl) throw new Error("apiUrl is required");
24
50
  if (!options.apiKey) throw new Error("apiKey is required");
51
+ if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
25
52
  this.apiUrl = options.apiUrl.replace(/\/+$/, "");
26
53
  this.apiKey = options.apiKey;
27
54
  this.fetchImpl = options.fetch ?? fetch;
@@ -93,28 +120,6 @@ function asProblem(value) {
93
120
  };
94
121
  }
95
122
 
96
- // src/core/derive-keys.ts
97
- import { hkdfSync } from "crypto";
98
- var KEY_LABELS = {
99
- qrSigningKey: "sneek-qr-v1",
100
- webhookSigningKey: "sneek-webhook-v1",
101
- proofKey: "sneek-proof-v1"
102
- };
103
- function deriveKeys(apiKey) {
104
- if (typeof apiKey !== "string" || apiKey.length === 0) {
105
- throw new TypeError("apiKey must be a nonempty string");
106
- }
107
- const inputKeyMaterial = Buffer.from(apiKey, "utf8");
108
- const derive = (label) => Buffer.from(
109
- hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
110
- );
111
- return {
112
- qrSigningKey: derive(KEY_LABELS.qrSigningKey),
113
- webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
114
- proofKey: derive(KEY_LABELS.proofKey)
115
- };
116
- }
117
-
118
123
  // src/pay/payments.ts
119
124
  var SneekPayClient = class {
120
125
  client;
@@ -188,5 +193,6 @@ export {
188
193
  SneekApiError,
189
194
  SneekClient,
190
195
  SneekPayClient,
191
- deriveKeys
196
+ deriveKeys,
197
+ isValidApiKey
192
198
  };
@@ -0,0 +1,22 @@
1
+ export interface SneekQrSession {
2
+ ref: string;
3
+ applicationId: string;
4
+ origin: string;
5
+ bindingProofHash: string;
6
+ expiresAt: number;
7
+ requestId?: string;
8
+ }
9
+ export interface SneekQrApprovalEvent {
10
+ type: 'qr.approved';
11
+ applicationId: string;
12
+ ref: string;
13
+ requestId: string;
14
+ }
15
+ export interface SneekApprovalStore {
16
+ createQrSession(session: SneekQrSession): Promise<void>;
17
+ /** Atomically attach only the first matching approval to a live QR session. */
18
+ recordQrApproval(event: SneekQrApprovalEvent, now: number): Promise<'recorded' | 'duplicate' | 'missing'>;
19
+ readQrSession(ref: string): Promise<SneekQrSession | null>;
20
+ /** Atomically claim a token jti until its exp time; false means replay. */
21
+ claimJti(jti: string, expiresAt: number): Promise<boolean>;
22
+ }
@@ -0,0 +1,97 @@
1
+ import { z } from 'zod';
2
+ export declare const QrWebhookEventSchema: z.ZodObject<{
3
+ type: z.ZodLiteral<"qr.approved">;
4
+ applicationId: z.ZodString;
5
+ ref: z.ZodString;
6
+ requestId: z.ZodString;
7
+ }, "strict", z.ZodTypeAny, {
8
+ type: "qr.approved";
9
+ requestId: string;
10
+ ref: string;
11
+ applicationId: string;
12
+ }, {
13
+ type: "qr.approved";
14
+ requestId: string;
15
+ ref: string;
16
+ applicationId: string;
17
+ }>;
18
+ export declare const SneekVerifyActionSchema: z.ZodUnion<[z.ZodObject<{
19
+ action: z.ZodLiteral<"config">;
20
+ }, "strict", z.ZodTypeAny, {
21
+ action: "config";
22
+ }, {
23
+ action: "config";
24
+ }>, z.ZodObject<{
25
+ action: z.ZodLiteral<"request">;
26
+ identifier: z.ZodString;
27
+ }, "strict", z.ZodTypeAny, {
28
+ action: "request";
29
+ identifier: string;
30
+ }, {
31
+ action: "request";
32
+ identifier: string;
33
+ }>, z.ZodObject<{
34
+ action: z.ZodLiteral<"switch">;
35
+ requestId: z.ZodString;
36
+ channel: z.ZodEnum<["sms", "whatsapp", "email", "push"]>;
37
+ proof: z.ZodString;
38
+ }, "strict", z.ZodTypeAny, {
39
+ action: "switch";
40
+ requestId: string;
41
+ channel: "sms" | "whatsapp" | "email" | "push";
42
+ proof: string;
43
+ }, {
44
+ action: "switch";
45
+ requestId: string;
46
+ channel: "sms" | "whatsapp" | "email" | "push";
47
+ proof: string;
48
+ }>, z.ZodObject<{
49
+ action: z.ZodLiteral<"verify">;
50
+ requestId: z.ZodString;
51
+ code: z.ZodOptional<z.ZodString>;
52
+ proof: z.ZodString;
53
+ }, "strict", z.ZodTypeAny, {
54
+ action: "verify";
55
+ requestId: string;
56
+ proof: string;
57
+ code?: string | undefined;
58
+ }, {
59
+ action: "verify";
60
+ requestId: string;
61
+ proof: string;
62
+ code?: string | undefined;
63
+ }>, z.ZodObject<{
64
+ action: z.ZodLiteral<"verify">;
65
+ requestId: z.ZodString;
66
+ ref: z.ZodString;
67
+ bindingProof: z.ZodString;
68
+ }, "strict", z.ZodTypeAny, {
69
+ action: "verify";
70
+ requestId: string;
71
+ ref: string;
72
+ bindingProof: string;
73
+ }, {
74
+ action: "verify";
75
+ requestId: string;
76
+ ref: string;
77
+ bindingProof: string;
78
+ }>, z.ZodObject<{
79
+ action: z.ZodLiteral<"create">;
80
+ }, "strict", z.ZodTypeAny, {
81
+ action: "create";
82
+ }, {
83
+ action: "create";
84
+ }>, z.ZodObject<{
85
+ action: z.ZodLiteral<"status">;
86
+ ref: z.ZodString;
87
+ bindingProof: z.ZodString;
88
+ }, "strict", z.ZodTypeAny, {
89
+ action: "status";
90
+ ref: string;
91
+ bindingProof: string;
92
+ }, {
93
+ action: "status";
94
+ ref: string;
95
+ bindingProof: string;
96
+ }>]>;
97
+ export type SneekVerifyAction = z.infer<typeof SneekVerifyActionSchema>;
@@ -0,0 +1,41 @@
1
+ import type { SneekApprovalStore } from './approval-store.js';
2
+ export interface SneekVerifyHandlerOptions {
3
+ apiUrl: string;
4
+ apiKey: string;
5
+ allowedOrigins: string[];
6
+ approvalStore: SneekApprovalStore;
7
+ onVerified: (result: {
8
+ identifier: string;
9
+ kind: 'email' | 'mobile';
10
+ method: string;
11
+ verifiedAt: string;
12
+ requestId: string;
13
+ }) => void | Promise<void>;
14
+ fetch?: typeof fetch;
15
+ }
16
+ export declare class SneekVerifyHandler {
17
+ private readonly client;
18
+ private readonly allowedOrigins;
19
+ private readonly keys;
20
+ private readonly approvalStore;
21
+ private readonly onVerified;
22
+ private readonly jwksByIssuer;
23
+ constructor(options: SneekVerifyHandlerOptions);
24
+ handle(request: Request): Promise<Response>;
25
+ handleWebhook(request: Request): Promise<Response>;
26
+ private getAllowedOrigin;
27
+ private config;
28
+ private startVerification;
29
+ private switchVerification;
30
+ private verify;
31
+ private verifiedClaims;
32
+ private startResponse;
33
+ private createProof;
34
+ private isValidProof;
35
+ private createQr;
36
+ private qrStatus;
37
+ private qrSession;
38
+ private partnerConfig;
39
+ private isValidWebhookSignature;
40
+ private hash;
41
+ }