feat: Passwordless cross-device authentication

- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
+94
View File
@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = formatDistance;
var formatDistanceLocale = {
lessThanXSeconds: {
one: 'mwens pase yon segond',
other: 'mwens pase {{count}} segond'
},
xSeconds: {
one: '1 segond',
other: '{{count}} segond'
},
halfAMinute: '30 segond',
lessThanXMinutes: {
one: 'mwens pase yon minit',
other: 'mwens pase {{count}} minit'
},
xMinutes: {
one: '1 minit',
other: '{{count}} minit'
},
aboutXHours: {
one: 'anviwon inè',
other: 'anviwon {{count}} è'
},
xHours: {
one: '1 lè',
other: '{{count}} lè'
},
xDays: {
one: '1 jou',
other: '{{count}} jou'
},
aboutXWeeks: {
one: 'anviwon 1 semèn',
other: 'anviwon {{count}} semèn'
},
xWeeks: {
one: '1 semèn',
other: '{{count}} semèn'
},
aboutXMonths: {
one: 'anviwon 1 mwa',
other: 'anviwon {{count}} mwa'
},
xMonths: {
one: '1 mwa',
other: '{{count}} mwa'
},
aboutXYears: {
one: 'anviwon 1 an',
other: 'anviwon {{count}} an'
},
xYears: {
one: '1 an',
other: '{{count}} an'
},
overXYears: {
one: 'plis pase 1 an',
other: 'plis pase {{count}} an'
},
almostXYears: {
one: 'prèske 1 an',
other: 'prèske {{count}} an'
}
};
function formatDistance(token, count, options) {
options = options || {};
var result;
if (typeof formatDistanceLocale[token] === 'string') {
result = formatDistanceLocale[token];
} else if (count === 1) {
result = formatDistanceLocale[token].one;
} else {
result = formatDistanceLocale[token].other.replace('{{count}}', count);
}
if (options.addSuffix) {
if (options.comparison > 0) {
return 'nan ' + result;
} else {
return 'sa fè ' + result;
}
}
return result;
}
module.exports = exports.default;
+46
View File
@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildFormatLongFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var dateFormats = {
full: 'EEEE d MMMM y',
long: 'd MMMM y',
medium: 'd MMM y',
short: 'dd/MM/y'
};
var timeFormats = {
full: 'HH:mm:ss zzzz',
long: 'HH:mm:ss z',
medium: 'HH:mm:ss',
short: 'HH:mm'
};
var dateTimeFormats = {
full: "{{date}} 'nan lè' {{time}}",
long: "{{date}} 'nan lè' {{time}}",
medium: '{{date}}, {{time}}',
short: '{{date}}, {{time}}'
};
var formatLong = {
date: (0, _index.default)({
formats: dateFormats,
defaultWidth: 'full'
}),
time: (0, _index.default)({
formats: timeFormats,
defaultWidth: 'full'
}),
dateTime: (0, _index.default)({
formats: dateTimeFormats,
defaultWidth: 'full'
})
};
var _default = formatLong;
exports.default = _default;
module.exports = exports.default;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = formatRelative;
var formatRelativeLocale = {
lastWeek: "eeee 'pase nan lè' p",
yesterday: "'yè nan lè' p",
today: "'jodi a' p",
tomorrow: "'demen nan lè' p'",
nextWeek: "eeee 'pwochen nan lè' p",
other: 'P'
};
function formatRelative(token, _date, _baseDate, _options) {
return formatRelativeLocale[token];
}
module.exports = exports.default;
+23
View File
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var formatters = {}; // Special case for day of month ordinals in long date format context:
// 1er mars, 2 mars, 3 mars, …
// See https://github.com/date-fns/date-fns/issues/437
var monthsTokens = ['MMM', 'MMMM'];
monthsTokens.forEach(function (monthToken) {
formatters['Do ' + monthToken] = function (date, options) {
var commonFormatters = options.formatters;
var dayOfMonthToken = date.getUTCDate() === 1 ? 'Do' : 'D';
var dayOfMonthFormatter = commonFormatters[dayOfMonthToken];
var monthFormatter = commonFormatters[monthToken];
return dayOfMonthFormatter(date, options) + ' ' + monthFormatter(date, options);
};
});
var _default = formatters;
exports.default = _default;
module.exports = exports.default;
+121
View File
@@ -0,0 +1,121 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildLocalizeFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var eraValues = {
narrow: ['av. J.-K', 'ap. J.-K'],
abbreviated: ['av. J.-K', 'ap. J.-K'],
wide: ['anvan Jezi Kris', 'apre Jezi Kris']
};
var quarterValues = {
narrow: ['T1', 'T2', 'T3', 'T4'],
abbreviated: ['1ye trim.', '2yèm trim.', '3yèm trim.', '4yèm trim.'],
wide: ['1ye trimès', '2yèm trimès', '3yèm trimès', '4yèm trimès']
};
var monthValues = {
narrow: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'O', 'S', 'O', 'N', 'D'],
abbreviated: ['janv.', 'fevr.', 'mas', 'avr.', 'me', 'jen', 'jiyè', 'out', 'sept.', 'okt.', 'nov.', 'des.'],
wide: ['janvye', 'fevrye', 'mas', 'avril', 'me', 'jen', 'jiyè', 'out', 'septanm', 'oktòb', 'novanm', 'desanm']
};
var dayValues = {
narrow: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],
short: ['di', 'le', 'ma', 'mè', 'je', 'va', 'sa'],
abbreviated: ['dim.', 'len.', 'mad.', 'mèk.', 'jed.', 'van.', 'sam.'],
wide: ['dimanch', 'lendi', 'madi', 'mèkredi', 'jedi', 'vandredi', 'samdi']
};
var dayPeriodValues = {
narrow: {
am: 'AM',
pm: 'PM',
midnight: 'minwit',
noon: 'midi',
morning: 'mat.',
afternoon: 'ap.m.',
evening: 'swa',
night: 'mat.'
},
abbreviated: {
am: 'AM',
pm: 'PM',
midnight: 'minwit',
noon: 'midi',
morning: 'maten',
afternoon: 'aprèmidi',
evening: 'swa',
night: 'maten'
},
wide: {
am: 'AM',
pm: 'PM',
midnight: 'minwit',
noon: 'midi',
morning: 'nan maten',
afternoon: 'nan aprèmidi',
evening: 'nan aswè',
night: 'nan maten'
}
};
function ordinalNumber(dirtyNumber, dirtyOptions) {
var number = Number(dirtyNumber);
var options = dirtyOptions || {};
var unit = String(options.unit);
var suffix;
if (number === 0) {
return number;
}
if (unit === 'year' || unit === 'hour' || unit === 'week') {
if (number === 1) {
suffix = 'ye';
} else {
suffix = 'yèm';
}
} else {
if (number === 1) {
suffix = 'ye';
} else {
suffix = 'yèm';
}
}
return number + suffix;
}
var localize = {
ordinalNumber: ordinalNumber,
era: (0, _index.default)({
values: eraValues,
defaultWidth: 'wide'
}),
quarter: (0, _index.default)({
values: quarterValues,
defaultWidth: 'wide',
argumentCallback: function (quarter) {
return Number(quarter) - 1;
}
}),
month: (0, _index.default)({
values: monthValues,
defaultWidth: 'wide'
}),
day: (0, _index.default)({
values: dayValues,
defaultWidth: 'wide'
}),
dayPeriod: (0, _index.default)({
values: dayPeriodValues,
defaultWidth: 'wide'
})
};
var _default = localize;
exports.default = _default;
module.exports = exports.default;
+111
View File
@@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _index = _interopRequireDefault(require("../../../_lib/buildMatchPatternFn/index.js"));
var _index2 = _interopRequireDefault(require("../../../_lib/buildMatchFn/index.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var matchOrdinalNumberPattern = /^(\d+)(ye|yèm)?/i;
var parseOrdinalNumberPattern = /\d+/i;
var matchEraPatterns = {
narrow: /^(av\.J\.K|ap\.J\.K|ap\.J\.-K)/i,
abbreviated: /^(av\.J\.-K|av\.J-K|apr\.J\.-K|apr\.J-K|ap\.J-K)/i,
wide: /^(avan Jezi Kris|apre Jezi Kris)/i
};
var parseEraPatterns = {
any: [/^av/i, /^ap/i]
};
var matchQuarterPatterns = {
narrow: /^[1234]/i,
abbreviated: /^t[1234]/i,
wide: /^[1234](ye|yèm)? trimès/i
};
var parseQuarterPatterns = {
any: [/1/i, /2/i, /3/i, /4/i]
};
var matchMonthPatterns = {
narrow: /^[jfmasond]/i,
abbreviated: /^(janv|fevr|mas|avr|me|jen|jiyè|out|sept|okt|nov|des)\.?/i,
wide: /^(janvye|fevrye|mas|avril|me|jen|jiyè|out|septanm|oktòb|novanm|desanm)/i
};
var parseMonthPatterns = {
narrow: [/^j/i, /^f/i, /^m/i, /^a/i, /^m/i, /^j/i, /^j/i, /^o/i, /^s/i, /^o/i, /^n/i, /^d/i],
any: [/^ja/i, /^f/i, /^ma/i, /^av/i, /^me/i, /^je/i, /^ji/i, /^ou/i, /^s/i, /^ok/i, /^n/i, /^d/i]
};
var matchDayPatterns = {
narrow: /^[lmjvsd]/i,
short: /^(di|le|ma|me|je|va|sa)/i,
abbreviated: /^(dim|len|mad|mèk|jed|van|sam)\.?/i,
wide: /^(dimanch|lendi|madi|mèkredi|jedi|vandredi|samdi)/i
};
var parseDayPatterns = {
narrow: [/^d/i, /^l/i, /^m/i, /^m/i, /^j/i, /^v/i, /^s/i],
any: [/^di/i, /^le/i, /^ma/i, /^mè/i, /^je/i, /^va/i, /^sa/i]
};
var matchDayPeriodPatterns = {
narrow: /^(a|p|minwit|midi|mat\.?|ap\.?m\.?|swa)/i,
any: /^([ap]\.?\s?m\.?|nan maten|nan aprèmidi|nan aswè)/i
};
var parseDayPeriodPatterns = {
any: {
am: /^a/i,
pm: /^p/i,
midnight: /^min/i,
noon: /^mid/i,
morning: /mat/i,
afternoon: /ap/i,
evening: /sw/i,
night: /nwit/i
}
};
var match = {
ordinalNumber: (0, _index.default)({
matchPattern: matchOrdinalNumberPattern,
parsePattern: parseOrdinalNumberPattern,
valueCallback: function (value) {
return parseInt(value, 10);
}
}),
era: (0, _index2.default)({
matchPatterns: matchEraPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseEraPatterns,
defaultParseWidth: 'any'
}),
quarter: (0, _index2.default)({
matchPatterns: matchQuarterPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseQuarterPatterns,
defaultParseWidth: 'any',
valueCallback: function (index) {
return index + 1;
}
}),
month: (0, _index2.default)({
matchPatterns: matchMonthPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseMonthPatterns,
defaultParseWidth: 'any'
}),
day: (0, _index2.default)({
matchPatterns: matchDayPatterns,
defaultMatchWidth: 'wide',
parsePatterns: parseDayPatterns,
defaultParseWidth: 'any'
}),
dayPeriod: (0, _index2.default)({
matchPatterns: matchDayPeriodPatterns,
defaultMatchWidth: 'any',
parsePatterns: parseDayPeriodPatterns,
defaultParseWidth: 'any'
})
};
var _default = match;
exports.default = _default;
module.exports = exports.default;