@webqit/webflo 1.0.34 → 1.0.36

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/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "vanila-javascript"
13
13
  ],
14
14
  "homepage": "https://webqit.io/tooling/webflo",
15
- "version": "1.0.34",
15
+ "version": "1.0.36",
16
16
  "license": "MIT",
17
17
  "repository": {
18
18
  "type": "git",
@@ -2,15 +2,14 @@ import { _isObject } from '@webqit/util/js/index.js';
2
2
  import { renderCookieObj } from './util-http.js';
3
3
  import { WebfloStorage } from './WebfloStorage.js';
4
4
 
5
- export class WebfloCookieStorage extends WebfloStorage {
5
+ export class HttpCookies extends WebfloStorage {
6
6
 
7
7
  #originals;
8
8
 
9
9
  constructor(request, iterable = []) {
10
10
  iterable = [...iterable].map(([key, value]) => [key, !_isObject(value) ? { name: key, value } : value]);
11
- iterable = Object.fromEntries(iterable);
12
- super(iterable, null, request);
13
- this.#originals = { ...iterable };
11
+ super(new Map(iterable), null, request);
12
+ this.#originals = new Map(iterable);
14
13
  }
15
14
 
16
15
  async set(key, value) {
@@ -24,8 +23,8 @@ export class WebfloCookieStorage extends WebfloStorage {
24
23
  }
25
24
 
26
25
  async render() {
27
- const entries = await Promise.all((await this.keys()).concat(Object.keys(this.#originals)).map(async (key) => {
28
- const a = Reflect.get(this.#originals, key);
26
+ const entries = await Promise.all((await this.keys()).concat(this.#originals.keys()).map(async (key) => {
27
+ const a = this.#originals.get(key);
29
28
  const b = await this.get(key, true);
30
29
  if (a === b || (_isObject(a) && _isObject(b) && _even(a, b))) {
31
30
  // Same
@@ -0,0 +1,11 @@
1
+ import { WebfloStorage } from './WebfloStorage.js';
2
+
3
+ export class HttpSession extends WebfloStorage {
4
+ static create(store, request) {
5
+ return new this(
6
+ store,
7
+ request,
8
+ true
9
+ );
10
+ }
11
+ }
@@ -1,27 +1,27 @@
1
1
  import { WebfloStorage } from './WebfloStorage.js';
2
2
 
3
3
  export class HttpUser extends WebfloStorage {
4
-
5
- static create(request, session, client) {
6
- return new this(request, session, client);
4
+
5
+ static create(store, request, session, client) {
6
+ return new this(store, request, session, client);
7
7
  }
8
8
 
9
- #session;
10
9
  #client;
11
10
 
12
- constructor(request, session, client) {
13
- super(session, '#user', request, session);
14
- this.#session = session;
11
+ constructor(store, request, session, client) {
12
+ super(
13
+ store,
14
+ request,
15
+ session
16
+ );
15
17
  this.#client = client;
16
18
  }
17
19
 
18
20
  async isSignedIn() {
19
- await this.#session.refresh();
20
21
  return await this.has('id');
21
22
  }
22
23
 
23
24
  async signIn(...args) {
24
- await this.#session.refresh();
25
25
  return await this.require(
26
26
  ['id'].concat(typeof args[0] === 'string' || Array.isArray(args[0]) ? args.unshift() : []),
27
27
  ...args
@@ -30,7 +30,6 @@ export class HttpUser extends WebfloStorage {
30
30
 
31
31
  async signOut() {
32
32
  await this.clear();
33
- await this.#session.commit();
34
33
  }
35
34
 
36
35
  async confirm(data, callback, options = {}) {
@@ -3,50 +3,51 @@ import { _even } from '@webqit/util/obj/index.js';
3
3
 
4
4
  export class WebfloStorage {
5
5
 
6
+ #store;
6
7
  #request;
7
8
  #session;
8
- #registry;
9
- #key;
10
- #store;
11
9
  #modified = false;
12
10
 
13
- constructor(registry, key, request, session = null) {
14
- this.#registry = registry;
15
- this.#key = key;
11
+ constructor(store, request, session = null) {
12
+ this.#store = store || new Map;
16
13
  this.#request = request;
17
14
  this.#session = session === true ? this : session;
18
15
  }
19
-
20
- async store() {
21
- if (!this.#key) {
22
- return this.#registry;
23
- }
24
- if (!this.#store && !(this.#store = await this.#registry.get(this.#key))) {
25
- this.#store = {};
26
- }
27
- return this.#store;
16
+
17
+ async has(key) { return await this.#store.has(key); }
18
+
19
+ async get(key) { return await this.#store.get(key); }
20
+
21
+ async set(key, value) {
22
+ await this.#store.set(key, value);
23
+ this.#modified = true;
24
+ await this.emit(key, value);
25
+ return this;
28
26
  }
29
27
 
30
- async refresh() {
31
- let $store;
32
- if (!this.#store || !($store = await this.#registry.get(this.#key))) return;
33
- Object.assign(this.#store, $store);
28
+ async delete(key) {
29
+ await this.#store.delete(key);
30
+ this.#modified = true;
31
+ await this.emit(key);
32
+ return this;
34
33
  }
35
34
 
36
- async commit() {
37
- if (this.#store && this.#key && this.#modified) {
38
- await this.#registry.set(this.#key, this.#store);
39
- }
40
- this.#modified = false;
35
+ async clear() {
36
+ await this.#store.clear();
37
+ this.#modified = true;
38
+ await this.emit();
39
+ return this;
41
40
  }
42
41
 
43
- get size() { return this.store().then((store) => Object.keys(store).length); }
42
+ async keys() { return [...await this.#store.keys()]; }
44
43
 
45
- [ Symbol.iterator ]() { return this.entries().then((entries) => entries[ Symbol.iterator ]()); }
44
+ async values() { return [...await this.#store.values()]; }
45
+
46
+ async entries() { return [...await this.#store.entries()]; }
46
47
 
47
48
  async json(arg = null) {
48
49
  if (!arguments.length || typeof arg === 'boolean') {
49
- return { ...(await this.store()) };
50
+ return Object.fromEntries(await this.#store.entries());
50
51
  }
51
52
  if (!_isObject(arg)) {
52
53
  throw new Error(`Argument must be a valid JSON object`);
@@ -56,39 +57,14 @@ export class WebfloStorage {
56
57
  }));
57
58
  }
58
59
 
59
- async get(key) { return Reflect.get(await this.store(), key); }
60
-
61
- async has(key) { return Reflect.has(await this.store(), key); }
62
-
63
- async keys() { return Object.keys(await this.store()); }
64
-
65
- async values() { return Object.values(await this.store()); }
66
-
67
- async entries() { return Object.entries(await this.store()); }
68
-
69
- async forEach(callback) { (await this.entries()).forEach(callback); }
60
+ async forEach(callback) { (await this.entries()).forEach(([key, value], i) => callback(value, key, i)); }
70
61
 
71
- async set(key, value) {
72
- Reflect.set(await this.store(), key, value);
73
- this.#modified = true;
74
- await this.emit(key, value);
75
- return this;
76
- }
62
+ [ Symbol.iterator ]() { return this.entries().then((entries) => entries[ Symbol.iterator ]()); }
77
63
 
78
- async delete(key) {
79
- Reflect.deleteProperty(await this.store(), key);
80
- this.#modified = true;
81
- await this.emit(key);
82
- return this;
83
- }
64
+ get size() { return this.#store.sizs; }
84
65
 
85
- async clear() {
86
- for (const key of await this.keys()) {
87
- Reflect.deleteProperty(await this.store(), key);
88
- }
89
- this.#modified = true;
90
- await this.emit();
91
- return this;
66
+ async commit() {
67
+ this.#modified = false;
92
68
  }
93
69
 
94
70
  #listeners = new Set;
@@ -1,6 +1,6 @@
1
- import { WebfloCookieStorage } from '../WebfloCookieStorage.js';
1
+ import { HttpCookies } from '../HttpCookies.js';
2
2
 
3
- export class CookieStorage extends WebfloCookieStorage {
3
+ export class ClientSideCookies extends HttpCookies {
4
4
  static create(request) {
5
5
  return new this(
6
6
  request,
@@ -6,8 +6,8 @@ import { MessagingOverBroadcast } from '../MessagingOverBroadcast.js';
6
6
  import { MessagingOverChannel } from '../MessagingOverChannel.js';
7
7
  import { MessagingOverSocket } from '../MessagingOverSocket.js';
8
8
  import { ClientMessaging } from './ClientMessaging.js';
9
- import { CookieStorage } from './CookieStorage.js';
10
- import { SessionStorage } from './SessionStorage.js';
9
+ import { ClientSideCookies } from './ClientSideCookies.js';
10
+ import { HttpSession } from '../HttpSession.js';
11
11
  import { HttpEvent } from '../HttpEvent.js';
12
12
  import { HttpUser } from '../HttpUser.js';
13
13
  import { Router } from './Router.js';
@@ -23,9 +23,9 @@ export class WebfloClient extends WebfloRuntime {
23
23
 
24
24
  static get HttpEvent() { return HttpEvent; }
25
25
 
26
- static get CookieStorage() { return CookieStorage; }
26
+ static get HttpCookies() { return ClientSideCookies; }
27
27
 
28
- static get SessionStorage() { return SessionStorage; }
28
+ static get HttpSession() { return HttpSession; }
29
29
 
30
30
  static get HttpUser() { return HttpUser; }
31
31
 
@@ -48,11 +48,8 @@ export class WebfloClient extends WebfloRuntime {
48
48
  return document.querySelector('meta[name="webflo-viewtransitions"]')?.value;
49
49
  }
50
50
 
51
- env(key) {
52
- return key in this.cx.params.mappings
53
- ? this.cx.params.env[this.cx.params.mappings[key]]
54
- : this.cx.params.env[key];
55
- }
51
+ #sdk = {};
52
+ get sdk() { return this.#sdk; }
56
53
 
57
54
  constructor(host) {
58
55
  super();
@@ -74,6 +71,12 @@ export class WebfloClient extends WebfloRuntime {
74
71
  };
75
72
  }
76
73
 
74
+ env(key) {
75
+ return key in this.cx.params.mappings
76
+ ? this.cx.params.env[this.cx.params.mappings[key]]
77
+ : this.cx.params.env[key];
78
+ }
79
+
77
80
  async initialize() {
78
81
  this.#backgroundMessaging = new MultiportMessagingAPI(this, { runtime: this });
79
82
  // Bind response and redirect handlers
@@ -329,12 +332,16 @@ export class WebfloClient extends WebfloRuntime {
329
332
  };
330
333
  // Create and route request
331
334
  scope.request = this.createRequest(scope.url, scope.init);
332
- scope.cookies = this.constructor.CookieStorage.create(scope.request);
333
- scope.session = this.constructor.SessionStorage.create(scope.request);
335
+ scope.cookies = this.constructor.HttpCookies.create(scope.request);
336
+ scope.session = this.constructor.HttpSession.create(
337
+ this.#sdk.storage?.('session'),
338
+ scope.request
339
+ );
334
340
  const messageChannel = new MessageChannel;
335
341
  this.backgroundMessaging.add(new MessagingOverChannel(null, messageChannel.port1));
336
342
  scope.clientMessaging = new ClientMessaging(this, messageChannel.port2);
337
343
  scope.user = this.constructor.HttpUser.create(
344
+ this.#sdk.storage?.('user'),
338
345
  scope.request,
339
346
  scope.session,
340
347
  scope.clientMessaging
@@ -346,7 +353,7 @@ export class WebfloClient extends WebfloRuntime {
346
353
  session: scope.session,
347
354
  user: scope.user,
348
355
  client: scope.clientMessaging,
349
- sdk: {}
356
+ sdk: this.#sdk
350
357
  });
351
358
  await this.setup(scope.httpEvent);
352
359
  scope.httpEvent.onRequestClone = () => this.createRequest(scope.url, scope.init);
@@ -3,8 +3,8 @@ import { _isObject } from '@webqit/util/js/index.js';
3
3
  import { pattern } from '../../util-url.js';
4
4
  import { WebfloRuntime } from '../../WebfloRuntime.js';
5
5
  import { ClientMessaging } from './ClientMessaging.js';
6
- import { CookieStorage } from './CookieStorage.js';
7
- import { SessionStorage } from './SessionStorage.js';
6
+ import { WorkerSideCookies } from './WorkerSideCookies.js';
7
+ import { HttpSession } from '../../HttpSession.js';
8
8
  import { HttpEvent } from '../../HttpEvent.js';
9
9
  import { HttpUser } from '../../HttpUser.js';
10
10
  import { Workport } from './Workport.js';
@@ -21,9 +21,9 @@ export class WebfloWorker extends WebfloRuntime {
21
21
 
22
22
  static get HttpEvent() { return HttpEvent; }
23
23
 
24
- static get CookieStorage() { return CookieStorage; }
24
+ static get HttpCookies() { return WorkerSideCookies; }
25
25
 
26
- static get SessionStorage() { return SessionStorage; }
26
+ static get HttpSession() { return HttpSession; }
27
27
 
28
28
  static get HttpUser() { return HttpUser; }
29
29
 
@@ -36,6 +36,9 @@ export class WebfloWorker extends WebfloRuntime {
36
36
  #cx;
37
37
  get cx() { return this.#cx; }
38
38
 
39
+ #sdk = {};
40
+ get sdk() { return this.#sdk; }
41
+
39
42
  constructor(cx) {
40
43
  super();
41
44
  if (!(cx instanceof this.constructor.Context)) {
@@ -163,11 +166,15 @@ export class WebfloWorker extends WebfloRuntime {
163
166
  };
164
167
  // Create and route request
165
168
  scope.request = this.createRequest(scope.url, scope.init);
166
- scope.cookies = this.constructor.CookieStorage.create(scope.request);
167
- scope.session = this.constructor.SessionStorage.create(scope.request);
169
+ scope.cookies = this.constructor.HttpCookies.create(scope.request);
170
+ scope.session = this.constructor.HttpSession.create(
171
+ this.#sdk.storage?.('session'),
172
+ scope.request
173
+ );
168
174
  const portID = crypto.randomUUID();
169
175
  scope.clientMessaging = new ClientMessaging(this, portID, { isPrimary: true });
170
176
  scope.user = this.constructor.HttpUser.create(
177
+ this.#sdk.storage?.('user'),
171
178
  scope.request,
172
179
  scope.session,
173
180
  scope.clientMessaging
@@ -1,6 +1,6 @@
1
- import { WebfloCookieStorage } from '../WebfloCookieStorage.js';
1
+ import { HttpCookies } from '../../HttpCookies.js';
2
2
 
3
- export class CookieStorage extends WebfloCookieStorage {
3
+ export class WorkerSideCookies extends HttpCookies {
4
4
  static create(request) {
5
5
  return new this(
6
6
  request,
@@ -1,6 +1,6 @@
1
- import { WebfloCookieStorage } from '../../WebfloCookieStorage.js';
1
+ import { HttpCookies } from '../HttpCookies.js';
2
2
 
3
- export class CookieStorage extends WebfloCookieStorage {
3
+ export class ServerSideCookies extends HttpCookies {
4
4
  static create(request) {
5
5
  return new this(
6
6
  request,
@@ -1,10 +1,9 @@
1
- import { WebfloStorage } from '../WebfloStorage.js';
1
+ import { HttpSession } from '../HttpSession.js';
2
2
  import crypto from 'crypto';
3
3
 
4
- const inmemSessionRegistry = new Map;
5
- export class SessionStorage extends WebfloStorage {
4
+ export class ServerSideSession extends HttpSession {
6
5
 
7
- static create(request, params = {}) {
6
+ static create(storageCallback, request, params = {}) {
8
7
  let sessionID = request.headers.get('Cookie', true).find((c) => c.name === '__sessid')?.value;
9
8
  if (sessionID?.includes('.')) {
10
9
  if (params.secret) {
@@ -30,28 +29,34 @@ export class SessionStorage extends WebfloStorage {
30
29
  sessionID = crypto.randomUUID();
31
30
  }
32
31
  }
33
- return new this(params.registry || inmemSessionRegistry, sessionID, request, params.ttl);
32
+ return new this(
33
+ storageCallback(sessionID),
34
+ request,
35
+ { sessionID, ...params }
36
+ );
34
37
  }
35
38
 
39
+ #params;
36
40
  #sessionID;
37
41
  get sessionID() { return this.#sessionID; }
38
- #ttl;
39
42
 
40
- constructor(reqistry, sessionID, request, ttl) {
43
+ constructor(store, request, { sessionID, ...params } = {}) {
44
+ if (!sessionID) {
45
+ throw new Error(`sessionID is required`);
46
+ }
41
47
  super(
42
- reqistry,
43
- `session/${sessionID}`,
48
+ store,
44
49
  request,
45
50
  true
46
51
  );
52
+ this.#params = params;
47
53
  this.#sessionID = sessionID;
48
- this.#ttl = ttl;
49
54
  }
50
55
 
51
56
  async commit(response = null) {
52
57
  if (response && !response.headers.get('Set-Cookie', true).find((c) => c.name === '__sessid')) {
53
58
  // expires six months
54
- response.headers.append('Set-Cookie', `__sessid=${this.#sessionID}; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=${this.#ttl}`);
59
+ response.headers.append('Set-Cookie', `__sessid=${this.#sessionID}; Path=/; Secure; HttpOnly; SameSite=Lax${this.#params.ttl ? `; Max-Age=${this.#params.ttl}` : ''}`);
55
60
  }
56
61
  await super.commit();
57
62
  }
@@ -15,14 +15,14 @@ import { Readable as _ReadableStream } from 'stream';
15
15
  import { WebfloRuntime } from '../WebfloRuntime.js';
16
16
  import { createWindow } from '@webqit/oohtml-ssr';
17
17
  import { Context } from './Context.js';
18
- import { CookieStorage } from './CookieStorage.js';
19
- import { SessionStorage } from './SessionStorage.js';
20
18
  import { MessagingOverSocket } from '../MessagingOverSocket.js';
21
19
  import { ClientMessagingRegistry } from './ClientMessagingRegistry.js';
20
+ import { ServerSideCookies } from './ServerSideCookies.js';
21
+ import { ServerSideSession } from './ServerSideSession.js';
22
22
  import { HttpEvent } from '../HttpEvent.js';
23
23
  import { HttpUser } from '../HttpUser.js';
24
24
  import { Router } from './Router.js';
25
- import { params, pattern } from '../util-url.js';
25
+ import { pattern } from '../util-url.js';
26
26
  import xfetch from '../xfetch.js';
27
27
  import '../util-http.js';
28
28
 
@@ -37,9 +37,9 @@ export class WebfloServer extends WebfloRuntime {
37
37
 
38
38
  static get HttpEvent() { return HttpEvent; }
39
39
 
40
- static get CookieStorage() { return CookieStorage; }
40
+ static get HttpCookies() { return ServerSideCookies; }
41
41
 
42
- static get SessionStorage() { return SessionStorage; }
42
+ static get HttpSession() { return ServerSideSession; }
43
43
 
44
44
  static get HttpUser() { return HttpUser; }
45
45
 
@@ -74,10 +74,10 @@ export class WebfloServer extends WebfloRuntime {
74
74
 
75
75
  async initialize() {
76
76
  process.on('uncaughtException', (err) => {
77
- console.error('Uncaught- Exception:', err);
77
+ console.error('Uncaught Exception:', err);
78
78
  });
79
79
  process.on('unhandledRejection', (reason, promise) => {
80
- console.log('Unhandled -Rejection', reason, promise);
80
+ console.log('Unhandled Rejection', reason, promise);
81
81
  });
82
82
  const resolveContextObj = async (cx, force = false) => {
83
83
  if (_isEmpty(cx.layout) || force) { cx.layout = await (new cx.config.deployment.Layout(cx)).read(); }
@@ -218,9 +218,39 @@ export class WebfloServer extends WebfloRuntime {
218
218
  }
219
219
  if (this.#cx.server.capabilities?.redis) {
220
220
  const { Redis } = await import('ioredis');
221
- this.#sdk.redis = this.env('REDIS_URL')
221
+ const redis = this.env('REDIS_URL')
222
222
  ? new Redis(this.env('REDIS_URL'))
223
223
  : new Redis;
224
+ this.#sdk.redis = redis;
225
+ this.#sdk.storage = (namespace, ttl = null) => ({
226
+ async has(key) { return await redis.hexists(namespace, key); },
227
+ async get(key) {
228
+ const value = await redis.hget(namespace, key);
229
+ return typeof value === 'undefined' ? value : JSON.parse(value);
230
+ },
231
+ async set(key, value) {
232
+ const returnValue = await redis.hset(namespace, key, JSON.stringify(value));
233
+ if (!this.ttlApplied && ttl) {
234
+ await redis.expire(namespace, ttl);
235
+ this.ttlApplied = true;
236
+ }
237
+ return returnValue;
238
+ },
239
+ async delete(key) { return await redis.hdel(namespace, key); },
240
+ async clear() { return await redis.del(namespace); },
241
+ async keys() { return await redis.hkeys(namespace); },
242
+ async values() { return await redis.hvals(namespace); },
243
+ async entries() { return Object.entries(await redis.hgetall(namespace) || {}); },
244
+ get size() { return redis.hlen(namespace); },
245
+ });
246
+ } else {
247
+ const inmemSessionRegistry = new Map;
248
+ this.#sdk.storage = (namespace) => {
249
+ if (!inmemSessionRegistry.has(namespace)) {
250
+ inmemSessionRegistry.set(namespace, new Map);
251
+ }
252
+ return inmemSessionRegistry.get(namespace);
253
+ };
224
254
  }
225
255
  if (this.#cx.server.capabilities?.webpush) {
226
256
  const { default: webpush } = await import('web-push');
@@ -271,14 +301,15 @@ export class WebfloServer extends WebfloRuntime {
271
301
  // Level 3 validation
272
302
  // and actual processing
273
303
  scope.request = this.createRequest(scope.url.href, requestInit);
274
- scope.session = this.constructor.SessionStorage.create(scope.request, {
275
- secret: this.env('SESSION_KEY'),
276
- registry: this.#sdk.redis && {
277
- get: async (key) => { return JSON.parse(await this.#sdk.redis.get(`${scope.url.host}/${key}`) || null) },
278
- set: async (key, value) => { return await this.#sdk.redis.set(`${scope.url.host}/${key}`, JSON.stringify(value), 'EX', this.env('SESSION_TTL') || 2592000/*30days*/) },
279
- },
280
- ttl: this.env('SESSION_TTL') || 2592000/*30days*/,
281
- });
304
+ scope.sessionTTL = this.env('SESSION_TTL') || 2592000/*30days*/;
305
+ scope.session = this.constructor.HttpSession.create(
306
+ (sessionID) => this.#sdk.storage?.(`${scope.url.host}/session:${sessionID}`, scope.sessionTTL),
307
+ scope.request,
308
+ {
309
+ secret: this.env('SESSION_KEY'),
310
+ ttl: scope.sessionTTL,
311
+ }
312
+ );
282
313
  if (!scope.error) {
283
314
  if (!(scope.clientMessagingRegistry = this.#globalMessagingRegistry.get(scope.session.sessionID))) {
284
315
  scope.error = `Lost or invalid clientID`;
@@ -576,15 +607,16 @@ export class WebfloServer extends WebfloRuntime {
576
607
  ? ((await (new this.#cx.config.runtime.server.Headers(this.#cx)).read()).entries || []).filter(entry => pattern(entry.url, url.origin).exec(url.href))
577
608
  : [];
578
609
  scope.request = this.createRequest(scope.url.href, scope.init, scope.autoHeaders.filter((header) => header.type === 'request'));
579
- scope.cookies = this.constructor.CookieStorage.create(scope.request);
580
- scope.session = this.constructor.SessionStorage.create(scope.request, {
581
- secret: this.env('SESSION_KEY'),
582
- registry: this.#sdk.redis && {
583
- get: async (key) => { return JSON.parse(await this.#sdk.redis.get(`${scope.url.host}/${key}`) || null) },
584
- set: async (key, value) => { return await this.#sdk.redis.set(`${scope.url.host}/${key}`, JSON.stringify(value), 'EX', this.env('SESSION_TTL') || 2592000/*30days*/); },
585
- },
586
- ttl: this.env('SESSION_TTL') || 2592000/*30days*/,
587
- });
610
+ scope.cookies = this.constructor.HttpCookies.create(scope.request);
611
+ scope.sessionTTL = this.env('SESSION_TTL') || 2592000/*30days*/;
612
+ scope.session = this.constructor.HttpSession.create(
613
+ (sessionID) => this.#sdk.storage?.(`${scope.url.host}/session:${sessionID}`, scope.sessionTTL),
614
+ scope.request,
615
+ {
616
+ secret: this.env('SESSION_KEY'),
617
+ ttl: scope.sessionTTL,
618
+ }
619
+ );
588
620
  const sessionID = scope.session.sessionID;
589
621
  if (!this.#globalMessagingRegistry.has(sessionID)) {
590
622
  this.#globalMessagingRegistry.set(sessionID, new ClientMessagingRegistry(this, sessionID));
@@ -592,6 +624,7 @@ export class WebfloServer extends WebfloRuntime {
592
624
  scope.clientMessagingRegistry = this.#globalMessagingRegistry.get(sessionID);
593
625
  scope.clientMessaging = scope.clientMessagingRegistry.createPort();
594
626
  scope.user = this.constructor.HttpUser.create(
627
+ this.#sdk.storage?.(`${scope.url.host}/user:${scope.session.sessionID}`, scope.sessionTTL),
595
628
  scope.request,
596
629
  scope.session,
597
630
  scope.clientMessaging
@@ -1,16 +0,0 @@
1
- import { WebfloStorage } from '../WebfloStorage.js';
2
-
3
- export class SessionStorage extends WebfloStorage {
4
- static create(request) {
5
- const registry = {
6
- async get(key) { return localStorage.getItem(key) },
7
- async set(key, value) { return localStorage.setItem(key, value) },
8
- };
9
- return new this(
10
- registry,
11
- 'session',
12
- request,
13
- true
14
- );
15
- }
16
- }
@@ -1,11 +0,0 @@
1
- import { WebfloStorage } from '../../WebfloStorage.js';
2
-
3
- export class SessionStorage extends WebfloStorage {
4
- static create(request) {
5
- return new this({}, null, request);
6
- }
7
-
8
- async commit(response = null) {
9
- await super.commit();
10
- }
11
- }