WIP: Patch that will not merge. (Cherry-pick the onboard-meeting-members deep-link fix.) #177

Open
trentlarson wants to merge 4 commits from master-patch into master
  1. 2
      BUILDING.md
  2. 4
      android/app/build.gradle
  3. 8
      ios/App/App.xcodeproj/project.pbxproj
  4. 4
      package-lock.json
  5. 2
      package.json
  6. 28
      src/interfaces/deepLinks.ts
  7. 30
      src/services/deepLinks.ts
  8. 4
      src/views/DeepLinkErrorView.vue
  9. 3
      src/views/OnboardMeetingMembersView.vue

2
BUILDING.md

@ -364,7 +364,7 @@ Prerequisites: macOS with Xcode installed
4. Bump the version to match Android & package.json:
```
cd ios/App && xcrun agvtool new-version 39 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.6;/g" App.xcodeproj/project.pbxproj && cd -
cd ios/App && xcrun agvtool new-version 43 && perl -p -i -e "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 1.0.9;/g" App.xcodeproj/project.pbxproj && cd -
# Unfortunately this edits Info.plist directly.
#xcrun agvtool new-marketing-version 0.4.5
```

4
android/app/build.gradle

@ -31,8 +31,8 @@ android {
applicationId "app.timesafari.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 39
versionName "1.0.6"
versionCode 43
versionName "1.0.9"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

8
ios/App/App.xcodeproj/project.pbxproj

@ -403,7 +403,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 39;
CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = GM3FS5JQPH;
ENABLE_APP_SANDBOX = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@ -413,7 +413,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.6;
MARKETING_VERSION = 1.0.9;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -430,7 +430,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 39;
CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = GM3FS5JQPH;
ENABLE_APP_SANDBOX = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
@ -440,7 +440,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.6;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";

4
package-lock.json

@ -1,12 +1,12 @@
{
"name": "timesafari",
"version": "1.0.6",
"version": "1.0.10-beta",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "timesafari",
"version": "1.0.6",
"version": "1.0.10-beta",
"dependencies": {
"@capacitor-community/sqlite": "6.0.2",
"@capacitor-mlkit/barcode-scanning": "^6.0.0",

2
package.json

@ -1,6 +1,6 @@
{
"name": "timesafari",
"version": "1.0.6",
"version": "1.0.10-beta",
"description": "Time Safari Application",
"author": {
"name": "Time Safari Team"

28
src/interfaces/deepLinks.ts

@ -28,7 +28,7 @@
import { z } from "zod";
// Parameter validation schemas for each route type
export const deepLinkSchemas = {
export const deepLinkPathSchemas = {
claim: z.object({
id: z.string(),
}),
@ -60,7 +60,7 @@ export const deepLinkSchemas = {
jwt: z.string().optional(),
}),
"onboard-meeting-members": z.object({
id: z.string(),
groupId: z.string(),
}),
project: z.object({
id: z.string(),
@ -70,6 +70,17 @@ export const deepLinkSchemas = {
}),
};
export const deepLinkQuerySchemas = {
"onboard-meeting-members": z.object({
password: z.string(),
}),
};
// Add a union type of all valid route paths
export const VALID_DEEP_LINK_ROUTES = Object.keys(
deepLinkPathSchemas,
) as readonly (keyof typeof deepLinkPathSchemas)[];
// Create a type from the array
export type DeepLinkRoute = (typeof VALID_DEEP_LINK_ROUTES)[number];
@ -80,14 +91,13 @@ export const baseUrlSchema = z.object({
queryParams: z.record(z.string()).optional(),
});
// Add a union type of all valid route paths
export const VALID_DEEP_LINK_ROUTES = Object.keys(
deepLinkSchemas,
) as readonly (keyof typeof deepLinkSchemas)[];
// export type DeepLinkPathParams = {
// [K in keyof typeof deepLinkPathSchemas]: z.infer<(typeof deepLinkPathSchemas)[K]>;
// };
export type DeepLinkParams = {
[K in keyof typeof deepLinkSchemas]: z.infer<(typeof deepLinkSchemas)[K]>;
};
// export type DeepLinkQueryParams = {
// [K in keyof typeof deepLinkQuerySchemas]: z.infer<(typeof deepLinkQuerySchemas)[K]>;
// };
export interface DeepLinkError extends Error {
code: string;

30
src/services/deepLinks.ts

@ -47,10 +47,11 @@ import { Router } from "vue-router";
import { z } from "zod";
import {
deepLinkSchemas,
deepLinkPathSchemas,
baseUrlSchema,
routeSchema,
DeepLinkRoute,
deepLinkQuerySchemas,
} from "../interfaces/deepLinks";
import { logConsoleAndDb } from "../db/databaseUtil";
import type { DeepLinkError } from "../interfaces/deepLinks";
@ -74,7 +75,7 @@ function getFirstKeyFromZodObject(
* because "router.replace" expects the right parameter name for the route.
*/
export const ROUTE_MAP: Record<string, { name: string; paramKey?: string }> =
Object.entries(deepLinkSchemas).reduce(
Object.entries(deepLinkPathSchemas).reduce(
(acc, [routeName, schema]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const paramKey = getFirstKeyFromZodObject(schema as z.ZodObject<any>);
@ -199,16 +200,22 @@ export class DeepLinkHandler {
}
// Continue with parameter validation as before...
const schema = deepLinkSchemas[path as keyof typeof deepLinkSchemas];
const pathSchema = deepLinkPathSchemas[path as keyof typeof deepLinkPathSchemas];
const querySchema = deepLinkQuerySchemas[path as keyof typeof deepLinkQuerySchemas];
let validatedParams;
let validatedPathParams: Record<string, string> = {};
let validatedQueryParams: Record<string, string> = {};
try {
validatedParams = await schema.parseAsync(params);
if (pathSchema) {
validatedPathParams = await pathSchema.parseAsync(params);
}
if (querySchema) {
validatedQueryParams = await querySchema.parseAsync(query);
}
} catch (error) {
// For parameter validation errors, provide specific error feedback
logConsoleAndDb(
`[DeepLink] Invalid parameters for route name ${routeName} for path: ${path}: ${JSON.stringify(error)} ... with params: ${JSON.stringify(params)} ... and query: ${JSON.stringify(query)}`,
true,
`[DeepLink] Invalid parameters for route name ${routeName} for path: ${path} ... with error: ${JSON.stringify(error)} ... with params: ${JSON.stringify(params)} ... and query: ${JSON.stringify(query)}`,
);
await this.router.replace({
name: "deep-link-error",
@ -228,21 +235,22 @@ export class DeepLinkHandler {
try {
await this.router.replace({
name: routeName,
params: validatedParams,
params: validatedPathParams,
query: validatedQueryParams
});
} catch (error) {
logConsoleAndDb(
`[DeepLink] Error routing to route name ${routeName} for path: ${path}: ${JSON.stringify(error)} ... with validated params: ${JSON.stringify(validatedParams)}`,
true,
`[DeepLink] Error routing to route name ${routeName} for path: ${path}: ${JSON.stringify(error)} ... with validated params: ${JSON.stringify(validatedPathParams)} ... and query: ${JSON.stringify(validatedQueryParams)}`,
);
// For parameter validation errors, provide specific error feedback
await this.router.replace({
name: "deep-link-error",
params: validatedParams,
params: validatedPathParams,
query: {
originalPath: path,
errorCode: "ROUTING_ERROR",
errorMessage: `Error routing to ${routeName}: ${JSON.stringify(error)}`,
...validatedQueryParams,
},
});
}

4
src/views/DeepLinkErrorView.vue

@ -47,7 +47,7 @@ import { computed, onMounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import {
VALID_DEEP_LINK_ROUTES,
deepLinkSchemas,
deepLinkPathSchemas,
} from "../interfaces/deepLinks";
import { logConsoleAndDb } from "../db/databaseUtil";
import { logger } from "../utils/logger";
@ -56,7 +56,7 @@ const route = useRoute();
const router = useRouter();
// an object with the route as the key and the first param name as the value
const deepLinkSchemaKeys = Object.fromEntries(
Object.entries(deepLinkSchemas).map(([route, schema]) => {
Object.entries(deepLinkPathSchemas).map(([route, schema]) => {
const param = Object.keys(schema.shape)[0];
return [route, param];
}),

3
src/views/OnboardMeetingMembersView.vue

@ -117,6 +117,9 @@ export default class OnboardMeetingMembersView extends Vue {
this.isRegistered = settings.isRegistered || false;
try {
if (!this.activeDid) {
logConsoleAndDb(
"[OnboardMeetingMembersView] No active DID found, creating identity as fallback for meeting setup",
);
this.activeDid = await generateSaveAndActivateIdentity();
this.isRegistered = false;
}

Loading…
Cancel
Save