@webqit/webflo 0.20.28 → 0.20.29

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.
@@ -1,5 +1,9 @@
1
- export function defineElement(WebfloSubClient, embedTagNames = 'webflo-embedded') {
2
- window.customElements.define(embedTagNames, class extends HTMLElement {
1
+ import { WebfloSubClient } from './WebfloSubClient.js';
2
+
3
+ export function defineElement() {
4
+ const embedTagName = 'webflo-embedded';
5
+
6
+ window.customElements.define(embedTagName, class extends HTMLElement {
3
7
 
4
8
  #superRuntime;
5
9
  #lifecycleController;
@@ -39,7 +43,7 @@ export function defineElement(WebfloSubClient, embedTagNames = 'webflo-embedded'
39
43
  }
40
44
 
41
45
  async connectedCallback() {
42
- this.#superRuntime = (this.parentNode?.closest(embedTagNames) || document).webfloRuntime;
46
+ this.#superRuntime = (this.parentNode?.closest(embedTagName) || document).webfloRuntime;
43
47
  this.#lifecycleController = await WebfloSubClient.create(this.#superRuntime, this).initialize();
44
48
  }
45
49
 
@@ -20,7 +20,7 @@ export class HttpCookies101 extends HttpKeyvalInterface {
20
20
  // ------ extras
21
21
 
22
22
  async render() {
23
- const json = await this.json(true);
23
+ const json = await this.json({ meta: true });
24
24
 
25
25
  const entries = Object.keys(json).concat(Object.keys(this.#initial)).map((key) => {
26
26
  const a = this.#initial[key];
@@ -45,8 +45,11 @@ export function renderCookieObjToString(cookieObj) {
45
45
  const attrsArr = [`${cookieObj.name}=${/*encodeURIComponent*/(cookieObj.value)}`];
46
46
  for (const attrName in cookieObj) {
47
47
  if (['name', 'value'].includes(attrName)) continue;
48
+
48
49
  let _attrName = attrName[0].toUpperCase() + attrName.substring(1);
49
50
  if (_attrName === 'MaxAge') { _attrName = 'Max-Age' };
51
+
52
+ if (cookieObj[attrName] === false) continue;
50
53
  attrsArr.push(cookieObj[attrName] === true ? _attrName : `${_attrName}=${cookieObj[attrName]}`);
51
54
  }
52
55
  return attrsArr.join('; ');
@@ -30,7 +30,7 @@ export class HttpEvent111 {
30
30
  node._context.parentEvent = this;
31
31
  });
32
32
 
33
- this.#url = new URLPlus(this.#init.request.url);
33
+ this.#url = new URLPlus(this.#init.request.url, undefined, { immutable: true });
34
34
 
35
35
  this._parentEvent?.signal.addEventListener('abort', () => this.#abortController.abort(), { once: true });
36
36
  this.#init.request.signal?.addEventListener('abort', () => this.#abortController.abort(), { once: true });
@@ -168,9 +168,12 @@ export class HttpEvent111 {
168
168
  const urlRewrite = new URL(url, this.request.url);
169
169
  const newThread = this.thread.spawn(urlRewrite.searchParams.get('_thread'));
170
170
  urlRewrite.searchParams.set('_thread', newThread.threadID);
171
- await newThread.append('back', this.request.url.replace(urlRewrite.origin, ''));
172
- for (const [key, value] of Object.entries(data)) {
173
- await newThread.append(key, value);
171
+
172
+ const back = this.request.url.replace(urlRewrite.origin, '');
173
+ await newThread.appendEach({ back, ...data });
174
+
175
+ if (this.url.query['_thread']) {
176
+ this.thread.extend();
174
177
  }
175
178
  //-----
176
179
  return await this.respondWith(null, { status, ...options, headers: { Location: urlRewrite.href } });
@@ -46,10 +46,11 @@ export class HttpKeyvalInterface {
46
46
  async keys() { return [...await this.#store.keys()]; }
47
47
  async values() { return [...await this.#store.values()]; }
48
48
  async entries() { return [...await this.#store.entries()]; }
49
- async has(key) { return await this.#store.has(key); }
50
- async get(key) { return await this.#store.get(key); }
51
- async set(key, value) { await this.#store.set(key, value); }
52
- async delete(key) { await this.#store.delete(key); }
49
+ async has(...args) { return await this.#store.has(...args); }
50
+ async get(...args) { return await this.#store.get(...args); }
51
+ async set(...args) { await this.#store.set(...args); }
52
+ async patch(...args) { await this.#store.patch(...args); }
53
+ async delete(...args) { await this.#store.delete(...args); }
53
54
  async clear() { await this.#store.clear(); }
54
55
  async json(...args) { return await this.#store.json(...args); }
55
56
 
@@ -4,9 +4,8 @@ export class HttpSession001 extends HttpKeyvalInterface {
4
4
 
5
5
  #sessionID;
6
6
  get sessionID() { return this.#sessionID; }
7
- #ttl;
8
7
 
9
- constructor({ context = {}, store, request, thread, sessionID, ttl }) {
8
+ constructor({ context = {}, store, request, thread, sessionID }) {
10
9
  if (!sessionID) {
11
10
  throw new Error(`sessionID is required`);
12
11
  }
@@ -16,9 +15,7 @@ export class HttpSession001 extends HttpKeyvalInterface {
16
15
  request,
17
16
  thread,
18
17
  sessionID,
19
- ttl
20
18
  });
21
19
  this.#sessionID = sessionID;
22
- this.#ttl = ttl;
23
20
  }
24
21
  }
@@ -6,8 +6,8 @@ export class HttpThread111 {
6
6
 
7
7
  static create({ context = {}, store, threadID, realm = 0 }) {
8
8
  let hydrationMode = true;
9
- if (!threadID || !(new RegExp(`^wq\\.${realm}\\.`)).test(threadID)) {
10
- threadID = `wq.${realm}.${(0 | Math.random() * 9e6).toString(36)}`;//`wq.${realm}.${crypto.randomUUID()}`;
9
+ if (!threadID || !/^[01]{3}-/.test(threadID)) {
10
+ threadID = `${realm === 3 ? '001' : '110'}-${(0 | Math.random() * 9e6).toString(36)}`;
11
11
  hydrationMode = false;
12
12
  }
13
13
  return new this({ context, store, threadID, realm, lifecycle: { dirty: hydrationMode, extended: false } });
@@ -75,63 +75,51 @@ export class HttpThread111 {
75
75
  return Object.keys(thread);
76
76
  }
77
77
 
78
- async has(key, filter = null) {
78
+ async has(key) {
79
79
  if (!this.#lifecycle.dirty) return false;
80
- if (filter === true || !filter) return (await this.keys()).includes(key);
81
- const thread = await this.#store.get(this.#threadID) || {};
82
- const values = [].concat(thread[key] ?? []);
83
- return values.findIndex(filter) !== -1;
80
+ return (await this.keys()).includes(key);
84
81
  }
85
82
 
86
83
  async append(key, value) {
87
84
  this.#lifecycle.dirty = true;
85
+
88
86
  const thread = await this.#store.get(this.#threadID) || {};
89
- thread[key] = [].concat(thread[key] ?? []);
90
- thread[key].push(value);
87
+ thread[key] = { content: value, context: thread[key] };
88
+
91
89
  await this.#store.set(this.#threadID, thread);
92
90
  }
93
91
 
94
- async get(key, filter = null) {
95
- if (!this.#lifecycle.dirty) return filter === true ? [] : undefined;
92
+ async appendEach(hash) {
93
+ this.#lifecycle.dirty = true;
94
+
96
95
  const thread = await this.#store.get(this.#threadID) || {};
97
- const values = [].concat(thread[key] ?? []);
96
+ for (const [key, value] of Object.entries(hash)) {
97
+ thread[key] = { content: value, context: thread[key] };
98
+ }
98
99
 
99
- let value;
100
- if (filter === true) {
101
- value = values;
102
- } else if (filter) {
103
- value = values.find(filter);
104
- } else { value = values[values.length - 1]; }
100
+ await this.#store.set(this.#threadID, thread);
101
+ }
105
102
 
106
- return value;
103
+ async get(key, withContext = false) {
104
+ if (!this.#lifecycle.dirty) return null;
105
+ const thread = await this.#store.get(this.#threadID) || {};
106
+ return (withContext ? thread[key] : thread[key]?.content) || null;
107
107
  }
108
108
 
109
- async consume(key, filter = null) {
110
- if (!this.#lifecycle.dirty) return filter === true ? [] : undefined;
109
+ async consume(key, withContext = false) {
110
+ if (!this.#lifecycle.dirty) return null;
111
111
  const thread = await this.#store.get(this.#threadID) || {};
112
- const values = [].concat(thread[key] ?? []);
113
-
114
- let value;
115
- if (filter === true) {
116
- delete thread[key];
117
- value = values;
118
- } else if (filter) {
119
- const i = values.findIndex(filter);
120
- if (i !== -1) {
121
- value = values.splice(i, 1)[0];
122
- }
123
- } else { value = values.pop(); }
124
-
125
- if (!values.length) {
126
- delete thread[key];
127
- }
112
+
113
+ const value = thread[key];
114
+ delete thread[key];
115
+
128
116
  if (!Object.keys(thread).length) {
129
117
  await this.#store.delete(this.#threadID);
130
118
  } else {
131
119
  await this.#store.set(this.#threadID, thread);
132
120
  }
133
121
 
134
- return value;
122
+ return (withContext ? value : value?.content) || null;
135
123
  }
136
124
 
137
125
  async clear() {
@@ -37,11 +37,11 @@ export class KeyvalsFactory001 extends KeyvalsFactoryInterface {
37
37
  }
38
38
 
39
39
  create({ type, ...options }) {
40
- const { path, ttl = 0 } = options;
40
+ const { path, ttl = null } = options;
41
41
 
42
42
  if (!Array.isArray(path) || path.length !== 2) throw new Error('Path must be an array of length 2');
43
43
  if (options.origins && (!Array.isArray(options.origins) || options.origins.length !== 1)) throw new Error('Origins must be an array of length 1');
44
- if (ttl && typeof ttl !== 'number') throw new Error('TTL must be a number');
44
+ if (ttl !== null && typeof ttl !== 'number') throw new Error('TTL must be a number');
45
45
 
46
46
  const origins = (options.origins || this.defaultOrigins).concat(this.instanceID);
47
47
 
@@ -32,11 +32,11 @@ export class KeyvalsFactory110 extends KeyvalsFactoryInterface {
32
32
  }
33
33
 
34
34
  create({ type = 'indexeddb', ...options }) {
35
- const { path, ttl = 0 } = options;
35
+ const { path, ttl = null } = options;
36
36
 
37
37
  if (!Array.isArray(path) || path.length !== 2) throw new Error('Path must be an array of length 2');
38
38
  if (options.origins && (!Array.isArray(options.origins) || options.origins.length !== 1)) throw new Error('Origins must be an array of length 1');
39
- if (ttl && typeof ttl !== 'number') throw new Error('TTL must be a number');
39
+ if (ttl !== null && typeof ttl !== 'number') throw new Error('TTL must be a number');
40
40
 
41
41
  const origins = (options.origins || this.defaultOrigins).concat(this.instanceID);
42
42
 
@@ -249,7 +249,9 @@ export class WebfloServer extends AppRuntime {
249
249
 
250
250
  identifyIncoming(request, autoGenerateID = false) {
251
251
  const secret = this.env('SESSION_KEY');
252
+
252
253
  let tenantID = request.headers.get('Cookie', true).find((c) => c.name === '__sessid')?.value;
254
+
253
255
  if (tenantID?.includes('.')) {
254
256
  if (secret) {
255
257
  const [rand, signature] = tenantID.split('.');
@@ -262,10 +264,12 @@ export class WebfloServer extends AppRuntime {
262
264
  } else {
263
265
  tenantID = null;
264
266
  }
265
- }
267
+ } else tenantID = null;
268
+
266
269
  if (!tenantID) {
267
270
  tenantID = request.headers.get('Authorization')?.replace(/\s+/, '_');
268
271
  }
272
+
269
273
  if (!tenantID && autoGenerateID) {
270
274
  if (secret) {
271
275
  const rand = `${(0 | Math.random() * 9e6).toString(36)}`;
@@ -277,6 +281,7 @@ export class WebfloServer extends AppRuntime {
277
281
  tenantID = crypto.randomUUID();
278
282
  }
279
283
  }
284
+
280
285
  return tenantID;
281
286
  }
282
287
 
@@ -708,15 +713,15 @@ export class WebfloServer extends AppRuntime {
708
713
  // Thread
709
714
  scopeObj.thread = HttpThread111.create({
710
715
  context: {},
711
- store: this.#keyvals.create({ path: ['thread', scopeObj.tenantID], origins }),
716
+ store: this.#keyvals.create({ path: ['thread', scopeObj.tenantID], origins, ttl: 60*60*24*30/* 30 days */ }),
712
717
  threadID: scopeObj.url.searchParams.get('_thread'),
713
718
  realm: 3
714
719
  });
715
720
 
716
721
  // Cookies
717
- const entries = scopeObj.request.headers.get('Cookie', true).map((c) => [c.name, c]);
722
+ const entries = scopeObj.request.headers.get('Cookie', true).map((c) => [c.name, c.value]);
718
723
  const store = InMemoryKV.create({ path: ['cookies', scopeObj.tenantID] });
719
- entries.forEach(([key, value]) => store.set(key, { value }));
724
+ entries.forEach(([key, value]) => store.set({ key, value }));
720
725
  const initial = Object.fromEntries(entries);
721
726
  scopeObj.cookies = HttpCookies101.create({
722
727
  context: { handlersRegistry: this.#keyvals.getHandlers('cookies', true) },
@@ -730,7 +735,6 @@ export class WebfloServer extends AppRuntime {
730
735
  context: { handlersRegistry: this.#keyvals.getHandlers('session', true) },
731
736
  store: this.#keyvals.create({ path: ['session', scopeObj.tenantID], ttl: scopeObj.sessionTTL, origins }),
732
737
  sessionID: scopeObj.tenantID,
733
- ttl: scopeObj.sessionTTL,
734
738
  realm: 3
735
739
  });
736
740
 
@@ -142,7 +142,7 @@ export class WebfloWorker extends AppRuntime {
142
142
  // Thread
143
143
  scopeObj.thread = HttpThread111.create({
144
144
  context: {},
145
- store: this.#keyvals.create({ path: ['thread', scopeObj.tenantID], origins }),
145
+ store: this.#keyvals.create({ path: ['thread', scopeObj.tenantID], origins, ttl: 60*60*24*30/* 30 days */ }),
146
146
  threadID: scopeObj.url.searchParams.get('_thread'),
147
147
  realm: 2
148
148
  });