@freeappstore/sdk 0.1.2 → 0.2.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/LICENSE +21 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +40 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +62 -0
- package/dist/proxy.js.map +1 -0
- package/dist/proxy.test.d.ts +2 -0
- package/dist/proxy.test.d.ts.map +1 -0
- package/dist/proxy.test.js +77 -0
- package/dist/proxy.test.js.map +1 -0
- package/dist/rooms.test.d.ts +2 -0
- package/dist/rooms.test.d.ts.map +1 -0
- package/dist/rooms.test.js +256 -0
- package/dist/rooms.test.js.map +1 -0
- package/package.json +14 -12
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FreeAppStore
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Auth } from './auth.js';
|
|
2
2
|
import { Kv } from './kv.js';
|
|
3
3
|
import { Rooms } from './rooms.js';
|
|
4
|
+
import { Proxy } from './proxy.js';
|
|
4
5
|
import type { FasInitOptions } from './types.js';
|
|
5
6
|
export type { User, FasInitOptions, Unsubscribe } from './types.js';
|
|
6
7
|
export type { Room, RoomMessage, RoomPeer, ConnectionState } from './rooms.js';
|
|
@@ -8,6 +9,7 @@ export declare class FreeAppStore {
|
|
|
8
9
|
readonly auth: Auth;
|
|
9
10
|
readonly kv: Kv;
|
|
10
11
|
readonly rooms: Rooms;
|
|
12
|
+
readonly proxy: Proxy;
|
|
11
13
|
constructor(opts: FasInitOptions);
|
|
12
14
|
}
|
|
13
15
|
export declare function initApp(opts: FasInitOptions): FreeAppStore;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACpE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/E,qBAAa,YAAY;IACvB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;gBAEV,IAAI,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACpE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/E,qBAAa,YAAY;IACvB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;gBAEV,IAAI,EAAE,cAAc;CAOjC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,YAAY,CAE1D"}
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Auth } from './auth.js';
|
|
2
2
|
import { Kv } from './kv.js';
|
|
3
3
|
import { Rooms } from './rooms.js';
|
|
4
|
+
import { Proxy } from './proxy.js';
|
|
4
5
|
export class FreeAppStore {
|
|
5
6
|
auth;
|
|
6
7
|
kv;
|
|
7
8
|
rooms;
|
|
9
|
+
proxy;
|
|
8
10
|
constructor(opts) {
|
|
9
11
|
const apiBase = opts.apiBase ?? 'https://api.freeappstore.online';
|
|
10
12
|
this.auth = new Auth(opts.appId, apiBase);
|
|
11
13
|
this.kv = new Kv(opts.appId, apiBase, this.auth);
|
|
12
14
|
this.rooms = new Rooms(opts.appId, apiBase, this.auth);
|
|
15
|
+
this.proxy = new Proxy(opts.appId, apiBase, this.auth);
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
export function initApp(opts) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMnC,MAAM,OAAO,YAAY;IACd,IAAI,CAAO;IACX,EAAE,CAAK;IACP,KAAK,CAAQ;IAEtB,YAAY,IAAoB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,iCAAiC,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,UAAU,OAAO,CAAC,IAAoB;IAC1C,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMnC,MAAM,OAAO,YAAY;IACd,IAAI,CAAO;IACX,EAAE,CAAK;IACP,KAAK,CAAQ;IACb,KAAK,CAAQ;IAEtB,YAAY,IAAoB;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,iCAAiC,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,UAAU,OAAO,CAAC,IAAoB;IAC1C,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Auth } from './auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Browser-side wrapper around the platform's per-app secret-injecting proxy.
|
|
4
|
+
*
|
|
5
|
+
* Pattern:
|
|
6
|
+
* const fas = initApp({ appId: 'weather' });
|
|
7
|
+
* const res = await fas.proxy.fetch(
|
|
8
|
+
* 'api.openweathermap.org/data/2.5/weather?q=London',
|
|
9
|
+
* );
|
|
10
|
+
*
|
|
11
|
+
* The first segment is the upstream host; the rest is path + query. The
|
|
12
|
+
* platform Worker authenticates the call with the user's session token,
|
|
13
|
+
* matches the URL against the app's allowlist, decrypts the developer's
|
|
14
|
+
* stored API key, and forwards the request server-side.
|
|
15
|
+
*
|
|
16
|
+
* The developer's secret never touches the browser.
|
|
17
|
+
*/
|
|
18
|
+
export declare class Proxy {
|
|
19
|
+
private readonly appId;
|
|
20
|
+
private readonly apiBase;
|
|
21
|
+
private readonly auth;
|
|
22
|
+
constructor(appId: string, apiBase: string, auth: Auth);
|
|
23
|
+
/**
|
|
24
|
+
* Fetch via the proxy. Accepts either:
|
|
25
|
+
* - "host/path?query" (preferred, matches the SDK's CLI register form)
|
|
26
|
+
* - a full "https://host/path?query" URL (we strip the scheme)
|
|
27
|
+
*/
|
|
28
|
+
fetch(target: string, init?: RequestInit): Promise<Response>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Strip a leading scheme (`https://`, `http://`) so callers can paste either
|
|
32
|
+
* form and get the same result. Throws on schemes other than http(s) — the
|
|
33
|
+
* proxy only ever forwards over https upstream and we want a loud error
|
|
34
|
+
* rather than a silent rewrite.
|
|
35
|
+
*
|
|
36
|
+
* Scheme detection is case-insensitive: `HTTPS://api.example.com/x` should
|
|
37
|
+
* normalize the same as `https://api.example.com/x`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeTarget(target: string): string;
|
|
40
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,KAAK;IAEd,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAFJ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI;IAG7B;;;;OAIG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CASnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWtD"}
|
package/dist/proxy.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-side wrapper around the platform's per-app secret-injecting proxy.
|
|
3
|
+
*
|
|
4
|
+
* Pattern:
|
|
5
|
+
* const fas = initApp({ appId: 'weather' });
|
|
6
|
+
* const res = await fas.proxy.fetch(
|
|
7
|
+
* 'api.openweathermap.org/data/2.5/weather?q=London',
|
|
8
|
+
* );
|
|
9
|
+
*
|
|
10
|
+
* The first segment is the upstream host; the rest is path + query. The
|
|
11
|
+
* platform Worker authenticates the call with the user's session token,
|
|
12
|
+
* matches the URL against the app's allowlist, decrypts the developer's
|
|
13
|
+
* stored API key, and forwards the request server-side.
|
|
14
|
+
*
|
|
15
|
+
* The developer's secret never touches the browser.
|
|
16
|
+
*/
|
|
17
|
+
export class Proxy {
|
|
18
|
+
appId;
|
|
19
|
+
apiBase;
|
|
20
|
+
auth;
|
|
21
|
+
constructor(appId, apiBase, auth) {
|
|
22
|
+
this.appId = appId;
|
|
23
|
+
this.apiBase = apiBase;
|
|
24
|
+
this.auth = auth;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fetch via the proxy. Accepts either:
|
|
28
|
+
* - "host/path?query" (preferred, matches the SDK's CLI register form)
|
|
29
|
+
* - a full "https://host/path?query" URL (we strip the scheme)
|
|
30
|
+
*/
|
|
31
|
+
async fetch(target, init) {
|
|
32
|
+
if (!this.auth.token) {
|
|
33
|
+
throw new Error('proxy.fetch: not signed in. Call fas.auth.login() first.');
|
|
34
|
+
}
|
|
35
|
+
const url = `${this.apiBase}/v1/apps/${this.appId}/proxy/${normalizeTarget(target)}`;
|
|
36
|
+
const headers = new Headers(init?.headers);
|
|
37
|
+
headers.set('Authorization', `Bearer ${this.auth.token}`);
|
|
38
|
+
return fetch(url, { ...init, headers });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Strip a leading scheme (`https://`, `http://`) so callers can paste either
|
|
43
|
+
* form and get the same result. Throws on schemes other than http(s) — the
|
|
44
|
+
* proxy only ever forwards over https upstream and we want a loud error
|
|
45
|
+
* rather than a silent rewrite.
|
|
46
|
+
*
|
|
47
|
+
* Scheme detection is case-insensitive: `HTTPS://api.example.com/x` should
|
|
48
|
+
* normalize the same as `https://api.example.com/x`.
|
|
49
|
+
*/
|
|
50
|
+
export function normalizeTarget(target) {
|
|
51
|
+
const schemeMatch = /^([a-z][a-z0-9+.-]*):\/\//i.exec(target);
|
|
52
|
+
if (schemeMatch) {
|
|
53
|
+
const scheme = schemeMatch[1].toLowerCase();
|
|
54
|
+
if (scheme === 'http' || scheme === 'https') {
|
|
55
|
+
return target.slice(schemeMatch[0].length);
|
|
56
|
+
}
|
|
57
|
+
throw new Error('proxy.fetch: only http(s) targets are supported');
|
|
58
|
+
}
|
|
59
|
+
// Already in "host/path" form.
|
|
60
|
+
return target.replace(/^\/+/, '');
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,KAAK;IAEG;IACA;IACA;IAHnB,YACmB,KAAa,EACb,OAAe,EACf,IAAU;QAFV,UAAK,GAAL,KAAK,CAAQ;QACb,YAAO,GAAP,OAAO,CAAQ;QACf,SAAI,GAAJ,IAAI,CAAM;IAC1B,CAAC;IAEJ;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,MAAc,EAAE,IAAkB;QAC5C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,YAAY,IAAI,CAAC,KAAK,UAAU,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QACrF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1D,OAAO,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1C,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,WAAW,GAAG,4BAA4B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9D,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;QAC7C,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YAC5C,OAAO,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IACD,+BAA+B;IAC/B,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.test.d.ts","sourceRoot":"","sources":["../src/proxy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { Proxy, normalizeTarget } from './proxy.js';
|
|
3
|
+
describe('normalizeTarget', () => {
|
|
4
|
+
it('passes through bare host/path form', () => {
|
|
5
|
+
expect(normalizeTarget('api.example.com/v1/x')).toBe('api.example.com/v1/x');
|
|
6
|
+
});
|
|
7
|
+
it('strips https:// and http:// prefixes', () => {
|
|
8
|
+
expect(normalizeTarget('https://api.example.com/v1/x')).toBe('api.example.com/v1/x');
|
|
9
|
+
expect(normalizeTarget('http://api.example.com/v1/x')).toBe('api.example.com/v1/x');
|
|
10
|
+
});
|
|
11
|
+
it('matches the scheme case-insensitively', () => {
|
|
12
|
+
expect(normalizeTarget('HTTPS://api.example.com/v1/x')).toBe('api.example.com/v1/x');
|
|
13
|
+
expect(normalizeTarget('Http://api.example.com/v1/x')).toBe('api.example.com/v1/x');
|
|
14
|
+
});
|
|
15
|
+
it('strips leading slashes from bare form', () => {
|
|
16
|
+
expect(normalizeTarget('//api.example.com/v1')).toBe('api.example.com/v1');
|
|
17
|
+
});
|
|
18
|
+
it('preserves query strings', () => {
|
|
19
|
+
expect(normalizeTarget('api.example.com/x?a=1&b=2')).toBe('api.example.com/x?a=1&b=2');
|
|
20
|
+
});
|
|
21
|
+
it('rejects non-http(s) schemes', () => {
|
|
22
|
+
expect(() => normalizeTarget('ftp://api.example.com/x')).toThrow(/http\(s\)/);
|
|
23
|
+
expect(() => normalizeTarget('javascript://x')).toThrow(/http\(s\)/);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe('Proxy.fetch', () => {
|
|
27
|
+
it('throws when not signed in', async () => {
|
|
28
|
+
const auth = { token: null };
|
|
29
|
+
const proxy = new Proxy('weather', 'https://api.example.com', auth);
|
|
30
|
+
await expect(proxy.fetch('api.openweathermap.org/data/2.5/weather')).rejects.toThrow(/not signed in/);
|
|
31
|
+
});
|
|
32
|
+
it('builds the right URL and forwards Bearer auth', async () => {
|
|
33
|
+
const auth = { token: 'tok-123' };
|
|
34
|
+
const proxy = new Proxy('weather', 'https://api.example.com', auth);
|
|
35
|
+
const captured = {};
|
|
36
|
+
const origFetch = globalThis.fetch;
|
|
37
|
+
globalThis.fetch = vi.fn(async (url, init) => {
|
|
38
|
+
captured.url = String(url);
|
|
39
|
+
captured.init = init;
|
|
40
|
+
return new Response('ok');
|
|
41
|
+
});
|
|
42
|
+
try {
|
|
43
|
+
await proxy.fetch('api.openweathermap.org/data/2.5/weather?q=London');
|
|
44
|
+
expect(captured.url).toBe('https://api.example.com/v1/apps/weather/proxy/api.openweathermap.org/data/2.5/weather?q=London');
|
|
45
|
+
const h = new Headers(captured.init?.headers);
|
|
46
|
+
expect(h.get('authorization')).toBe('Bearer tok-123');
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
globalThis.fetch = origFetch;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
it('preserves caller-supplied headers and method', async () => {
|
|
53
|
+
const auth = { token: 'tok' };
|
|
54
|
+
const proxy = new Proxy('weather', 'https://api.example.com', auth);
|
|
55
|
+
const captured = {};
|
|
56
|
+
const origFetch = globalThis.fetch;
|
|
57
|
+
globalThis.fetch = vi.fn(async (_url, init) => {
|
|
58
|
+
captured.init = init;
|
|
59
|
+
return new Response('ok');
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
await proxy.fetch('api.example.com/v1/x', {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: { 'Content-Type': 'application/json' },
|
|
65
|
+
body: '{}',
|
|
66
|
+
});
|
|
67
|
+
expect(captured.init?.method).toBe('POST');
|
|
68
|
+
const h = new Headers(captured.init?.headers);
|
|
69
|
+
expect(h.get('content-type')).toBe('application/json');
|
|
70
|
+
expect(h.get('authorization')).toBe('Bearer tok');
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
globalThis.fetch = origFetch;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=proxy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.test.js","sourceRoot":"","sources":["../src/proxy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rooms.test.d.ts","sourceRoot":"","sources":["../src/rooms.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { Rooms } from './rooms.js';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal WebSocket stand-in. Tests poke at `created[i]` to drive open/
|
|
5
|
+
* message/error/close events imperatively.
|
|
6
|
+
*/
|
|
7
|
+
class FakeWebSocket {
|
|
8
|
+
static CONNECTING = 0;
|
|
9
|
+
static OPEN = 1;
|
|
10
|
+
static CLOSING = 2;
|
|
11
|
+
static CLOSED = 3;
|
|
12
|
+
readyState = FakeWebSocket.CONNECTING;
|
|
13
|
+
sent = [];
|
|
14
|
+
url;
|
|
15
|
+
listeners = new Map();
|
|
16
|
+
constructor(url) {
|
|
17
|
+
this.url = url.toString();
|
|
18
|
+
created.push(this);
|
|
19
|
+
}
|
|
20
|
+
addEventListener(type, fn) {
|
|
21
|
+
if (!this.listeners.has(type))
|
|
22
|
+
this.listeners.set(type, new Set());
|
|
23
|
+
this.listeners.get(type).add(fn);
|
|
24
|
+
}
|
|
25
|
+
send(data) {
|
|
26
|
+
this.sent.push(data);
|
|
27
|
+
}
|
|
28
|
+
close() {
|
|
29
|
+
if (this.readyState !== FakeWebSocket.CLOSED) {
|
|
30
|
+
this.readyState = FakeWebSocket.CLOSED;
|
|
31
|
+
this.fire('close', {});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
triggerOpen() {
|
|
35
|
+
this.readyState = FakeWebSocket.OPEN;
|
|
36
|
+
this.fire('open', {});
|
|
37
|
+
}
|
|
38
|
+
triggerMessage(data) {
|
|
39
|
+
this.fire('message', { data });
|
|
40
|
+
}
|
|
41
|
+
triggerError() {
|
|
42
|
+
this.fire('error', {});
|
|
43
|
+
}
|
|
44
|
+
triggerClose() {
|
|
45
|
+
this.readyState = FakeWebSocket.CLOSED;
|
|
46
|
+
this.fire('close', {});
|
|
47
|
+
}
|
|
48
|
+
fire(type, ev) {
|
|
49
|
+
this.listeners.get(type)?.forEach((fn) => fn(ev));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let created = [];
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
created = [];
|
|
55
|
+
globalThis['WebSocket'] = FakeWebSocket;
|
|
56
|
+
});
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
delete globalThis['WebSocket'];
|
|
59
|
+
vi.useRealTimers();
|
|
60
|
+
});
|
|
61
|
+
function fakeAuth(token) {
|
|
62
|
+
return { token };
|
|
63
|
+
}
|
|
64
|
+
function newRoom(token = 'tok') {
|
|
65
|
+
const rooms = new Rooms('demo', 'https://api.example', fakeAuth(token));
|
|
66
|
+
return rooms.join('lobby');
|
|
67
|
+
}
|
|
68
|
+
describe('Room.connect — initial state', () => {
|
|
69
|
+
it('starts in connecting state and creates a WebSocket immediately', () => {
|
|
70
|
+
const room = newRoom();
|
|
71
|
+
expect(created).toHaveLength(1);
|
|
72
|
+
expect(room.state).toBe('connecting');
|
|
73
|
+
expect(created[0].url).toMatch(/wss:\/\/api\.example\/v1\/apps\/demo\/rooms\/lobby/);
|
|
74
|
+
expect(created[0].url).toContain('token=tok');
|
|
75
|
+
});
|
|
76
|
+
it('encodes appId and roomId in the URL path', () => {
|
|
77
|
+
const rooms = new Rooms('app%name', 'https://api.example', fakeAuth('tok'));
|
|
78
|
+
rooms.join('room/with/slashes');
|
|
79
|
+
expect(created[0].url).toContain('/v1/apps/app%25name/rooms/room%2Fwith%2Fslashes');
|
|
80
|
+
});
|
|
81
|
+
it('with no auth token, sets state to closed and does NOT open a socket', () => {
|
|
82
|
+
const room = newRoom(null);
|
|
83
|
+
expect(created).toHaveLength(0);
|
|
84
|
+
expect(room.state).toBe('closed');
|
|
85
|
+
});
|
|
86
|
+
it('flips to open state when the socket opens', () => {
|
|
87
|
+
const room = newRoom();
|
|
88
|
+
created[0].triggerOpen();
|
|
89
|
+
expect(room.state).toBe('open');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('Room.onConnectionState', () => {
|
|
93
|
+
it('fires immediately with current state on subscribe', () => {
|
|
94
|
+
const room = newRoom();
|
|
95
|
+
const seen = [];
|
|
96
|
+
room.onConnectionState((s) => seen.push(s));
|
|
97
|
+
expect(seen).toEqual(['connecting']);
|
|
98
|
+
});
|
|
99
|
+
it('fires on every state transition', () => {
|
|
100
|
+
const room = newRoom();
|
|
101
|
+
const seen = [];
|
|
102
|
+
room.onConnectionState((s) => seen.push(s));
|
|
103
|
+
created[0].triggerOpen();
|
|
104
|
+
expect(seen).toEqual(['connecting', 'open']);
|
|
105
|
+
});
|
|
106
|
+
it('does not fire when state is set to the same value', () => {
|
|
107
|
+
const room = newRoom();
|
|
108
|
+
const seen = [];
|
|
109
|
+
room.onConnectionState((s) => seen.push(s));
|
|
110
|
+
// Trigger open twice — should only see one open transition.
|
|
111
|
+
created[0].triggerOpen();
|
|
112
|
+
created[0].triggerOpen();
|
|
113
|
+
expect(seen.filter((s) => s === 'open')).toHaveLength(1);
|
|
114
|
+
});
|
|
115
|
+
it('returns an unsubscribe function', () => {
|
|
116
|
+
const room = newRoom();
|
|
117
|
+
const seen = [];
|
|
118
|
+
const unsub = room.onConnectionState((s) => seen.push(s));
|
|
119
|
+
unsub();
|
|
120
|
+
created[0].triggerOpen(); // should NOT fire after unsub
|
|
121
|
+
expect(seen).toEqual(['connecting']);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('Room.send', () => {
|
|
125
|
+
it('serializes data to a kind:msg envelope when socket is open', () => {
|
|
126
|
+
const room = newRoom();
|
|
127
|
+
created[0].triggerOpen();
|
|
128
|
+
room.send({ hello: 'world' });
|
|
129
|
+
expect(created[0].sent).toEqual([JSON.stringify({ kind: 'msg', data: { hello: 'world' } })]);
|
|
130
|
+
});
|
|
131
|
+
it('silently drops messages when socket is not yet open (regression: no throw)', () => {
|
|
132
|
+
const room = newRoom();
|
|
133
|
+
expect(() => room.send({ hello: 'world' })).not.toThrow();
|
|
134
|
+
expect(created[0].sent).toEqual([]);
|
|
135
|
+
});
|
|
136
|
+
it('silently drops messages after close', () => {
|
|
137
|
+
const room = newRoom();
|
|
138
|
+
created[0].triggerOpen();
|
|
139
|
+
room.close();
|
|
140
|
+
room.send({ hello: 'world' });
|
|
141
|
+
// After close, socket is null — no sent message.
|
|
142
|
+
expect(created[0].sent).toEqual([]);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('Room.onMessage', () => {
|
|
146
|
+
it('receives kind:msg frames as RoomMessage', () => {
|
|
147
|
+
const room = newRoom();
|
|
148
|
+
created[0].triggerOpen();
|
|
149
|
+
const messages = [];
|
|
150
|
+
room.onMessage((m) => messages.push(m));
|
|
151
|
+
created[0].triggerMessage(JSON.stringify({
|
|
152
|
+
kind: 'msg',
|
|
153
|
+
from: { uid: 'gh:1', login: 'alice' },
|
|
154
|
+
data: { text: 'hi' },
|
|
155
|
+
at: 1700000000000,
|
|
156
|
+
}));
|
|
157
|
+
expect(messages).toHaveLength(1);
|
|
158
|
+
expect(messages[0].from).toEqual({ uid: 'gh:1', login: 'alice' });
|
|
159
|
+
expect(messages[0].data).toEqual({ text: 'hi' });
|
|
160
|
+
});
|
|
161
|
+
it('ignores malformed JSON frames without throwing', () => {
|
|
162
|
+
const room = newRoom();
|
|
163
|
+
created[0].triggerOpen();
|
|
164
|
+
const messages = [];
|
|
165
|
+
room.onMessage((m) => messages.push(m));
|
|
166
|
+
expect(() => created[0].triggerMessage('not-json{')).not.toThrow();
|
|
167
|
+
expect(messages).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
it('ignores frames with unknown `kind`', () => {
|
|
170
|
+
const room = newRoom();
|
|
171
|
+
created[0].triggerOpen();
|
|
172
|
+
const messages = [];
|
|
173
|
+
room.onMessage((m) => messages.push(m));
|
|
174
|
+
created[0].triggerMessage(JSON.stringify({ kind: 'something-else', data: {} }));
|
|
175
|
+
expect(messages).toEqual([]);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
describe('Room.onPeers', () => {
|
|
179
|
+
it('fires immediately with empty peers list on subscribe', () => {
|
|
180
|
+
const room = newRoom();
|
|
181
|
+
const calls = [];
|
|
182
|
+
room.onPeers((peers) => calls.push(peers));
|
|
183
|
+
expect(calls).toEqual([[]]);
|
|
184
|
+
});
|
|
185
|
+
it('updates on kind:peers frame', () => {
|
|
186
|
+
const room = newRoom();
|
|
187
|
+
created[0].triggerOpen();
|
|
188
|
+
const calls = [];
|
|
189
|
+
room.onPeers((peers) => calls.push(peers));
|
|
190
|
+
created[0].triggerMessage(JSON.stringify({
|
|
191
|
+
kind: 'peers',
|
|
192
|
+
peers: [{ uid: 'gh:1', login: 'alice' }, { uid: 'gh:2', login: 'bob' }],
|
|
193
|
+
}));
|
|
194
|
+
expect(calls).toHaveLength(2); // initial + the broadcast
|
|
195
|
+
expect(calls[1]).toEqual([
|
|
196
|
+
{ uid: 'gh:1', login: 'alice' },
|
|
197
|
+
{ uid: 'gh:2', login: 'bob' },
|
|
198
|
+
]);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('Room.close', () => {
|
|
202
|
+
it('stops reconnect, clears listeners, sets state to closed', () => {
|
|
203
|
+
const room = newRoom();
|
|
204
|
+
const stateSeen = [];
|
|
205
|
+
const messages = [];
|
|
206
|
+
room.onConnectionState((s) => stateSeen.push(s));
|
|
207
|
+
room.onMessage((m) => messages.push(m));
|
|
208
|
+
created[0].triggerOpen();
|
|
209
|
+
room.close();
|
|
210
|
+
expect(room.state).toBe('closed');
|
|
211
|
+
// Sending should have no effect (socket cleared).
|
|
212
|
+
room.send({ x: 1 });
|
|
213
|
+
expect(created[0].sent.filter((s) => s.includes('"x":1'))).toEqual([]);
|
|
214
|
+
});
|
|
215
|
+
it('cancels a pending reconnect timer', () => {
|
|
216
|
+
vi.useFakeTimers();
|
|
217
|
+
const room = newRoom();
|
|
218
|
+
created[0].triggerOpen();
|
|
219
|
+
created[0].triggerClose(); // unexpected close → schedules reconnect
|
|
220
|
+
expect(room.state).toBe('closed');
|
|
221
|
+
room.close(); // user-initiated; should cancel reconnect
|
|
222
|
+
vi.advanceTimersByTime(60_000); // jump past any backoff
|
|
223
|
+
expect(created).toHaveLength(1); // no second connect
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
describe('Room reconnect on unexpected close', () => {
|
|
227
|
+
it('opens a new WebSocket after backoff', () => {
|
|
228
|
+
vi.useFakeTimers();
|
|
229
|
+
const room = newRoom();
|
|
230
|
+
created[0].triggerOpen();
|
|
231
|
+
expect(created).toHaveLength(1);
|
|
232
|
+
created[0].triggerClose(); // unexpected — schedules reconnect
|
|
233
|
+
expect(room.state).toBe('closed');
|
|
234
|
+
// First reconnect attempt fires after RECONNECT_BASE_MS (1000ms) + jitter (up to 1000ms).
|
|
235
|
+
vi.advanceTimersByTime(2100);
|
|
236
|
+
expect(created.length).toBeGreaterThanOrEqual(2);
|
|
237
|
+
expect(room.state).toBe('connecting');
|
|
238
|
+
});
|
|
239
|
+
it('opens succeed → state goes back to open + reconnect counter resets', () => {
|
|
240
|
+
vi.useFakeTimers();
|
|
241
|
+
const room = newRoom();
|
|
242
|
+
created[0].triggerOpen();
|
|
243
|
+
created[0].triggerClose();
|
|
244
|
+
vi.advanceTimersByTime(2100);
|
|
245
|
+
created[1].triggerOpen();
|
|
246
|
+
expect(room.state).toBe('open');
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe('Room error handling', () => {
|
|
250
|
+
it('socket error → state goes to error', () => {
|
|
251
|
+
const room = newRoom();
|
|
252
|
+
created[0].triggerError();
|
|
253
|
+
expect(room.state).toBe('error');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
//# sourceMappingURL=rooms.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rooms.test.js","sourceRoot":"","sources":["../src/rooms.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@freeappstore/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Browser SDK for free apps on freeappstore.online — auth, per-user KV, light realtime rooms.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Browser SDK for free apps on freeappstore.online — auth, per-user KV, light realtime rooms, secret-injecting proxy for third-party APIs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
-
"homepage": "https://github.com/freeappstore-online/
|
|
15
|
+
"homepage": "https://github.com/freeappstore-online/platform#readme",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/freeappstore-online/
|
|
18
|
+
"url": "git+https://github.com/freeappstore-online/platform.git",
|
|
19
19
|
"directory": "packages/sdk"
|
|
20
20
|
},
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/freeappstore-online/
|
|
22
|
+
"url": "https://github.com/freeappstore-online/platform/issues"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"freeappstore",
|
|
@@ -29,18 +29,20 @@
|
|
|
29
29
|
"rooms",
|
|
30
30
|
"websocket",
|
|
31
31
|
"github-oauth",
|
|
32
|
-
"cloudflare-workers"
|
|
32
|
+
"cloudflare-workers",
|
|
33
|
+
"proxy",
|
|
34
|
+
"api-key"
|
|
33
35
|
],
|
|
34
36
|
"files": [
|
|
35
37
|
"dist",
|
|
36
38
|
"README.md"
|
|
37
39
|
],
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "tsc",
|
|
40
|
-
"typecheck": "tsc --noEmit"
|
|
41
|
-
},
|
|
42
40
|
"devDependencies": {
|
|
43
41
|
"typescript": "^5.7.0"
|
|
44
42
|
},
|
|
45
|
-
"sideEffects": false
|
|
46
|
-
|
|
43
|
+
"sideEffects": false,
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|